From b6a2d7e82249bba271599732e16ffba176ae7de8 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Fri, 31 Mar 2017 23:06:34 -0400 Subject: [PATCH 1/4] support pub(restricted) in thread_local! --- src/libstd/thread/local.rs | 69 ++++++++++++++---------- src/test/run-pass/thread-local-syntax.rs | 22 +++++--- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index dad21473eae..49ceaff8d3e 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -115,7 +115,7 @@ impl fmt::Debug for LocalKey { /// # Syntax /// /// The macro wraps any number of static declarations and makes them thread local. -/// Each static may be public or private, and attributes are allowed. Example: +/// Publicity and attributes for each static are allowed. Example: /// /// ``` /// use std::cell::RefCell; @@ -136,31 +136,40 @@ impl fmt::Debug for LocalKey { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] macro_rules! thread_local { - // rule 0: empty (base case for the recursion) + // empty (base case for the recursion) () => {}; - // rule 1: process multiple declarations where the first one is private + // process multiple declarations where the first one is private ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - thread_local!($(#[$attr])* static $name: $t = $init); // go to rule 2 + __thread_local_inner!($(#[$attr])* [] $name, $t, $init); thread_local!($($rest)*); ); - // rule 2: handle a single private declaration + // handle a single private declaration ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => ( - $(#[$attr])* static $name: $crate::thread::LocalKey<$t> = - __thread_local_inner!($t, $init); + __thread_local_inner!($(#[$attr])* [] $name, $t, $init); ); - // rule 3: handle multiple declarations where the first one is public + // handle multiple declarations where the first one is public ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - thread_local!($(#[$attr])* pub static $name: $t = $init); // go to rule 4 + __thread_local_inner!($(#[$attr])* [pub] $name, $t, $init); thread_local!($($rest)*); ); - // rule 4: handle a single public declaration + // handle a single public declaration ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr) => ( - $(#[$attr])* pub static $name: $crate::thread::LocalKey<$t> = - __thread_local_inner!($t, $init); + __thread_local_inner!($(#[$attr])* [pub] $name, $t, $init); + ); + + // handle multiple declarations where the first one is restricted public + ($(#[$attr:meta])* pub $vis:tt static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( + __thread_local_inner!($(#[$attr])* [pub $vis] $name, $t, $init); + thread_local!($($rest)*); + ); + + // handle a single restricted public declaration + ($(#[$attr:meta])* pub $vis:tt static $name:ident: $t:ty = $init:expr) => ( + __thread_local_inner!($(#[$attr])* [pub $vis] $name, $t, $init); ); } @@ -171,27 +180,29 @@ macro_rules! thread_local { #[macro_export] #[allow_internal_unstable] macro_rules! __thread_local_inner { - ($t:ty, $init:expr) => {{ - fn __init() -> $t { $init } + ($(#[$attr:meta])* [$($vis:tt)*] $name:ident, $t:ty, $init:expr) => { + $(#[$attr])* $($vis)* static $name: $crate::thread::LocalKey<$t> = { + fn __init() -> $t { $init } - fn __getit() -> $crate::option::Option< - &'static $crate::cell::UnsafeCell< - $crate::option::Option<$t>>> - { - #[thread_local] - #[cfg(target_thread_local)] - static __KEY: $crate::thread::__FastLocalKeyInner<$t> = - $crate::thread::__FastLocalKeyInner::new(); + fn __getit() -> $crate::option::Option< + &'static $crate::cell::UnsafeCell< + $crate::option::Option<$t>>> + { + #[thread_local] + #[cfg(target_thread_local)] + static __KEY: $crate::thread::__FastLocalKeyInner<$t> = + $crate::thread::__FastLocalKeyInner::new(); - #[cfg(not(target_thread_local))] - static __KEY: $crate::thread::__OsLocalKeyInner<$t> = - $crate::thread::__OsLocalKeyInner::new(); + #[cfg(not(target_thread_local))] + static __KEY: $crate::thread::__OsLocalKeyInner<$t> = + $crate::thread::__OsLocalKeyInner::new(); - __KEY.get() - } + __KEY.get() + } - $crate::thread::LocalKey::new(__getit, __init) - }} + $crate::thread::LocalKey::new(__getit, __init) + }; + } } /// Indicator of the state of a thread local storage key. diff --git a/src/test/run-pass/thread-local-syntax.rs b/src/test/run-pass/thread-local-syntax.rs index a5967249b54..373824122fd 100644 --- a/src/test/run-pass/thread-local-syntax.rs +++ b/src/test/run-pass/thread-local-syntax.rs @@ -11,13 +11,21 @@ #![deny(missing_docs)] //! this tests the syntax of `thread_local!` -thread_local! { - // no docs - #[allow(unused)] - static FOO: i32 = 42; - /// docs - pub static BAR: String = String::from("bar"); +mod foo { + mod bar { + thread_local! { + // no docs + #[allow(unused)] + static FOO: i32 = 42; + /// docs + pub static BAR: String = String::from("bar"); + + // look at these restrictions!! + pub(crate) static BAZ: usize = 0; + pub(in foo) static QUUX: usize = 0; + } + thread_local!(static SPLOK: u32 = 0); + } } -thread_local!(static BAZ: u32 = 0); fn main() {} From 8cce5bc7aba5b2f4f57df4e108e998b96fa01c8d Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 19 Apr 2017 02:29:40 +0000 Subject: [PATCH 2/4] use :vis in thread_local! --- src/libstd/lib.rs | 1 + src/libstd/thread/local.rs | 38 ++++++++------------------------------ 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2fc107c663b..dda069324b0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -277,6 +277,7 @@ #![feature(link_args)] #![feature(linkage)] #![feature(macro_reexport)] +#![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(needs_drop)] #![feature(never_type)] diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 49ceaff8d3e..c3aa3ff79c6 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -139,37 +139,15 @@ macro_rules! thread_local { // empty (base case for the recursion) () => {}; - // process multiple declarations where the first one is private - ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - __thread_local_inner!($(#[$attr])* [] $name, $t, $init); + // process multiple declarations + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( + __thread_local_inner!($(#[$attr])* $vis $name, $t, $init); thread_local!($($rest)*); ); - // handle a single private declaration - ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => ( - __thread_local_inner!($(#[$attr])* [] $name, $t, $init); - ); - - // handle multiple declarations where the first one is public - ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - __thread_local_inner!($(#[$attr])* [pub] $name, $t, $init); - thread_local!($($rest)*); - ); - - // handle a single public declaration - ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr) => ( - __thread_local_inner!($(#[$attr])* [pub] $name, $t, $init); - ); - - // handle multiple declarations where the first one is restricted public - ($(#[$attr:meta])* pub $vis:tt static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - __thread_local_inner!($(#[$attr])* [pub $vis] $name, $t, $init); - thread_local!($($rest)*); - ); - - // handle a single restricted public declaration - ($(#[$attr:meta])* pub $vis:tt static $name:ident: $t:ty = $init:expr) => ( - __thread_local_inner!($(#[$attr])* [pub $vis] $name, $t, $init); + // handle a single declaration + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( + __thread_local_inner!($(#[$attr])* $vis $name, $t, $init); ); } @@ -180,8 +158,8 @@ macro_rules! thread_local { #[macro_export] #[allow_internal_unstable] macro_rules! __thread_local_inner { - ($(#[$attr:meta])* [$($vis:tt)*] $name:ident, $t:ty, $init:expr) => { - $(#[$attr])* $($vis)* static $name: $crate::thread::LocalKey<$t> = { + ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => { + $(#[$attr])* $vis static $name: $crate::thread::LocalKey<$t> = { fn __init() -> $t { $init } fn __getit() -> $crate::option::Option< From 8e7c4888b717a24dfc68f47c5dde00334fed2317 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Fri, 21 Apr 2017 04:30:08 +0000 Subject: [PATCH 3/4] stage0 fallback --- src/libstd/thread/local.rs | 67 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index c3aa3ff79c6..8b2064c9d61 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -110,6 +110,7 @@ impl fmt::Debug for LocalKey { } } +#[cfg(not(stage0))] /// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax @@ -151,6 +152,7 @@ macro_rules! thread_local { ); } +#[cfg(not(stage0))] #[doc(hidden)] #[unstable(feature = "thread_local_internals", reason = "should not be necessary", @@ -183,6 +185,71 @@ macro_rules! __thread_local_inner { } } +#[cfg(stage0)] +/// Declare a new thread local storage key of type `std::thread::LocalKey`. +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] +macro_rules! thread_local { + // rule 0: empty (base case for the recursion) + () => {}; + + // rule 1: process multiple declarations where the first one is private + ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( + thread_local!($(#[$attr])* static $name: $t = $init); // go to rule 2 + thread_local!($($rest)*); + ); + + // rule 2: handle a single private declaration + ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => ( + $(#[$attr])* static $name: $crate::thread::LocalKey<$t> = + __thread_local_inner!($t, $init); + ); + + // rule 3: handle multiple declarations where the first one is public + ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( + thread_local!($(#[$attr])* pub static $name: $t = $init); // go to rule 4 + thread_local!($($rest)*); + ); + + // rule 4: handle a single public declaration + ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr) => ( + $(#[$attr])* pub static $name: $crate::thread::LocalKey<$t> = + __thread_local_inner!($t, $init); + ); +} + +#[cfg(stage0)] +#[doc(hidden)] +#[unstable(feature = "thread_local_internals", + reason = "should not be necessary", + issue = "0")] +#[macro_export] +#[allow_internal_unstable] +macro_rules! __thread_local_inner { + ($t:ty, $init:expr) => {{ + fn __init() -> $t { $init } + + fn __getit() -> $crate::option::Option< + &'static $crate::cell::UnsafeCell< + $crate::option::Option<$t>>> + { + #[thread_local] + #[cfg(target_thread_local)] + static __KEY: $crate::thread::__FastLocalKeyInner<$t> = + $crate::thread::__FastLocalKeyInner::new(); + + #[cfg(not(target_thread_local))] + static __KEY: $crate::thread::__OsLocalKeyInner<$t> = + $crate::thread::__OsLocalKeyInner::new(); + + __KEY.get() + } + + $crate::thread::LocalKey::new(__getit, __init) + }} +} + /// Indicator of the state of a thread local storage key. #[unstable(feature = "thread_local_state", reason = "state querying was recently added", From f9f4707469c2bc44ba3d643c805c8f3f62db7bd5 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Fri, 21 Apr 2017 23:54:38 +0000 Subject: [PATCH 4/4] let #[allow_internal_unstable] cover :vis --- src/libsyntax/ext/tt/macro_rules.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a98a9dd2040..f786b1abb8a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -222,7 +222,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); - valid &= check_lhs_nt_follows(sess, features, &tt); + valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt); return tt; } } @@ -272,11 +272,12 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) fn check_lhs_nt_follows(sess: &ParseSess, features: &RefCell, + attrs: &[ast::Attribute], lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. if let quoted::TokenTree::Delimited(_, ref tts) = *lhs { - check_matcher(sess, features, &tts.tts) + check_matcher(sess, features, attrs, &tts.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; sess.span_diagnostic.span_err(lhs.span(), msg); @@ -328,11 +329,12 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { fn check_matcher(sess: &ParseSess, features: &RefCell, + attrs: &[ast::Attribute], matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); let err = sess.span_diagnostic.err_count(); - check_matcher_core(sess, features, &first_sets, matcher, &empty_suffix); + check_matcher_core(sess, features, attrs, &first_sets, matcher, &empty_suffix); err == sess.span_diagnostic.err_count() } @@ -575,6 +577,7 @@ impl TokenSet { // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, features: &RefCell, + attrs: &[ast::Attribute], first_sets: &FirstSets, matcher: &[quoted::TokenTree], follow: &TokenSet) -> TokenSet { @@ -605,7 +608,7 @@ fn check_matcher_core(sess: &ParseSess, match *token { TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => { let can_be_followed_by_any; - if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) { + if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) { let msg = format!("invalid fragment specifier `{}`", bad_frag); sess.span_diagnostic.struct_span_err(token.span(), &msg) .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \ @@ -631,7 +634,7 @@ fn check_matcher_core(sess: &ParseSess, } TokenTree::Delimited(span, ref d) => { let my_suffix = TokenSet::singleton(d.close_tt(span)); - check_matcher_core(sess, features, first_sets, &d.tts, &my_suffix); + check_matcher_core(sess, features, attrs, first_sets, &d.tts, &my_suffix); // don't track non NT tokens last.replace_with_irrelevant(); @@ -663,7 +666,12 @@ fn check_matcher_core(sess: &ParseSess, // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, features, first_sets, &seq_rep.tts, my_suffix); + let next = check_matcher_core(sess, + features, + attrs, + first_sets, + &seq_rep.tts, + my_suffix); if next.maybe_empty { last.add_all(&next); } else { @@ -836,12 +844,13 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result, + attrs: &[ast::Attribute], tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { let frag_name = frag_spec.name.as_str(); let frag_span = tok.span(); - if !is_legal_fragment_specifier(sess, features, &frag_name, frag_span) { + if !is_legal_fragment_specifier(sess, features, attrs, &frag_name, frag_span) { return Err(frag_name.to_string()); } } @@ -850,13 +859,15 @@ fn has_legal_fragment_specifier(sess: &ParseSess, fn is_legal_fragment_specifier(sess: &ParseSess, features: &RefCell, + attrs: &[ast::Attribute], frag_name: &str, frag_span: Span) -> bool { match frag_name { "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, "vis" => { - if !features.borrow().macro_vis_matcher { + if !features.borrow().macro_vis_matcher + && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_VIS_MATCHER; emit_feature_err(sess, "macro_vis_matcher",