Skip to content

Check #[thread_local] statics correctly in the compiler. #43746

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

Merged
merged 2 commits into from
Aug 12, 2017
Merged
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/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
@@ -404,6 +404,7 @@ impl<'a> LoweringContext<'a> {
format: codemap::CompilerDesugaring(Symbol::intern(reason)),
span: Some(span),
allow_internal_unstable: true,
allow_internal_unsafe: false,
},
});
span.ctxt = SyntaxContext::empty().apply_mark(mark);
8 changes: 7 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
@@ -643,7 +643,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}

Def::Static(_, mutbl) => {
Def::Static(def_id, mutbl) => {
// `#[thread_local]` statics may not outlive the current function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like 2-space indent here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire file has broken (read: old-skool match rules) indentation, I'm actually on a multiple of 4 and the Def::Static line above is wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just mentioned this b/c the line just after these modifications is 4-space indented, but yes it looks like the indentation is off in most of this file.

for attr in &self.tcx.get_attrs(def_id)[..] {
if attr.check_name("thread_local") {
return Ok(self.cat_rvalue_node(id, span, expr_ty));
}
}
Ok(Rc::new(cmt_ {
id:id,
span:span,
1 change: 1 addition & 0 deletions src/librustc_allocator/expand.rs
Original file line number Diff line number Diff line change
@@ -79,6 +79,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
format: MacroAttribute(Symbol::intern(name)),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
}
});
let span = Span {
25 changes: 17 additions & 8 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -195,24 +195,35 @@ impl LintPass for UnsafeCode {
}
}

impl UnsafeCode {
fn report_unsafe(&self, cx: &LateContext, span: Span, desc: &'static str) {
// This comes from a macro that has #[allow_internal_unsafe].
if span.allows_unsafe() {
return;
}

cx.span_lint(UNSAFE_CODE, span, desc);
}
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) {
cx.span_lint(UNSAFE_CODE, blk.span, "usage of an `unsafe` block");
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
}
}
}

fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
}

hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait")
}

_ => return,
@@ -228,12 +239,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
_: ast::NodeId) {
match fk {
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
self.report_unsafe(cx, span, "declaration of an `unsafe` function")
}

FnKind::Method(_, sig, ..) => {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
self.report_unsafe(cx, span, "implementation of an `unsafe` method")
}
}

@@ -244,9 +255,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE,
item.span,
"declaration of an `unsafe` method")
self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
}
}
}
1 change: 1 addition & 0 deletions src/librustc_mir/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -442,4 +442,5 @@ static A : &'static u32 = &S.a; // ok!

