Skip to content

Commit 8658908

Browse files
committed
Auto merge of #43185 - durka:thread-local-pub-restricted, r=alexcrichton
support pub(restricted) in thread_local! (round 2) Resurrected #40984 now that the issue blocking it was fixed. Original description: `pub(restricted)` was stabilized in #40556 so let's go! Here is a [playground](https://play.rust-lang.org/?gist=f55f32f164a6ed18c219fec8f8293b98&version=nightly&backtrace=1). I changed the interface of `__thread_local_inner!`, which is supposedly unstable but this is not checked for macros (#34097 cc @petrochenkov @jseyfried), so this may be an issue.
2 parents b4502f7 + f9f4707 commit 8658908

File tree

4 files changed

+92
-16
lines changed

4 files changed

+92
-16
lines changed

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@
277277
#![feature(link_args)]
278278
#![feature(linkage)]
279279
#![feature(macro_reexport)]
280+
#![feature(macro_vis_matcher)]
280281
#![feature(needs_panic_runtime)]
281282
#![feature(needs_drop)]
282283
#![feature(never_type)]

src/libstd/thread/local.rs

+57-1
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,13 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
110110
}
111111
}
112112

113+
#[cfg(not(stage0))]
113114
/// Declare a new thread local storage key of type [`std::thread::LocalKey`].
114115
///
115116
/// # Syntax
116117
///
117118
/// The macro wraps any number of static declarations and makes them thread local.
118-
/// Each static may be public or private, and attributes are allowed. Example:
119+
/// Publicity and attributes for each static are allowed. Example:
119120
///
120121
/// ```
121122
/// use std::cell::RefCell;
@@ -135,6 +136,60 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
135136
#[macro_export]
136137
#[stable(feature = "rust1", since = "1.0.0")]
137138
#[allow_internal_unstable]
139+
macro_rules! thread_local {
140+
// empty (base case for the recursion)
141+
() => {};
142+
143+
// process multiple declarations
144+
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
145+
__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
146+
thread_local!($($rest)*);
147+
);
148+
149+
// handle a single declaration
150+
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
151+
__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
152+
);
153+
}
154+
155+
#[cfg(not(stage0))]
156+
#[doc(hidden)]
157+
#[unstable(feature = "thread_local_internals",
158+
reason = "should not be necessary",
159+
issue = "0")]
160+
#[macro_export]
161+
#[allow_internal_unstable]
162+
macro_rules! __thread_local_inner {
163+
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
164+
$(#[$attr])* $vis static $name: $crate::thread::LocalKey<$t> = {
165+
fn __init() -> $t { $init }
166+
167+
fn __getit() -> $crate::option::Option<
168+
&'static $crate::cell::UnsafeCell<
169+
$crate::option::Option<$t>>>
170+
{
171+
#[thread_local]
172+
#[cfg(target_thread_local)]
173+
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
174+
$crate::thread::__FastLocalKeyInner::new();
175+
176+
#[cfg(not(target_thread_local))]
177+
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
178+
$crate::thread::__OsLocalKeyInner::new();
179+
180+
__KEY.get()
181+
}
182+
183+
$crate::thread::LocalKey::new(__getit, __init)
184+
};
185+
}
186+
}
187+
188+
#[cfg(stage0)]
189+
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
190+
#[macro_export]
191+
#[stable(feature = "rust1", since = "1.0.0")]
192+
#[allow_internal_unstable]
138193
macro_rules! thread_local {
139194
// rule 0: empty (base case for the recursion)
140195
() => {};
@@ -164,6 +219,7 @@ macro_rules! thread_local {
164219
);
165220
}
166221

222+
#[cfg(stage0)]
167223
#[doc(hidden)]
168224
#[unstable(feature = "thread_local_internals",
169225
reason = "should not be necessary",

src/libsyntax/ext/tt/macro_rules.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
222222
if let MatchedNonterminal(ref nt) = *m {
223223
if let NtTT(ref tt) = **nt {
224224
let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap();
225-
valid &= check_lhs_nt_follows(sess, features, &tt);
225+
valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt);
226226
return tt;
227227
}
228228
}
@@ -272,11 +272,12 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
272272

