Skip to content

Commit c0bfe34

Browse files
committedDec 9, 2020
Auto merge of rust-lang#78363 - RalfJung:promotion, r=oli-obk
remove this weird special case from promotion Promotion has a special case to ignore interior mutability under some specific circumstances. The purpose of this PR is to figure out what changes if we remove that. Since `Cell::new` and friends only get promoted inside `const`/`static` initializers these days, it actually is not easy to exploit this case: you need something like ```rust const TEST_INTERIOR_MUT: () = { // The "0." case is already ruled out by not permitting any interior mutability in `const`. let _val: &'static _ = &(Cell::new(1), 2).1; }; ``` I assume something like `&Some(&(Cell::new(1), 2).1)` would hit the nested case inside `validate_rvalue`... though I am not sure why that would not just trigger nested promotion, first promoting the inner reference and then the outer one? Fixes rust-lang#67534 (by simply rejecting that code^^) r? `@oli-obk` (but for now this is not meant to be merged!) Cc `@rust-lang/wg-const-eval`
2 parents db85512 + d057a93 commit c0bfe34

File tree

4 files changed

+56
-78
lines changed

4 files changed

+56
-78
lines changed
 

‎compiler/rustc_mir/src/transform/promote_consts.rs

+6-52
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_middle::ty::cast::CastTy;
2222
use rustc_middle::ty::subst::InternalSubsts;
2323
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
2424
use rustc_span::symbol::sym;
25-
use rustc_span::{Span, DUMMY_SP};
25+
use rustc_span::Span;
2626

2727
use rustc_index::vec::{Idx, IndexVec};
2828
use rustc_target::spec::abi::Abi;
@@ -326,41 +326,16 @@ impl<'tcx> Validator<'_, 'tcx> {
326326
if place.projection.contains(&ProjectionElem::Deref) {
327327
return Err(Unpromotable);
328328
}
329-
330-
let mut has_mut_interior =
331-
self.qualif_local::<qualifs::HasMutInterior>(place.local);
332-
// HACK(eddyb) this should compute the same thing as
333-
// `<HasMutInterior as Qualif>::in_projection` from
334-
// `check_consts::qualifs` but without recursion.
335-
if has_mut_interior {
336-
// This allows borrowing fields which don't have
337-
// `HasMutInterior`, from a type that does, e.g.:
338-
// `let _: &'static _ = &(Cell::new(1), 2).1;`
339-
let mut place_projection = &place.projection[..];
340-
// FIXME(eddyb) use a forward loop instead of a reverse one.
341-
while let &[ref proj_base @ .., elem] = place_projection {
342-
// FIXME(eddyb) this is probably excessive, with
343-
// the exception of `union` member accesses.
344-
let ty =
345-
Place::ty_from(place.local, proj_base, self.body, self.tcx)
346-
.projection_ty(self.tcx, elem)
347-
.ty;
348-
if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
349-
has_mut_interior = false;
350-
break;
351-
}
352-
353-
place_projection = proj_base;
354-
}
329+
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
330+
return Err(Unpromotable);
355331
}
356332

357333
// FIXME(eddyb) this duplicates part of `validate_rvalue`.
334+
let has_mut_interior =
335+
self.qualif_local::<qualifs::HasMutInterior>(place.local);
358336
if has_mut_interior {
359337
return Err(Unpromotable);
360338
}
361-
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
362-
return Err(Unpromotable);
363-
}
364339

365340
if let BorrowKind::Mut { .. } = kind {
366341
let ty = place.ty(self.body, self.tcx).ty;
@@ -692,28 +667,7 @@ impl<'tcx> Validator<'_, 'tcx> {
692667

693668
self.validate_place(place)?;
694669

695-
// HACK(eddyb) this should compute the same thing as
696-
// `<HasMutInterior as Qualif>::in_projection` from
697-
// `check_consts::qualifs` but without recursion.
698-
let mut has_mut_interior =
699-
self.qualif_local::<qualifs::HasMutInterior>(place.local);
700-
if has_mut_interior {
701-
let mut place_projection = place.projection;
702-
// FIXME(eddyb) use a forward loop instead of a reverse one.
703-
while let &[ref proj_base @ .., elem] = place_projection {
704-
// FIXME(eddyb) this is probably excessive, with
705-
// the exception of `union` member accesses.
706-
let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx)
707-
.projection_ty(self.tcx, elem)
708-
.ty;
709-
if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
710-
has_mut_interior = false;
711-
break;
712-
}
713-
714-
place_projection = proj_base;
715-
}
716-
}
670+
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
717671
if has_mut_interior {
718672
return Err(Unpromotable);
719673
}

