Skip to content

Commit

Permalink
Auto merge of #53131 - davidtwco:issue-52663-thread-local-static, r=n…
Browse files Browse the repository at this point in the history
…ikomatsakis

NLL says something "does not live long enough" when talking about a (thread-local) static

Part of #52663.

r? @nikomatsakis
  • Loading branch information
bors committed Aug 10, 2018
2 parents f6d43ed + 43850e0 commit a77dfcc
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 51 deletions.
48 changes: 45 additions & 3 deletions src/librustc_mir/borrow_check/error_reporting.rs
Expand Up @@ -412,6 +412,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
.insert((root_place.clone(), borrow_span));

let mut err = match &self.describe_place(&borrow.borrowed_place) {
Some(_) if self.is_place_thread_local(root_place) => {
self.report_thread_local_value_does_not_live_long_enough(
drop_span,
borrow_span,
)
}
Some(name) => self.report_local_value_does_not_live_long_enough(
context,
name,
Expand Down Expand Up @@ -455,9 +461,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context, name, scope_tree, borrow, drop_span, borrow_span
);

let tcx = self.tcx;
let mut err =
tcx.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name), Origin::Mir);
let mut err = self.tcx.path_does_not_live_long_enough(
borrow_span, &format!("`{}`", name), Origin::Mir);

err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(
drop_span,
Expand All @@ -468,6 +474,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err
}

fn report_thread_local_value_does_not_live_long_enough(
&mut self,
drop_span: Span,
borrow_span: Span,
) -> DiagnosticBuilder<'cx> {
debug!(
"report_thread_local_value_does_not_live_long_enough(\
{:?}, {:?}\
)",
drop_span, borrow_span
);

let mut err = self.tcx.thread_local_value_does_not_live_long_enough(
borrow_span, Origin::Mir);

err.span_label(borrow_span,
"thread-local variables cannot be borrowed beyond the end of the function");
err.span_label(drop_span, "end of enclosing function is here");
err
}

fn report_temporary_value_does_not_live_long_enough(
&mut self,
context: Context,
Expand Down Expand Up @@ -856,6 +883,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
},
}
}

/// Check if a place is a thread-local static.
pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
if let Place::Static(statik) = place {
let attrs = self.tcx.get_attrs(statik.def_id);
let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));

debug!("is_place_thread_local: attrs={:?} is_thread_local={:?}",
attrs, is_thread_local);
is_thread_local
} else {
debug!("is_place_thread_local: no");
false
}
}
}

// The span(s) associated to a use of a place.
Expand Down
9 changes: 2 additions & 7 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -1487,15 +1487,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) = match root_place {
Place::Promoted(_) => (true, false),
Place::Static(statik) => {
Place::Static(_) => {
// Thread-locals might be dropped after the function exits, but
// "true" statics will never be.
let is_thread_local = self
.tcx
.get_attrs(statik.def_id)
.iter()
.any(|attr| attr.check_name("thread_local"));

let is_thread_local = self.is_place_thread_local(&root_place);
(true, is_thread_local)
}
Place::Local(_) => {
Expand Down
23 changes: 23 additions & 0 deletions src/librustc_mir/diagnostics.rs
Expand Up @@ -2164,6 +2164,29 @@ unsafe { b.resume() };
```
"##,

E0712: r##"
This error occurs because a borrow of a thread-local variable was made inside a
function which outlived the lifetime of the function.
Example of erroneous code:
```compile_fail,E0712
#![feature(nll)]
#![feature(thread_local)]
#[thread_local]
static FOO: u8 = 3;
fn main() {
let a = &FOO; // error: thread-local variable borrowed past end of function
std::thread::spawn(move || {
println!("{}", a);
});
}
```
"##,

}

register_diagnostics! {
Expand Down
16 changes: 16 additions & 0 deletions src/librustc_mir/util/borrowck_errors.rs
Expand Up @@ -675,6 +675,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {

self.cancel_if_wrong_origin(err, o)
}

fn thread_local_value_does_not_live_long_enough(
self,
span: Span,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0712,
"thread-local variable borrowed past end of function{OGN}",
OGN = o
);

self.cancel_if_wrong_origin(err, o)
}
}

impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
Expand Down
Expand Up @@ -19,5 +19,5 @@ static FOO: u8 = 3;
fn assert_static(_t: &'static u8) {}
fn main() {
assert_static(&FOO); //[ast]~ ERROR [E0597]
//[mir]~^ ERROR [E0597]
//[mir]~^ ERROR [E0712]
}
14 changes: 0 additions & 14 deletions src/test/ui/issue-17954.ast.nll.stderr

This file was deleted.

14 changes: 0 additions & 14 deletions src/test/ui/issue-17954.mir.stderr

This file was deleted.

12 changes: 12 additions & 0 deletions src/test/ui/issue-17954.nll.stderr
@@ -0,0 +1,12 @@
error[E0712]: thread-local variable borrowed past end of function
--> $DIR/issue-17954.rs:17:13
|
LL | let a = &FOO;
| ^^^^ thread-local variables cannot be borrowed beyond the end of the function
...
LL | }
| - end of enclosing function is here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0712`.
15 changes: 4 additions & 11 deletions src/test/ui/issue-17954.rs
Expand Up @@ -8,26 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

#![feature(thread_local)]

#[thread_local]
static FOO: u8 = 3;

fn main() {
let a = &FOO;
//[mir]~^ ERROR `FOO` does not live long enough [E0597]
//[mir]~| does not live long enough
//[mir]~| NOTE borrowed value must be valid for the static lifetime
//[ast]~^^^^ ERROR borrowed value does not live long enough
//[ast]~| does not live long enough
//[ast]~| NOTE borrowed value must be valid for the static lifetime
//~^ 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);
});
}
//[mir]~^ `FOO` dropped here while still borrowed
//[ast]~^^ temporary value only lives until here
//~^ NOTE temporary value only lives until here
@@ -1,5 +1,5 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/issue-17954.rs:20:14
--> $DIR/issue-17954.rs:17:14
|
LL | let a = &FOO;
| ^^^ temporary value does not live long enough
Expand Down

0 comments on commit a77dfcc

Please sign in to comment.