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

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

Merged
merged 1 commit into from
Aug 10, 2018
Merged
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
48 changes: 45 additions & 3 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -2251,6 +2251,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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