‎src/test/ui/consts/promote-not.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(unconditional_panic, const_err)]
44
#![feature(const_fn, const_fn_union)]
55

6+
use std::cell::Cell;
7+
68
// We do not promote mutable references.
79
static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
810

@@ -32,4 +34,14 @@ const TEST_UNION: () = {
3234
let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
3335
};
3436

35-
fn main() {}
37+
// In a `const`, we do not promote things with interior mutability. Not even if we "project it away".
38+
const TEST_INTERIOR_MUT: () = {
39+
// The "0." case is already ruled out by not permitting any interior mutability in `const`.
40+
let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
41+
};
42+
43+
fn main() {
44+
// We must not promote things with interior mutability. Not even if we "project it away".
45+
let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed
46+
let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
47+
}

‎src/test/ui/consts/promote-not.stderr

+37-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0716]: temporary value dropped while borrowed
2-
--> $DIR/promote-not.rs:7:50
2+
--> $DIR/promote-not.rs:9:50
33
|
44
LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
55
| ----------^^^^^^^^^-
@@ -9,7 +9,7 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]);
99
| using this value as a static requires that borrow lasts for `'static`
1010

1111
error[E0716]: temporary value dropped while borrowed
12-
--> $DIR/promote-not.rs:10:18
12+
--> $DIR/promote-not.rs:12:18
1313
|
1414
LL | let x = &mut [1,2,3];
1515
| ^^^^^^^ creates a temporary which is freed while still in use
@@ -19,7 +19,7 @@ LL | };
1919
| - temporary value is freed at the end of this statement
2020

2121
error[E0716]: temporary value dropped while borrowed
22-
--> $DIR/promote-not.rs:19:32
22+
--> $DIR/promote-not.rs:21:32
2323
|
2424
LL | let _x: &'static () = &foo();
2525
| ----------- ^^^^^ creates a temporary which is freed while still in use
@@ -29,7 +29,7 @@ LL | }
2929
| - temporary value is freed at the end of this statement
3030

3131
error[E0716]: temporary value dropped while borrowed
32-
--> $DIR/promote-not.rs:27:29
32+
--> $DIR/promote-not.rs:29:29
3333
|
3434
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
3535
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -39,7 +39,7 @@ LL | }
3939
| - temporary value is freed at the end of this statement
4040

4141
error[E0716]: temporary value dropped while borrowed
42-
--> $DIR/promote-not.rs:32:29
42+
--> $DIR/promote-not.rs:34:29
4343
|
4444
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
4545
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -48,6 +48,37 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
4848
LL | };
4949
| - temporary value is freed at the end of this statement
5050

51-
error: aborting due to 5 previous errors
51+
error[E0716]: temporary value dropped while borrowed
52+
--> $DIR/promote-not.rs:40:29
53+
|
54+
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
55+
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
56+
| |
57+
| type annotation requires that borrow lasts for `'static`
58+
LL | };
59+
| - temporary value is freed at the end of this statement
60+
61+
error[E0716]: temporary value dropped while borrowed
62+
--> $DIR/promote-not.rs:45:29
63+
|
64+
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
65+
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
66+
| |
67+
| type annotation requires that borrow lasts for `'static`
68+
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
69+
LL | }
70+
| - temporary value is freed at the end of this statement
71+
72+
error[E0716]: temporary value dropped while borrowed
73+
--> $DIR/promote-not.rs:46:29
74+
|
75+
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
76+
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
77+
| |
78+
| type annotation requires that borrow lasts for `'static`
79+
LL | }
80+
| - temporary value is freed at the end of this statement
81+
82+
error: aborting due to 8 previous errors
5283

5384
For more information about this error, try `rustc --explain E0716`.

‎src/test/ui/issues/issue-49955-2.rs

-19
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.