Skip to content

Commit a77dfcc

Browse files
committed
Auto merge of #53131 - davidtwco:issue-52663-thread-local-static, r=nikomatsakis
NLL says something "does not live long enough" when talking about a (thread-local) static Part of #52663. r? @nikomatsakis
2 parents f6d43ed + 43850e0 commit a77dfcc

10 files changed

+104
-51
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+45-3
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
412412
.insert((root_place.clone(), borrow_span));
413413

414414
let mut err = match &self.describe_place(&borrow.borrowed_place) {
415+
Some(_) if self.is_place_thread_local(root_place) => {
416+
self.report_thread_local_value_does_not_live_long_enough(
417+
drop_span,
418+
borrow_span,
419+
)
420+
}
415421
Some(name) => self.report_local_value_does_not_live_long_enough(
416422
context,
417423
name,
@@ -455,9 +461,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
455461
context, name, scope_tree, borrow, drop_span, borrow_span
456462
);
457463

458-
let tcx = self.tcx;
459-
let mut err =
460-
tcx.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name), Origin::Mir);
464+
let mut err = self.tcx.path_does_not_live_long_enough(
465+
borrow_span, &format!("`{}`", name), Origin::Mir);
466+
461467
err.span_label(borrow_span, "borrowed value does not live long enough");
462468
err.span_label(
463469
drop_span,
@@ -468,6 +474,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
468474
err
469475
}
470476

477+
fn report_thread_local_value_does_not_live_long_enough(
478+
&mut self,
479+
drop_span: Span,
480+
borrow_span: Span,
481+
) -> DiagnosticBuilder<'cx> {
482+
debug!(
483+
"report_thread_local_value_does_not_live_long_enough(\
484+
{:?}, {:?}\
485+
)",
486+
drop_span, borrow_span
487+
);
488+
489+
let mut err = self.tcx.thread_local_value_does_not_live_long_enough(
490+
borrow_span, Origin::Mir);
491+
492+
err.span_label(borrow_span,
493+
"thread-local variables cannot be borrowed beyond the end of the function");
494+
err.span_label(drop_span, "end of enclosing function is here");
495+
err
496+
}
497+
471498
fn report_temporary_value_does_not_live_long_enough(
472499
&mut self,
473500
context: Context,
@@ -856,6 +883,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
856883
},
857884
}
858885
}
886+
887+
/// Check if a place is a thread-local static.
888+
pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
889+
if let Place::Static(statik) = place {
890+
let attrs = self.tcx.get_attrs(statik.def_id);
891+
let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
892+
893+
debug!("is_place_thread_local: attrs={:?} is_thread_local={:?}",
894+
attrs, is_thread_local);
895+
is_thread_local
896+
} else {
897+
debug!("is_place_thread_local: no");
898+
false
899+
}
900+
}
859901
}
860902

861903
// The span(s) associated to a use of a place.

src/librustc_mir/borrow_check/mod.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1487,15 +1487,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14871487
// FIXME: allow thread-locals to borrow other thread locals?
14881488
let (might_be_alive, will_be_dropped) = match root_place {
14891489
Place::Promoted(_) => (true, false),
1490-
Place::Static(statik) => {
1490+
Place::Static(_) => {
14911491
// Thread-locals might be dropped after the function exits, but
14921492
// "true" statics will never be.
1493-
let is_thread_local = self
1494-
.tcx
1495-
.get_attrs(statik.def_id)
1496-
.iter()
1497-
.any(|attr| attr.check_name("thread_local"));
1498-
1493+
let is_thread_local = self.is_place_thread_local(&root_place);
14991494
(true, is_thread_local)
15001495
}
15011496
Place::Local(_) => {

src/librustc_mir/diagnostics.rs

+23
Original file line numberDiff line numberDiff line change
@@ -2164,6 +2164,29 @@ unsafe { b.resume() };
21642164
```
21652165
"##,
21662166

2167+
E0712: r##"
2168+
This error occurs because a borrow of a thread-local variable was made inside a
2169+
function which outlived the lifetime of the function.
2170+
2171+
Example of erroneous code:
2172+
2173+
```compile_fail,E0712
2174+
#![feature(nll)]
2175+
#![feature(thread_local)]
2176+
2177+
#[thread_local]
2178+
static FOO: u8 = 3;
2179+
2180+
fn main() {
2181+
let a = &FOO; // error: thread-local variable borrowed past end of function
2182+
2183+
std::thread::spawn(move || {
2184+
println!("{}", a);
2185+
});
2186+
}
2187+
```
2188+
"##,
2189+
21672190
}
21682191

21692192
register_diagnostics! {

src/librustc_mir/util/borrowck_errors.rs

+16
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
675675

676676
self.cancel_if_wrong_origin(err, o)
677677
}
678+
679+
fn thread_local_value_does_not_live_long_enough(
680+
self,
681+
span: Span,
682+
o: Origin,
683+
) -> DiagnosticBuilder<'cx> {
684+
let err = struct_span_err!(
685+
self,
686+
span,
687+
E0712,
688+
"thread-local variable borrowed past end of function{OGN}",
689+
OGN = o
690+
);
691+
692+
self.cancel_if_wrong_origin(err, o)
693+
}
678694
}
679695

680696
impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {

src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ static FOO: u8 = 3;
1919
fn assert_static(_t: &'static u8) {}
2020
fn main() {
2121
assert_static(&FOO); //[ast]~ ERROR [E0597]
22-
//[mir]~^ ERROR [E0597]
22+
//[mir]~^ ERROR [E0712]
2323
}

src/test/ui/issue-17954.ast.nll.stderr

-14
This file was deleted.

src/test/ui/issue-17954.mir.stderr

-14
This file was deleted.

src/test/ui/issue-17954.nll.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0712]: thread-local variable borrowed past end of function
2+
--> $DIR/issue-17954.rs:17:13
3+
|
4+
LL | let a = &FOO;
5+
| ^^^^ thread-local variables cannot be borrowed beyond the end of the function
6+
...
7+
LL | }
8+
| - end of enclosing function is here
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0712`.

src/test/ui/issue-17954.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,19 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// revisions: ast mir
12-
//[mir]compile-flags: -Z borrowck=mir
13-
1411
#![feature(thread_local)]
1512

1613
#[thread_local]
1714
static FOO: u8 = 3;
1815

1916
fn main() {
2017
let a = &FOO;
21-
//[mir]~^ ERROR `FOO` does not live long enough [E0597]
22-
//[mir]~| does not live long enough
23-
//[mir]~| NOTE borrowed value must be valid for the static lifetime
24-
//[ast]~^^^^ ERROR borrowed value does not live long enough
25-
//[ast]~| does not live long enough
26-
//[ast]~| NOTE borrowed value must be valid for the static lifetime
18+
//~^ ERROR borrowed value does not live long enough
19+
//~| does not live long enough
20+
//~| NOTE borrowed value must be valid for the static lifetime
2721

2822
std::thread::spawn(move || {
2923
println!("{}", a);
3024
});
3125
}
32-
//[mir]~^ `FOO` dropped here while still borrowed
33-
//[ast]~^^ temporary value only lives until here
26+
//~^ NOTE temporary value only lives until here

src/test/ui/issue-17954.ast.stderr src/test/ui/issue-17954.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0597]: borrowed value does not live long enough
2-
--> $DIR/issue-17954.rs:20:14
2+
--> $DIR/issue-17954.rs:17:14
33
|
44
LL | let a = &FOO;
55
| ^^^ temporary value does not live long enough

0 commit comments

Comments
 (0)