register_diagnostics! {
E0526, // shuffle indices are not constant
E0625, // thread-local statics cannot be accessed at compile-time
}
20 changes: 19 additions & 1 deletion src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
@@ -484,8 +484,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}
}
},
Lvalue::Static(_) => {
Lvalue::Static(ref global) => {
self.add(Qualif::STATIC);

if self.mode != Mode::Fn {
for attr in &self.tcx.get_attrs(global.def_id)[..] {
if attr.check_name("thread_local") {
span_err!(self.tcx.sess, self.span, E0625,
"thread-local statics cannot be \
accessed at compile-time");
return;
}
}
}

if self.mode == Mode::Const || self.mode == Mode::ConstFn {
span_err!(self.tcx.sess, self.span, E0013,
"{}s cannot refer to statics, use \
@@ -998,6 +1010,12 @@ impl MirPass for QualifyAndPromoteConstants {

// Statics must be Sync.
if mode == Mode::Static {
// `#[thread_local]` statics don't have to be `Sync`.
for attr in &tcx.get_attrs(def_id)[..] {
if attr.check_name("thread_local") {
return;
}
}
let ty = mir.return_ty;
tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
22 changes: 18 additions & 4 deletions src/librustc_plugin/registry.rs
Original file line number Diff line number Diff line change
@@ -102,9 +102,19 @@ impl<'a> Registry<'a> {
panic!("user-defined macros may not be named `macro_rules`");
}
self.syntax_exts.push((name, match extension {
NormalTT(ext, _, allow_internal_unstable) => {
NormalTT {
expander,
def_info: _,
allow_internal_unstable,
allow_internal_unsafe
} => {
let nid = ast::CRATE_NODE_ID;
NormalTT(ext, Some((nid, self.krate_span)), allow_internal_unstable)
NormalTT {
expander,
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe
}
}
IdentTT(ext, _, allow_internal_unstable) => {
IdentTT(ext, Some(self.krate_span), allow_internal_unstable)
@@ -134,8 +144,12 @@ impl<'a> Registry<'a> {
/// It builds for you a `NormalTT` that calls `expander`,
/// and also takes care of interning the macro's name.
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
self.register_syntax_extension(Symbol::intern(name),
NormalTT(Box::new(expander), None, false));
self.register_syntax_extension(Symbol::intern(name), NormalTT {
expander: Box::new(expander),
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
});
}

/// Register a compiler lint pass.
2 changes: 1 addition & 1 deletion src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
@@ -313,7 +313,7 @@ impl<'a> base::Resolver for Resolver<'a> {
fn check_unused_macros(&self) {
for did in self.unused_macros.iter() {
let id_span = match *self.macro_map[did] {
SyntaxExtension::NormalTT(_, isp, _) => isp,
SyntaxExtension::NormalTT { def_info, .. } => def_info,
SyntaxExtension::DeclMacro(.., osp) => osp,
_ => None,
};
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
@@ -243,6 +243,7 @@
#![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(asm)]
#![feature(box_syntax)]
62 changes: 31 additions & 31 deletions src/libstd/thread/local.rs
Original file line number Diff line number Diff line change
@@ -91,13 +91,13 @@ pub struct LocalKey<T: 'static> {
//
// Note that the thunk is itself unsafe because the returned lifetime of the
// slot where data lives, `'static`, is not actually valid. The lifetime
// here is actually `'thread`!
// here is actually slightly shorter than the currently running thread!
//
// Although this is an extra layer of indirection, it should in theory be
// trivially devirtualizable by LLVM because the value of `inner` never
// changes and the constant should be readonly within a crate. This mainly
// only runs into problems when TLS statics are exported across crates.
inner: fn() -> Option<&'static UnsafeCell<Option<T>>>,
inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,

// initialization routine to invoke to create a value
init: fn() -> T,
@@ -157,12 +157,13 @@ macro_rules! thread_local {
issue = "0")]
#[macro_export]
#[allow_internal_unstable]
#[cfg_attr(not(stage0), allow_internal_unsafe)]
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<
unsafe fn __getit() -> $crate::option::Option<
&'static $crate::cell::UnsafeCell<
$crate::option::Option<$t>>>
{
@@ -178,7 +179,9 @@ macro_rules! __thread_local_inner {
__KEY.get()
}

$crate::thread::LocalKey::new(__getit, __init)
unsafe {
$crate::thread::LocalKey::new(__getit, __init)
}
};
}
}
@@ -252,8 +255,8 @@ impl<T: 'static> LocalKey<T> {
#[unstable(feature = "thread_local_internals",
reason = "recently added to create a key",
issue = "0")]
pub const fn new(inner: fn() -> Option<&'static UnsafeCell<Option<T>>>,
init: fn() -> T) -> LocalKey<T> {
pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell<Option<T>>>,
init: fn() -> T) -> LocalKey<T> {
LocalKey {
inner: inner,
init: init,
@@ -391,6 +394,7 @@ pub mod fast {
}
}

#[cfg(stage0)]
unsafe impl<T> ::marker::Sync for Key<T> { }

impl<T> Key<T> {
@@ -402,14 +406,12 @@ pub mod fast {
}
}

pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
unsafe {
if mem::needs_drop::<T>() && self.dtor_running.get() {
return None
}
self.register_dtor();
pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
if mem::needs_drop::<T>() && self.dtor_running.get() {
return None
}
Some(&self.inner)
self.register_dtor();
Some(&*(&self.inner as *const _))
}

unsafe fn register_dtor(&self) {
@@ -478,26 +480,24 @@ pub mod os {
}
}

pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
unsafe {
let ptr = self.os.get() as *mut Value<T>;
if !ptr.is_null() {
if ptr as usize == 1 {
return None
}
return Some(&(*ptr).value);
pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
let ptr = self.os.get() as *mut Value<T>;
if !ptr.is_null() {
if ptr as usize == 1 {
return None
}

// If the lookup returned null, we haven't initialized our own
// local copy, so do that now.
let ptr: Box<Value<T>> = box Value {
key: self,
value: UnsafeCell::new(None),
};
let ptr = Box::into_raw(ptr);
self.os.set(ptr as *mut u8);
Some(&(*ptr).value)
return Some(&(*ptr).value);
}

// If the lookup returned null, we haven't initialized our own
// local copy, so do that now.
let ptr: Box<Value<T>> = box Value {
key: self,
value: UnsafeCell::new(None),
};
let ptr = Box::into_raw(ptr);
self.os.set(ptr as *mut u8);
Some(&(*ptr).value)
}
}

16 changes: 11 additions & 5 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
@@ -532,10 +532,16 @@ pub enum SyntaxExtension {
/// A normal, function-like syntax extension.
///
/// `bytes!` is a `NormalTT`.
///
/// The `bool` dictates whether the contents of the macro can
/// directly use `#[unstable]` things (true == yes).
NormalTT(Box<TTMacroExpander>, Option<(ast::NodeId, Span)>, bool),
NormalTT {
expander: Box<TTMacroExpander>,
def_info: Option<(ast::NodeId, Span)>,
/// Whether the contents of the macro can
/// directly use `#[unstable]` things (true == yes).
allow_internal_unstable: bool,
/// Whether the contents of the macro can use `unsafe`
/// without triggering the `unsafe_code` lint.
allow_internal_unsafe: bool,
},

/// A function-like syntax extension that has an extra ident before
/// the block.
@@ -562,7 +568,7 @@ impl SyntaxExtension {
pub fn kind(&self) -> MacroKind {
match *self {
SyntaxExtension::DeclMacro(..) |
SyntaxExtension::NormalTT(..) |
SyntaxExtension::NormalTT { .. } |
SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro(..) =>
MacroKind::Bang,
1 change: 1 addition & 0 deletions src/libsyntax/ext/derive.rs
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
},
});

27 changes: 20 additions & 7 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
@@ -411,6 +411,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
}
});

@@ -458,7 +459,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let path = &mac.node.path;

let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
let validate_and_set_expn_info = |def_site_span, allow_internal_unstable| {
let validate_and_set_expn_info = |def_site_span,
allow_internal_unstable,
allow_internal_unsafe| {
if ident.name != keywords::Invalid.name() {
return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident));
}
@@ -467,7 +470,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
span: def_site_span,
allow_internal_unstable: allow_internal_unstable,
allow_internal_unstable,
allow_internal_unsafe,
},
});
Ok(())
@@ -476,20 +480,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let opt_expanded = match *ext {
DeclMacro(ref expand, def_span) => {
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
false) {
false, false) {
self.cx.span_err(path.span, &msg);
return kind.dummy(span);
}
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
}

NormalTT(ref expandfun, def_info, allow_internal_unstable) => {
NormalTT {
ref expander,
def_info,
allow_internal_unstable,
allow_internal_unsafe
} => {
if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s),
allow_internal_unstable) {
allow_internal_unstable,
allow_internal_unsafe) {
self.cx.span_err(path.span, &msg);
return kind.dummy(span);
}
kind.make_from(expandfun.expand(self.cx, span, mac.node.stream()))
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
}

IdentTT(ref expander, tt_span, allow_internal_unstable) => {
@@ -504,7 +514,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
span: tt_span,
allow_internal_unstable: allow_internal_unstable,
allow_internal_unstable,
allow_internal_unsafe: false,
}
});

@@ -540,6 +551,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
span: None,
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable: false,
allow_internal_unsafe: false,
},
});

