Skip to content

Commit f32f111

Browse files
committed
Auto merge of #55150 - pnkfelix:issues-47215-54797-fix-ice-from-moving-out-of-thread-local-under-ast-borrowck, r=nikomatsakis
Do not allow moving out of thread local under ast borrowck AST borrowck failed to prevent moving out of a thread-local static. This was broken. And it also (sometimes?) caused an ICE during drop elaboration. Fix #47215 Fix #54797
2 parents 42c11de + 1d46ce5 commit f32f111

16 files changed

+91
-14
lines changed

src/librustc/middle/mem_categorization.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ use util::nodemap::ItemLocalSet;
9393
#[derive(Clone, Debug, PartialEq)]
9494
pub enum Categorization<'tcx> {
9595
Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope
96+
ThreadLocal(ty::Region<'tcx>), // value that cannot move, but still restricted in scope
9697
StaticItem,
9798
Upvar(Upvar), // upvar referenced by closure env
9899
Local(ast::NodeId), // local variable
@@ -268,6 +269,7 @@ impl<'tcx> cmt_<'tcx> {
268269
Categorization::Deref(ref base_cmt, _) => {
269270
base_cmt.immutability_blame()
270271
}
272+
Categorization::ThreadLocal(..) |
271273
Categorization::StaticItem => {
272274
// Do we want to do something here?
273275
None
@@ -715,17 +717,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
715717
}
716718

717719
Def::Static(def_id, mutbl) => {
718-
// `#[thread_local]` statics may not outlive the current function.
719-
for attr in &self.tcx.get_attrs(def_id)[..] {
720-
if attr.check_name("thread_local") {
721-
return Ok(self.cat_rvalue_node(hir_id, span, expr_ty));
722-
}
723-
}
720+
// `#[thread_local]` statics may not outlive the current function, but
721+
// they also cannot be moved out of.
722+
let is_thread_local = self.tcx.get_attrs(def_id)[..]
723+
.iter()
724+
.any(|attr| attr.check_name("thread_local"));
725+
726+
let cat = if is_thread_local {
727+
let re = self.temporary_scope(hir_id.local_id);
728+
Categorization::ThreadLocal(re)
729+
} else {
730+
Categorization::StaticItem
731+
};
724732

725733
Ok(cmt_ {
726734
hir_id,
727-
span:span,
728-
cat:Categorization::StaticItem,
735+
span,
736+
cat,
729737
mutbl: if mutbl { McDeclared } else { McImmutable},
730738
ty:expr_ty,
731739
note: NoteNone
@@ -1408,6 +1416,7 @@ impl<'tcx> cmt_<'tcx> {
14081416
match self.cat {
14091417
Categorization::Rvalue(..) |
14101418
Categorization::StaticItem |
1419+
Categorization::ThreadLocal(..) |
14111420
Categorization::Local(..) |
14121421
Categorization::Deref(_, UnsafePtr(..)) |
14131422
Categorization::Deref(_, BorrowedPtr(..)) |
@@ -1439,6 +1448,7 @@ impl<'tcx> cmt_<'tcx> {
14391448
}
14401449

14411450
Categorization::Rvalue(..) |
1451+
Categorization::ThreadLocal(..) |
14421452
Categorization::Local(..) |
14431453
Categorization::Upvar(..) |
14441454
Categorization::Deref(_, UnsafePtr(..)) => { // yes, it's aliasable, but...
@@ -1485,6 +1495,9 @@ impl<'tcx> cmt_<'tcx> {
14851495
Categorization::StaticItem => {
14861496
"static item".into()
14871497
}
1498+
Categorization::ThreadLocal(..) => {
1499+
"thread-local static item".into()
1500+
}
14881501
Categorization::Rvalue(..) => {
14891502
"non-place".into()
14901503
}

src/librustc_borrowck/borrowck/check_loans.rs

+1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
377377
// by-move upvars, which is local data for generators
378378
Categorization::Upvar(..) => true,
379379

380+
Categorization::ThreadLocal(region) |
380381
Categorization::Rvalue(region) => {
381382
// Rvalues promoted to 'static are no longer local
382383
if let RegionKind::ReStatic = *region {

src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
177177
match cmt.cat {
178178
Categorization::Deref(_, mc::BorrowedPtr(..)) |
179179
Categorization::Deref(_, mc::UnsafePtr(..)) |
180+
Categorization::ThreadLocal(..) |
180181
Categorization::StaticItem => {
181182
Some(cmt.clone())
182183
}

src/librustc_borrowck/borrowck/gather_loans/lifetime.rs

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
7070

7171
match cmt.cat {
7272
Categorization::Rvalue(..) |
73+
Categorization::ThreadLocal(..) |
7374
Categorization::Local(..) | // L-Local
7475
Categorization::Upvar(..) |
7576
Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
@@ -105,6 +106,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
105106
//! rooting etc, and presuming `cmt` is not mutated.
106107
107108
match cmt.cat {
109+
Categorization::ThreadLocal(temp_scope) |
108110
Categorization::Rvalue(temp_scope) => {
109111
temp_scope
110112
}

src/librustc_borrowck/borrowck/gather_loans/move_error.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
145145
match move_from.cat {
146146
Categorization::Deref(_, mc::BorrowedPtr(..)) |
147147
Categorization::Deref(_, mc::UnsafePtr(..)) |
148+
Categorization::Deref(_, mc::Unique) |
149+
Categorization::ThreadLocal(..) |
148150
Categorization::StaticItem => {
149151
bccx.cannot_move_out_of(
150152
move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
@@ -166,7 +168,10 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
166168
}
167169
}
168170
}
169-
_ => {
171+
172+
Categorization::Rvalue(..) |
173+
Categorization::Local(..) |
174+
Categorization::Upvar(..) => {
170175
span_bug!(move_from.span, "this path should not cause illegal move");
171176
}
172177
}

src/librustc_borrowck/borrowck/gather_loans/restrictions.rs

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
7070
RestrictionResult::Safe
7171
}
7272

73+
Categorization::ThreadLocal(..) => {
74+
// Thread-locals are statics that have a scope, with
75+
// no underlying structure to provide restrictions.
76+
RestrictionResult::Safe
77+
}
78+
7379
Categorization::Local(local_id) => {
7480
// R-Variable, locally declared
7581
let lp = new_lp(LpVar(local_id));

src/librustc_borrowck/borrowck/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option<Rc<LoanPath
520520

521521
match cmt.cat {
522522
Categorization::Rvalue(..) |
523+
Categorization::ThreadLocal(..) |
523524
Categorization::StaticItem => {
524525
(None, false)
525526
}

src/librustc_passes/rvalue_promotion.rs

+1
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
663663
let mut cur = cmt;
664664
loop {
665665
match cur.cat {
666+
Categorization::ThreadLocal(..) |
666667
Categorization::Rvalue(..) => {
667668
if loan_cause == euv::MatchDiscriminant {
668669
// Ignore the dummy immutable borrow created by EUV.

src/librustc_typeck/check/regionck.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
12431243
| Categorization::StaticItem
12441244
| Categorization::Upvar(..)
12451245
| Categorization::Local(..)
1246+
| Categorization::ThreadLocal(..)
12461247
| Categorization::Rvalue(..) => {
12471248
// These are all "base cases" with independent lifetimes
12481249
// that are not subject to inference

src/librustc_typeck/check/upvar.rs

+2
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
401401

402402
Categorization::Deref(_, mc::UnsafePtr(..)) |
403403
Categorization::StaticItem |
404+
Categorization::ThreadLocal(..) |
404405
Categorization::Rvalue(..) |
405406
Categorization::Local(_) |
406407
Categorization::Upvar(..) => {
@@ -431,6 +432,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> {
431432

432433
Categorization::Deref(_, mc::UnsafePtr(..)) |
433434
Categorization::StaticItem |
435+
Categorization::ThreadLocal(..) |
434436
Categorization::Rvalue(..) |
435437
Categorization::Local(_) |
436438
Categorization::Upvar(..) => {}

src/test/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.ast.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ error[E0597]: borrowed value does not live long enough
22
--> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:21:21
33
|
44
LL | assert_static(&FOO); //[ast]~ ERROR [E0597]
5-
| ^^^ - temporary value only lives until here
5+
| ^^^ - borrowed value only lives until here
66
| |
7-
| temporary value does not live long enough
7+
| borrowed value does not live long enough
88
|
99
= note: borrowed value must be valid for the static lifetime...
1010

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0507]: cannot move out of static item
2+
--> $DIR/issue-47215-ice-from-drop-elab.rs:17:21
3+
|
4+
LL | let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507]
5+
| ^
6+
| |
7+
| cannot move out of static item
8+
| help: consider borrowing here: `&X`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0507`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// rust-lang/rust#47215: at one time, the compiler categorized
2+
// thread-local statics as a temporary rvalue, as a way to enforce
3+
// that they are only valid for a given lifetime.
4+
//
5+
// The problem with this is that you cannot move out of static items,
6+
// but you *can* move temporary rvalues. I.e., the categorization
7+
// above only solves half of the problem presented by thread-local
8+
// statics.
9+
10+
#![feature(thread_local)]
11+
12+
#[thread_local]
13+
static mut X: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
14+
15+
fn main() {
16+
unsafe {
17+
let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507]
18+
let _y = x.get_mut();
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0507]: cannot move out of thread-local static item
2+
--> $DIR/issue-47215-ice-from-drop-elab.rs:17:21
3+
|
4+
LL | let mut x = X; //~ ERROR cannot move out of thread-local static item [E0507]
5+
| ^
6+
| |
7+
| cannot move out of thread-local static item
8+
| help: consider using a reference instead: `&X`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0507`.

src/test/ui/issues/issue-17954.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ fn main() {
2323
println!("{}", a);
2424
});
2525
}
26-
//~^ NOTE temporary value only lives until here
26+
//~^ NOTE borrowed value only lives until here

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ error[E0597]: borrowed value does not live long enough
22
--> $DIR/issue-17954.rs:17:14
33
|
44
LL | let a = &FOO;
5-
| ^^^ temporary value does not live long enough
5+
| ^^^ borrowed value does not live long enough
66
...
77
LL | }
8-
| - temporary value only lives until here
8+
| - borrowed value only lives until here
99
|
1010
= note: borrowed value must be valid for the static lifetime...
1111

0 commit comments

Comments
 (0)