273273
fn check_lhs_nt_follows(sess: &ParseSess,
274274
features: &RefCell<Features>,
275+
attrs: &[ast::Attribute],
275276
lhs: &quoted::TokenTree) -> bool {
276277
// lhs is going to be like TokenTree::Delimited(...), where the
277278
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
278279
if let quoted::TokenTree::Delimited(_, ref tts) = *lhs {
279-
check_matcher(sess, features, &tts.tts)
280+
check_matcher(sess, features, attrs, &tts.tts)
280281
} else {
281282
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
282283
sess.span_diagnostic.span_err(lhs.span(), msg);
@@ -328,11 +329,12 @@ fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
328329

329330
fn check_matcher(sess: &ParseSess,
330331
features: &RefCell<Features>,
332+
attrs: &[ast::Attribute],
331333
matcher: &[quoted::TokenTree]) -> bool {
332334
let first_sets = FirstSets::new(matcher);
333335
let empty_suffix = TokenSet::empty();
334336
let err = sess.span_diagnostic.err_count();
335-
check_matcher_core(sess, features, &first_sets, matcher, &empty_suffix);
337+
check_matcher_core(sess, features, attrs, &first_sets, matcher, &empty_suffix);
336338
err == sess.span_diagnostic.err_count()
337339
}
338340

@@ -575,6 +577,7 @@ impl TokenSet {
575577
// see `FirstSets::new`.
576578
fn check_matcher_core(sess: &ParseSess,
577579
features: &RefCell<Features>,
580+
attrs: &[ast::Attribute],
578581
first_sets: &FirstSets,
579582
matcher: &[quoted::TokenTree],
580583
follow: &TokenSet) -> TokenSet {
@@ -605,7 +608,7 @@ fn check_matcher_core(sess: &ParseSess,
605608
match *token {
606609
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
607610
let can_be_followed_by_any;
608-
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) {
611+
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) {
609612
let msg = format!("invalid fragment specifier `{}`", bad_frag);
610613
sess.span_diagnostic.struct_span_err(token.span(), &msg)
611614
.help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
@@ -631,7 +634,7 @@ fn check_matcher_core(sess: &ParseSess,
631634
}
632635
TokenTree::Delimited(span, ref d) => {
633636
let my_suffix = TokenSet::singleton(d.close_tt(span));
634-
check_matcher_core(sess, features, first_sets, &d.tts, &my_suffix);
637+
check_matcher_core(sess, features, attrs, first_sets, &d.tts, &my_suffix);
635638
// don't track non NT tokens
636639
last.replace_with_irrelevant();
637640

@@ -663,7 +666,12 @@ fn check_matcher_core(sess: &ParseSess,
663666
// At this point, `suffix_first` is built, and
664667
// `my_suffix` is some TokenSet that we can use
665668
// for checking the interior of `seq_rep`.
666-
let next = check_matcher_core(sess, features, first_sets, &seq_rep.tts, my_suffix);
669+
let next = check_matcher_core(sess,
670+
features,
671+
attrs,
672+
first_sets,
673+
&seq_rep.tts,
674+
my_suffix);
667675
if next.maybe_empty {
668676
last.add_all(&next);
669677
} else {
@@ -836,12 +844,13 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
836844

837845
fn has_legal_fragment_specifier(sess: &ParseSess,
838846
features: &RefCell<Features>,
847+
attrs: &[ast::Attribute],
839848
tok: &quoted::TokenTree) -> Result<(), String> {
840849
debug!("has_legal_fragment_specifier({:?})", tok);
841850
if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
842851
let frag_name = frag_spec.name.as_str();
843852
let frag_span = tok.span();
844-
if !is_legal_fragment_specifier(sess, features, &frag_name, frag_span) {
853+
if !is_legal_fragment_specifier(sess, features, attrs, &frag_name, frag_span) {
845854
return Err(frag_name.to_string());
846855
}
847856
}
@@ -850,13 +859,15 @@ fn has_legal_fragment_specifier(sess: &ParseSess,
850859

851860
fn is_legal_fragment_specifier(sess: &ParseSess,
852861
features: &RefCell<Features>,
862+
attrs: &[ast::Attribute],
853863
frag_name: &str,
854864
frag_span: Span) -> bool {
855865
match frag_name {
856866
"item" | "block" | "stmt" | "expr" | "pat" |
857867
"path" | "ty" | "ident" | "meta" | "tt" | "" => true,
858868
"vis" => {
859-
if !features.borrow().macro_vis_matcher {
869+
if !features.borrow().macro_vis_matcher
870+
&& !attr::contains_name(attrs, "allow_internal_unstable") {
860871
let explain = feature_gate::EXPLAIN_VIS_MATCHER;
861872
emit_feature_err(sess,
862873
"macro_vis_matcher",

src/test/run-pass/thread-local-syntax.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@
1111
#![deny(missing_docs)]
1212
//! this tests the syntax of `thread_local!`
1313
14-
thread_local! {
15-
// no docs
16-
#[allow(unused)]
17-
static FOO: i32 = 42;
18-
/// docs
19-
pub static BAR: String = String::from("bar");
14+
mod foo {
15+
mod bar {
16+
thread_local! {
17+
// no docs
18+
#[allow(unused)]
19+
static FOO: i32 = 42;
20+
/// docs
21+
pub static BAR: String = String::from("bar");
22+
23+
// look at these restrictions!!
24+
pub(crate) static BAZ: usize = 0;
25+
pub(in foo) static QUUX: usize = 0;
26+
}
27+
thread_local!(static SPLOK: u32 = 0);
28+
}
2029
}
21-
thread_local!(static BAZ: u32 = 0);
2230

2331
fn main() {}

0 commit comments

Comments
 (0)