@@ -578,6 +590,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: MacroAttribute(pretty_name),
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
}
};

12 changes: 9 additions & 3 deletions src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
@@ -269,7 +269,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()])
}

let exp: Box<_> = Box::new(MacroRulesMacroExpander {
let expander: Box<_> = Box::new(MacroRulesMacroExpander {
name: def.ident,
lhses: lhses,
rhses: rhses,
@@ -278,9 +278,15 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)

if body.legacy {
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
NormalTT(exp, Some((def.id, def.span)), allow_internal_unstable)
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
NormalTT {
expander,
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe
}
} else {
SyntaxExtension::DeclMacro(exp, Some((def.id, def.span)))
SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
}
}

15 changes: 15 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -194,6 +194,14 @@ declare_features! (
// rustc internal
(active, allow_internal_unstable, "1.0.0", None),

// Allows the use of #[allow_internal_unsafe]. This is an
// attribute on macro_rules! and can't use the attribute handling
// below (it has to be checked before expansion possibly makes
// macros disappear).
//
// rustc internal
(active, allow_internal_unsafe, "1.0.0", None),

// #23121. Array patterns have some hazards yet.
(active, slice_patterns, "1.0.0", Some(23121)),

@@ -735,6 +743,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
cfg_fn!(allow_internal_unstable))),

("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
"allow_internal_unsafe",
EXPLAIN_ALLOW_INTERNAL_UNSAFE,
cfg_fn!(allow_internal_unsafe))),

