提交 45649335 编写于 作者: B bors

Auto merge of #43746 - eddyb:sound-thread-local, r=alexcrichton

Check #[thread_local] statics correctly in the compiler.

Fixes #43733 by introducing `#[allow_internal_unsafe]` analogous to `#[allow_internal_unstable]`, for letting a macro expand to `unsafe` blocks and functions even in `#![forbid(unsafe_code)]` crates.

Fixes #17954 by not letting references to `#[thread_local]` statics escape the function they're taken in - we can't just use a magical lifetime because Rust has *lifetime parametrism*, so if we added the often-proposed `'thread` lifetime, we'd have no way to check it in generic code.
To avoid potential edge cases in the compiler, the lifetime is actually that of a temporary at the same position, i.e. `&TLS_STATIC` has the same lifetime `&non_const_fn()` would.

Referring to `#[thread_local]` `static`s at compile-time is banned now (as per PR discussion).

Additionally, to remove `unsafe impl Sync` from `std::thread::local::fast::Key`, `#[thread_local]` statics are now not required to implement `Sync`, as they are not shared between threads.
......@@ -404,6 +404,7 @@ fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span
format: codemap::CompilerDesugaring(Symbol::intern(reason)),
span: Some(span),
allow_internal_unstable: true,
allow_internal_unsafe: false,
},
});
span.ctxt = SyntaxContext::empty().apply_mark(mark);
......
......@@ -643,7 +643,13 @@ pub fn cat_def(&self,
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.
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,
......
......@@ -79,6 +79,7 @@ fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
format: MacroAttribute(Symbol::intern(name)),
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
}
});
let span = Span {
......
......@@ -195,12 +195,23 @@ fn get_lints(&self) -> LintArray {
}
}
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");
}
}
}
......@@ -208,11 +219,11 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
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 @@ fn check_fn(&mut self,
_: 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 @@ fn check_fn(&mut self,
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")
}
}
}
......
......@@ -442,4 +442,5 @@ struct Foo {
register_diagnostics! {
E0526, // shuffle indices are not constant
E0625, // thread-local statics cannot be accessed at compile-time
}
......@@ -484,8 +484,20 @@ fn visit_lvalue(&mut self,
}
}
},
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 @@ fn run_pass<'a, 'tcx>(&self,
// 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);
......
......@@ -102,9 +102,19 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
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 @@ pub fn take_whitelisted_custom_derives(&mut self) -> Vec<ast::Name> {
/// 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.
......
......@@ -313,7 +313,7 @@ fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, forc
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,
};
......
......@@ -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)]
......
......@@ -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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 @@ fn __getit() -> $crate::option::Option<
__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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
#[cfg(stage0)]
unsafe impl<T> ::marker::Sync for Key<T> { }
impl<T> Key<T> {
......@@ -402,14 +406,12 @@ pub const fn new() -> Key<T> {
}
}
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 const fn new() -> Key<T> {
}
}
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)
}
}
......
......@@ -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,
......
......@@ -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,
},
});
......
......@@ -411,6 +411,7 @@ fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
}
});
......@@ -458,7 +459,9 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
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 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
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 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
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 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
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 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
span: None,
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable: false,
allow_internal_unsafe: false,
},
});
......@@ -578,6 +590,7 @@ fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -
format: MacroAttribute(pretty_name),
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
}
};
......
......@@ -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)))
}
}
......
......@@ -194,6 +194,14 @@ pub fn new() -> 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 fn is_builtin_attr(attr: &ast::Attribute) -> bool {
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 fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga
"`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.";
......
......@@ -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 }
......
......@@ -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,
}
});
......
......@@ -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);
......
......@@ -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 };
......
......@@ -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.
......
......@@ -153,6 +153,16 @@ pub fn allows_unstable(&self) -> bool {
}
}
/// 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![];
......
// 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() {}
// 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
// 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() {}
// 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()));
}
// 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() {}
......@@ -48,5 +48,10 @@ fn expand<'cx>(&self,
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,
});
}
......@@ -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);
......@@ -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);
......
......@@ -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() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册