Skip to content

Commit 9300fbb

Browse files
Rollup merge of #121893 - RalfJung:const-interior-mut-tests, r=oli-obk
Add tests (and a bit of cleanup) for interior mut handling in promotion and const-checking Basically these are the parts of #121786 that can be salvaged. r? ``@oli-obk``
2 parents 1279830 + fb802f2 commit 9300fbb

File tree

8 files changed

+119
-33
lines changed

8 files changed

+119
-33
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,10 @@ pub fn const_validate_mplace<'mir, 'tcx>(
412412
_ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
413413
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
414414
None => {
415-
// In normal `const` (not promoted), the outermost allocation is always only copied,
416-
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
417-
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
418-
CtfeValidationMode::Const { allow_immutable_unsafe_cell }
415+
// This is a normal `const` (not promoted).
416+
// The outermost allocation is always only copied, so having `UnsafeCell` in there
417+
// is okay despite them being in immutable memory.
418+
CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner }
419419
}
420420
};
421421
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type QualifResults<'mir, 'tcx, Q> =
3030
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
3131

3232
#[derive(Default)]
33-
pub struct Qualifs<'mir, 'tcx> {
33+
pub(crate) struct Qualifs<'mir, 'tcx> {
3434
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
3535
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
3636
needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ where
284284
if Q::in_adt_inherently(cx, def, args) {
285285
return true;
286286
}
287+
// Don't do any value-based reasoning for unions.
287288
if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
288289
return true;
289290
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@build-pass
2+
// Some code that looks like it might be relying on promotion, but actually this is using the
3+
// enclosing-scope rule, meaning the reference is "extended" to outlive its block and live as long
4+
// as the surrounding block (which in this case is the entire program). There are multiple
5+
// allocations being interned at once.
6+
7+
struct Gen<T>(T);
8+
impl<'a, T> Gen<&'a T> {
9+
// Can't be promoted because `T` might not be `'static`.
10+
const C: &'a [T] = &[];
11+
}
12+
13+
// Can't be promoted because of `Drop`.
14+
const V: &Vec<i32> = &Vec::new();
15+
16+
fn main() {}

tests/ui/consts/promote-not.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![allow(unconditional_panic)]
44

55
use std::cell::Cell;
6+
use std::mem::ManuallyDrop;
67

78
// We do not promote mutable references.
89
static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed
@@ -39,7 +40,16 @@ const TEST_INTERIOR_MUT: () = {
3940
let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
4041
};
4142

42-
const TEST_DROP: String = String::new();
43+
// This gets accepted by the "outer scope" rule, not promotion.
44+
const TEST_DROP_OUTER_SCOPE: &String = &String::new();
45+
// To demonstrate that, we can rewrite it as follows. If this was promotion it would still work.
46+
const TEST_DROP_NOT_PROMOTE: &String = {
47+
let x = &String::new(); //~ ERROR destructor of `String` cannot be evaluated at compile-time
48+
// The "dropped while borrowed" error seems to be suppressed, but the key point is that this
49+
// fails to compile.
50+
x
51+
};
52+
4353

4454
fn main() {
4555
// We must not promote things with interior mutability. Not even if we "project it away".
@@ -58,6 +68,7 @@ fn main() {
5868
let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
5969

6070
// No promotion of temporaries that need to be dropped.
71+
const TEST_DROP: String = String::new();
6172
let _val: &'static _ = &TEST_DROP;
6273
//~^ ERROR temporary value dropped while borrowed
6374
let _val: &'static _ = &&TEST_DROP;
@@ -69,4 +80,12 @@ fn main() {
6980
let _val: &'static _ = &[&TEST_DROP; 1];
7081
//~^ ERROR temporary value dropped while borrowed
7182
//~| ERROR temporary value dropped while borrowed
83+
84+
// Make sure there is no value-based reasoning for unions.
85+
union UnionWithCell {
86+
f1: i32,
87+
f2: ManuallyDrop<Cell<i32>>,
88+
}
89+
let x: &'static _ = &UnionWithCell { f1: 0 };
90+
//~^ ERROR temporary value dropped while borrowed
7291
}

tests/ui/consts/promote-not.stderr

+47-26
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:8: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:11:18
12+
--> $DIR/promote-not.rs:12:18
1313
|
1414
LL | let x = &mut [1,2,3];
1515
| ^^^^^^^ creates a temporary value 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:33:29
22+
--> $DIR/promote-not.rs:34:29
2323
|
2424
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
2525
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value 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:39:29
32+
--> $DIR/promote-not.rs:40:29
3333
|
3434
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
3535
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -38,8 +38,17 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).1;
3838
LL | };
3939
| - temporary value is freed at the end of this statement
4040

41+
error[E0493]: destructor of `String` cannot be evaluated at compile-time
42+
--> $DIR/promote-not.rs:47:14
43+
|
44+
LL | let x = &String::new();
45+
| ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants
46+
...
47+
LL | };
48+
| - value is dropped here
49+
4150
error[E0716]: temporary value dropped while borrowed
42-
--> $DIR/promote-not.rs:20:32
51+
--> $DIR/promote-not.rs:21:32
4352
|
4453
LL | let _x: &'static () = &foo();
4554
| ----------- ^^^^^ creates a temporary value which is freed while still in use
@@ -49,7 +58,7 @@ LL | }
4958
| - temporary value is freed at the end of this statement
5059