("fundamental", Whitelisted, Gated(Stability::Unstable,
"fundamental",
"the `#[fundamental]` attribute \
@@ -1045,6 +1058,8 @@ pub const EXPLAIN_TRACE_MACROS: &'static str =
"`trace_macros` is not stable enough for use and is subject to change";
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
"allow_internal_unstable side-steps feature gating and stability checks";
pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str =
"allow_internal_unsafe side-steps the unsafe_code lint";

pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
"`#[derive]` for custom traits is deprecated and will be removed in the future.";
1 change: 1 addition & 0 deletions src/libsyntax/std_inject.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ fn ignored_span(sp: Span) -> Span {
format: MacroAttribute(Symbol::intern("std_inject")),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
}
});
Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp }
1 change: 1 addition & 0 deletions src/libsyntax/test.rs
Original file line number Diff line number Diff line change
@@ -291,6 +291,7 @@ fn generate_test_harness(sess: &ParseSess,
format: MacroAttribute(Symbol::intern("test")),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
}
});

14 changes: 12 additions & 2 deletions src/libsyntax_ext/lib.rs
Original file line number Diff line number Diff line change
@@ -64,7 +64,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
register(Symbol::intern(stringify!($name)),
NormalTT(Box::new($f as MacroExpanderFn), None, false));
NormalTT {
expander: Box::new($f as MacroExpanderFn),
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
});
)* }
}

@@ -112,7 +117,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,

// format_args uses `unstable` things internally.
register(Symbol::intern("format_args"),
NormalTT(Box::new(format::expand_format_args), None, true));
NormalTT {
expander: Box::new(format::expand_format_args),
def_info: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
});

for (name, ext) in user_exts {
register(name, ext);
1 change: 1 addition & 0 deletions src/libsyntax_ext/proc_macro_registrar.rs
Original file line number Diff line number Diff line change
@@ -368,6 +368,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
format: MacroAttribute(Symbol::intern("proc_macro")),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
}
});
let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP };
3 changes: 3 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
@@ -310,6 +310,9 @@ pub struct NameAndSpan {
/// features internally without forcing the whole crate to opt-in
/// to them.
pub allow_internal_unstable: bool,
/// Whether the macro is allowed to use `unsafe` internally
/// even if the user crate has `#![forbid(unsafe_code)]`.
pub allow_internal_unsafe: bool,
/// The span of the macro definition itself. The macro may not
/// have a sensible definition span (e.g. something defined
/// completely inside libsyntax) in which case this is None.
10 changes: 10 additions & 0 deletions src/libsyntax_pos/lib.rs
Original file line number Diff line number Diff line change
@@ -153,6 +153,16 @@ impl Span {
}
}

/// Check if a span is "internal" to a macro in which `unsafe`
/// can be used without triggering the `unsafe_code` lint
// (that is, a macro marked with `#[allow_internal_unsafe]`).
pub fn allows_unsafe(&self) -> bool {
match self.ctxt.outer().expn_info() {
Some(info) => info.callee.allow_internal_unsafe,
None => false,
}
}

pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
let mut prev_span = DUMMY_SP;
let mut result = vec![];
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// gate-test-allow_internal_unsafe

#![allow(unused_macros)]

macro_rules! bar {
() => {
// more layers don't help:
#[allow_internal_unsafe] //~ ERROR allow_internal_unsafe side-steps
macro_rules! baz {
() => {}
}
}
}

bar!();

fn main() {}
25 changes: 25 additions & 0 deletions src/test/compile-fail/issue-17954.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(thread_local)]

#[thread_local]
static FOO: u8 = 3;

fn main() {
let a = &FOO;
//~^ ERROR borrowed value does not live long enough
//~| does not live long enough
//~| NOTE borrowed value must be valid for the static lifetime

std::thread::spawn(move || {
println!("{}", a);
});
} //~ temporary value only lives until here
39 changes: 39 additions & 0 deletions src/test/compile-fail/issue-43733-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(const_fn, drop_types_in_const)]
#![feature(cfg_target_thread_local, thread_local_internals)]

// On platforms *without* `#[thread_local]`, use
// a custom non-`Sync` type to fake the same error.
#[cfg(not(target_thread_local))]
struct Key<T> {
_data: std::cell::UnsafeCell<Option<T>>,
_flag: std::cell::Cell<bool>,
}

#[cfg(not(target_thread_local))]
impl<T> Key<T> {
const fn new() -> Self {
Key {
_data: std::cell::UnsafeCell::new(None),
_flag: std::cell::Cell::new(false),
}
}
}

#[cfg(target_thread_local)]
use std::thread::__FastLocalKeyInner as Key;

