Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support pub(restricted) in thread_local! #40984

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@
#![feature(link_args)]
#![feature(linkage)]
#![feature(macro_reexport)]
#![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)]
#![feature(never_type)]
#![feature(num_bits_bytes)]
Expand Down
58 changes: 57 additions & 1 deletion src/libstd/thread/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,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;
Expand All @@ -129,6 +130,60 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
#[macro_export]
#[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)
() => {};
Expand Down Expand Up @@ -158,6 +213,7 @@ macro_rules! thread_local {
);
}

#[cfg(stage0)]
#[doc(hidden)]
#[unstable(feature = "thread_local_internals",
reason = "should not be necessary",
Expand Down
27 changes: 19 additions & 8 deletions src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,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;
}
}
Expand Down Expand Up @@ -255,11 +255,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.
match lhs {
&quoted::TokenTree::Delimited(_, ref tts) => check_matcher(sess, features, &tts.tts),
&quoted::TokenTree::Delimited(_, ref tts) => check_matcher(sess, features, attrs, &tts.tts),
_ => {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
sess.span_diagnostic.span_err(lhs.span(), msg);
Expand Down Expand Up @@ -313,11 +314,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()
}

Expand Down Expand Up @@ -560,6 +562,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 {
Expand Down Expand Up @@ -590,7 +593,7 @@ fn check_matcher_core(sess: &ParseSess,
match *token {
TokenTree::Token(..) | 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`, \
Expand All @@ -616,7 +619,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();

Expand Down Expand Up @@ -648,7 +651,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 {
Expand Down Expand Up @@ -821,12 +829,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());
}
}
Expand All @@ -835,13 +844,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",
Expand Down
22 changes: 15 additions & 7 deletions src/test/run-pass/thread-local-syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}