5160
error[E0716]: temporary value dropped while borrowed
52-
--> $DIR/promote-not.rs:28:29
61+
--> $DIR/promote-not.rs:29:29
5362
|
5463
LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x };
5564
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -59,7 +68,7 @@ LL | }
5968
| - temporary value is freed at the end of this statement
6069

6170
error[E0716]: temporary value dropped while borrowed
62-
--> $DIR/promote-not.rs:46:29
71+
--> $DIR/promote-not.rs:56:29
6372
|
6473
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
6574
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -70,7 +79,7 @@ LL | }
7079
| - temporary value is freed at the end of this statement
7180

7281
error[E0716]: temporary value dropped while borrowed
73-
--> $DIR/promote-not.rs:47:29
82+
--> $DIR/promote-not.rs:57:29
7483
|
7584
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
7685
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -81,7 +90,7 @@ LL | }
8190
| - temporary value is freed at the end of this statement
8291

8392
error[E0716]: temporary value dropped while borrowed
84-
--> $DIR/promote-not.rs:50:29
93+
--> $DIR/promote-not.rs:60:29
8594
|
8695
LL | let _val: &'static _ = &(1/0);
8796
| ---------- ^^^^^ creates a temporary value which is freed while still in use
@@ -92,7 +101,7 @@ LL | }
92101
| - temporary value is freed at the end of this statement
93102

94103
error[E0716]: temporary value dropped while borrowed
95-
--> $DIR/promote-not.rs:51:29
104+
--> $DIR/promote-not.rs:61:29
96105
|
97106
LL | let _val: &'static _ = &(1/(1-1));
98107
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -103,7 +112,7 @@ LL | }
103112
| - temporary value is freed at the end of this statement
104113

105114
error[E0716]: temporary value dropped while borrowed
106-
--> $DIR/promote-not.rs:52:29
115+
--> $DIR/promote-not.rs:62:29
107116
|
108117
LL | let _val: &'static _ = &((1+1)/(1-1));
109118
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -114,7 +123,7 @@ LL | }
114123
| - temporary value is freed at the end of this statement
115124

116125
error[E0716]: temporary value dropped while borrowed
117-
--> $DIR/promote-not.rs:53:29
126+
--> $DIR/promote-not.rs:63:29
118127
|
119128
LL | let _val: &'static _ = &(i32::MIN/-1);
120129
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -125,7 +134,7 @@ LL | }
125134
| - temporary value is freed at the end of this statement
126135

127136
error[E0716]: temporary value dropped while borrowed
128-
--> $DIR/promote-not.rs:54:29
137+
--> $DIR/promote-not.rs:64:29
129138
|
130139
LL | let _val: &'static _ = &(i32::MIN/(0-1));
131140
| ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -136,7 +145,7 @@ LL | }
136145
| - temporary value is freed at the end of this statement
137146

138147
error[E0716]: temporary value dropped while borrowed
139-
--> $DIR/promote-not.rs:55:29
148+
--> $DIR/promote-not.rs:65:29
140149
|
141150
LL | let _val: &'static _ = &(-128i8/-1);
142151
| ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -147,7 +156,7 @@ LL | }
147156
| - temporary value is freed at the end of this statement
148157

149158
error[E0716]: temporary value dropped while borrowed
150-
--> $DIR/promote-not.rs:56:29
159+
--> $DIR/promote-not.rs:66:29
151160
|
152161
LL | let _val: &'static _ = &(1%0);
153162
| ---------- ^^^^^ creates a temporary value which is freed while still in use
@@ -158,7 +167,7 @@ LL | }
158167
| - temporary value is freed at the end of this statement
159168

160169
error[E0716]: temporary value dropped while borrowed
161-
--> $DIR/promote-not.rs:57:29
170+
--> $DIR/promote-not.rs:67:29
162171
|
163172
LL | let _val: &'static _ = &(1%(1-1));
164173
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -169,7 +178,7 @@ LL | }
169178
| - temporary value is freed at the end of this statement
170179

171180
error[E0716]: temporary value dropped while borrowed
172-
--> $DIR/promote-not.rs:58:29
181+
--> $DIR/promote-not.rs:68:29
173182
|
174183
LL | let _val: &'static _ = &([1,2,3][4]+1);
175184
| ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -180,7 +189,7 @@ LL | }
180189
| - temporary value is freed at the end of this statement
181190