static __KEY: Key<()> = Key::new();
//~^ ERROR `std::cell::UnsafeCell<std::option::Option<()>>: std::marker::Sync` is not satisfied
//~| ERROR `std::cell::Cell<bool>: std::marker::Sync` is not satisfied

fn main() {}
41 changes: 41 additions & 0 deletions src/test/compile-fail/issue-43733.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(const_fn, drop_types_in_const)]
#![feature(cfg_target_thread_local, thread_local_internals)]

type Foo = std::cell::RefCell<String>;

#[cfg(target_thread_local)]
static __KEY: std::thread::__FastLocalKeyInner<Foo> =
std::thread::__FastLocalKeyInner::new();

#[cfg(not(target_thread_local))]
static __KEY: std::thread::__OsLocalKeyInner<Foo> =
std::thread::__OsLocalKeyInner::new();

fn __getit() -> std::option::Option<
&'static std::cell::UnsafeCell<
std::option::Option<Foo>>>
{
__KEY.get() //~ ERROR invocation of unsafe method requires unsafe
}

static FOO: std::thread::LocalKey<Foo> =
std::thread::LocalKey::new(__getit, Default::default);
//~^ ERROR call to unsafe function requires unsafe

fn main() {
FOO.with(|foo| println!("{}", foo.borrow()));
std::thread::spawn(|| {
FOO.with(|foo| *foo.borrow_mut() += "foo");
}).join().unwrap();
FOO.with(|foo| println!("{}", foo.borrow()));
}
38 changes: 38 additions & 0 deletions src/test/compile-fail/thread-local-in-ctfe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(const_fn, thread_local)]

#[thread_local]
static A: u32 = 1;

static B: u32 = A;
//~^ ERROR thread-local statics cannot be accessed at compile-time
//~| ERROR cannot refer to other statics by value
//~| WARN non-constant path in constant expression

static C: &u32 = &A;
//~^ ERROR thread-local statics cannot be accessed at compile-time

const D: u32 = A;
//~^ ERROR thread-local statics cannot be accessed at compile-time
//~| ERROR cannot refer to statics by value
//~| WARN non-constant path in constant expression

const E: &u32 = &A;
//~^ ERROR thread-local statics cannot be accessed at compile-time

const fn f() -> u32 {
A
//~^ ERROR thread-local statics cannot be accessed at compile-time
//~| ERROR cannot refer to statics by value
}

fn main() {}
7 changes: 6 additions & 1 deletion src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
Original file line number Diff line number Diff line change
@@ -48,5 +48,10 @@ impl TTMacroExpander for Expander {
pub fn plugin_registrar(reg: &mut Registry) {
let args = reg.args().to_owned();
reg.register_syntax_extension(Symbol::intern("plugin_args"),
NormalTT(Box::new(Expander { args: args, }), None, false));
NormalTT {
expander: Box::new(Expander { args: args, }),
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
});
}
11 changes: 7 additions & 4 deletions src/test/run-pass/auxiliary/thread-local-extern-static.rs
Original file line number Diff line number Diff line change
@@ -8,10 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(thread_local)]
#![feature(cfg_target_thread_local)]
#![feature(cfg_target_thread_local, const_fn, thread_local)]
#![crate_type = "lib"]

#[cfg(target_thread_local)]
use std::cell::Cell;

#[no_mangle]
#[cfg_attr(target_thread_local, thread_local)]
pub static FOO: u32 = 3;
#[cfg(target_thread_local)]
#[thread_local]
pub static FOO: Cell<u32> = Cell::new(3);
2 changes: 1 addition & 1 deletion src/test/run-pass/issue-30756.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(unsafe_code)]
#![forbid(unsafe_code)]

thread_local!(static FOO: u8 = 1);

18 changes: 13 additions & 5 deletions src/test/run-pass/thread-local-extern-static.rs
Original file line number Diff line number Diff line change
@@ -11,18 +11,26 @@
// ignore-windows
// aux-build:thread-local-extern-static.rs

#![feature(thread_local)]
#![feature(cfg_target_thread_local)]
#![feature(cfg_target_thread_local, thread_local)]

#[cfg(target_thread_local)]
extern crate thread_local_extern_static;

#[cfg(target_thread_local)]
use std::cell::Cell;

#[cfg(target_thread_local)]
extern {
#[cfg_attr(target_thread_local, thread_local)]
static FOO: u32;
#[thread_local]
static FOO: Cell<u32>;
}

#[cfg(target_thread_local)]
fn main() {
unsafe {
assert_eq!(FOO, 3);
assert_eq!(FOO.get(), 3);
}
}

#[cfg(not(target_thread_local))]
fn main() {}