about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-07-15 06:14:11 +0000
committerbors <bors@rust-lang.org>2017-07-15 06:14:11 +0000
commit8658908cf822e9425d0841435c111584750aa236 (patch)
treee892d86136cc2af79670e010416bc7a746ff0ed4
parentb4502f7c0b51526d0177204a71dc2b3200f7348b (diff)
parentf9f4707469c2bc44ba3d643c805c8f3f62db7bd5 (diff)
downloadrust-8658908cf822e9425d0841435c111584750aa236.tar.gz
rust-8658908cf822e9425d0841435c111584750aa236.zip
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.
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/thread/local.rs58
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs27
-rw-r--r--src/test/run-pass/thread-local-syntax.rs22
4 files changed, 92 insertions, 16 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 28e8f72ac64..be433e2b81e 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -110,12 +110,13 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
     }
 }
 
+#[cfg(not(stage0))]
 /// Declare a new thread local storage key of type [`std::thread::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,6 +137,60 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable]
 macro_rules! thread_local {
+    // empty (base case for the recursion)
+    () => {};
+
+    // 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 declaration
+    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
+        __thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+    );
+}
+
+#[cfg(not(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 {
+    ($(#[$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<
+                &'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)
+        };
+    }
+}
+
+#[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)
     () => {};
 
@@ -164,6 +219,7 @@ macro_rules! thread_local {
     );
 }
 
+#[cfg(stage0)]
 #[doc(hidden)]
 #[unstable(feature = "thread_local_internals",
            reason = "should not be necessary",
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<Features>, 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<Features>, def: &ast::Item)
 
 fn check_lhs_nt_follows(sess: &ParseSess,
                         features: &RefCell<Features>,
+                        attrs: &[ast::Attribute],
                         lhs: &quoted::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: &quoted::TokenTree) -> bool {
 
 fn check_matcher(sess: &ParseSess,
                  features: &RefCell<Features>,
+                 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<Features>,
+                      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: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
 
 fn has_legal_fragment_specifier(sess: &ParseSess,
                                 features: &RefCell<Features>,
+                                attrs: &[ast::Attribute],
                                 tok: &quoted::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<Features>,
+                               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",
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() {}