182191
error[E0716]: temporary value dropped while borrowed
183-
--> $DIR/promote-not.rs:61:29
192+
--> $DIR/promote-not.rs:72:29
184193
|
185194
LL | let _val: &'static _ = &TEST_DROP;
186195
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -191,7 +200,7 @@ LL | }
191200
| - temporary value is freed at the end of this statement
192201

193202
error[E0716]: temporary value dropped while borrowed
194-
--> $DIR/promote-not.rs:63:29
203+
--> $DIR/promote-not.rs:74:29
195204
|
196205
LL | let _val: &'static _ = &&TEST_DROP;
197206
| ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -202,7 +211,7 @@ LL | }
202211
| - temporary value is freed at the end of this statement
203212

204213
error[E0716]: temporary value dropped while borrowed
205-
--> $DIR/promote-not.rs:63:30
214+
--> $DIR/promote-not.rs:74:30
206215
|
207216
LL | let _val: &'static _ = &&TEST_DROP;
208217
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -213,7 +222,7 @@ LL | }
213222
| - temporary value is freed at the end of this statement
214223

215224
error[E0716]: temporary value dropped while borrowed
216-
--> $DIR/promote-not.rs:66:29
225+
--> $DIR/promote-not.rs:77:29
217226
|
218227
LL | let _val: &'static _ = &(&TEST_DROP,);
219228
| ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -224,7 +233,7 @@ LL | }
224233
| - temporary value is freed at the end of this statement
225234

226235
error[E0716]: temporary value dropped while borrowed
227-
--> $DIR/promote-not.rs:66:31
236+
--> $DIR/promote-not.rs:77:31
228237
|
229238
LL | let _val: &'static _ = &(&TEST_DROP,);
230239
| ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -235,7 +244,7 @@ LL | }
235244
| - temporary value is freed at the end of this statement
236245

237246
error[E0716]: temporary value dropped while borrowed
238-
--> $DIR/promote-not.rs:69:29
247+
--> $DIR/promote-not.rs:80:29
239248
|
240249
LL | let _val: &'static _ = &[&TEST_DROP; 1];
241250
| ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -246,14 +255,26 @@ LL | }
246255
| - temporary value is freed at the end of this statement
247256

248257
error[E0716]: temporary value dropped while borrowed
249-
--> $DIR/promote-not.rs:69:31
258+
--> $DIR/promote-not.rs:80:31
250259
|
251260
LL | let _val: &'static _ = &[&TEST_DROP; 1];
252261
| ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement
253262
| | |
254263
| | creates a temporary value which is freed while still in use
255264
| type annotation requires that borrow lasts for `'static`
256265

257-
error: aborting due to 24 previous errors
266+
error[E0716]: temporary value dropped while borrowed
267+
--> $DIR/promote-not.rs:89:26
268+
|
269+
LL | let x: &'static _ = &UnionWithCell { f1: 0 };
270+
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
271+
| |
272+
| type annotation requires that borrow lasts for `'static`
273+
LL |
274+
LL | }
275+
| - temporary value is freed at the end of this statement
276+
277+
error: aborting due to 26 previous errors
258278

259-
For more information about this error, try `rustc --explain E0716`.
279+
Some errors have detailed explanations: E0493, E0716.
280+
For more information about an error, try `rustc --explain E0493`.

tests/ui/consts/refs-to-cell-in-final.rs

+23
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,27 @@ static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
1515
const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
1616
//~^ ERROR: cannot refer to interior mutable data
1717

18+
// This one does not get promoted because of `Drop`, and then enters interesting codepaths because
19+
// as a value it has no interior mutability, but as a type it does. See
20+
// <https://github.com/rust-lang/rust/issues/121610>. Value-based reasoning for interior mutability
21+
// is questionable (https://github.com/rust-lang/unsafe-code-guidelines/issues/493) so for now we
22+
// reject this, though not with a great error message.
23+
pub enum JsValue {
24+
Undefined,
25+
Object(Cell<bool>),
26+
}
27+
impl Drop for JsValue {
28+
fn drop(&mut self) {}
29+
}
30+
const UNDEFINED: &JsValue = &JsValue::Undefined;
31+
//~^ERROR: mutable pointer in final value of constant
32+
33+
// In contrast, this one works since it is being promoted.
34+
const NONE: &'static Option<Cell<i32>> = &None;
35+
// Making it clear that this is promotion, not "outer scope".
36+
const NONE_EXPLICIT_PROMOTED: &'static Option<Cell<i32>> = {
37+
let x = &None;
38+
x
39+
};
40+
1841
fn main() {}

tests/ui/consts/refs-to-cell-in-final.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ error[E0492]: constants cannot refer to interior mutable data
1212
LL | const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
1313
| ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value
1414

15-
error: aborting due to 2 previous errors
15+
error: encountered mutable pointer in final value of constant
16+
--> $DIR/refs-to-cell-in-final.rs:30:1
17+
|
18+
LL | const UNDEFINED: &JsValue = &JsValue::Undefined;
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 3 previous errors
1622

1723
For more information about this error, try `rustc --explain E0492`.

0 commit comments

Comments
 (0)