diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 8ee3a0cc96793..5e1f45f133412 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -412,10 +412,10 @@ pub fn const_validate_mplace<'mir, 'tcx>( _ if cid.promoted.is_some() => CtfeValidationMode::Promoted, Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` None => { - // In normal `const` (not promoted), the outermost allocation is always only copied, - // so having `UnsafeCell` in there is okay despite them being in immutable memory. - let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner; - CtfeValidationMode::Const { allow_immutable_unsafe_cell } + // This is a normal `const` (not promoted). + // The outermost allocation is always only copied, so having `UnsafeCell` in there + // is okay despite them being in immutable memory. + CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner } } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 53308cd7f901c..a93e8138aa412 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -30,7 +30,7 @@ type QualifResults<'mir, 'tcx, Q> = rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; #[derive(Default)] -pub struct Qualifs<'mir, 'tcx> { +pub(crate) struct Qualifs<'mir, 'tcx> { has_mut_interior: Option>, needs_drop: Option>, needs_non_const_drop: Option>, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 7eb3c181d6958..1847847d9d2ae 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -284,6 +284,7 @@ where if Q::in_adt_inherently(cx, def, args) { return true; } + // Don't do any value-based reasoning for unions. if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) { return true; } diff --git a/tests/ui/consts/enclosing-scope-rule.rs b/tests/ui/consts/enclosing-scope-rule.rs new file mode 100644 index 0000000000000..7041ad9af34e0 --- /dev/null +++ b/tests/ui/consts/enclosing-scope-rule.rs @@ -0,0 +1,16 @@ +//@build-pass +// Some code that looks like it might be relying on promotion, but actually this is using the +// enclosing-scope rule, meaning the reference is "extended" to outlive its block and live as long +// as the surrounding block (which in this case is the entire program). There are multiple +// allocations being interned at once. + +struct Gen(T); +impl<'a, T> Gen<&'a T> { + // Can't be promoted because `T` might not be `'static`. + const C: &'a [T] = &[]; +} + +// Can't be promoted because of `Drop`. +const V: &Vec = &Vec::new(); + +fn main() {} diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs index 47a06e8a72b71..9b16f32532a77 100644 --- a/tests/ui/consts/promote-not.rs +++ b/tests/ui/consts/promote-not.rs @@ -3,6 +3,7 @@ #![allow(unconditional_panic)] use std::cell::Cell; +use std::mem::ManuallyDrop; // We do not promote mutable references. 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: () = { let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed }; -const TEST_DROP: String = String::new(); +// This gets accepted by the "outer scope" rule, not promotion. +const TEST_DROP_OUTER_SCOPE: &String = &String::new(); +// To demonstrate that, we can rewrite it as follows. If this was promotion it would still work. +const TEST_DROP_NOT_PROMOTE: &String = { + let x = &String::new(); //~ ERROR destructor of `String` cannot be evaluated at compile-time + // The "dropped while borrowed" error seems to be suppressed, but the key point is that this + // fails to compile. + x +}; + fn main() { // We must not promote things with interior mutability. Not even if we "project it away". @@ -58,6 +68,7 @@ fn main() { let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed // No promotion of temporaries that need to be dropped. + const TEST_DROP: String = String::new(); let _val: &'static _ = &TEST_DROP; //~^ ERROR temporary value dropped while borrowed let _val: &'static _ = &&TEST_DROP; @@ -69,4 +80,12 @@ fn main() { let _val: &'static _ = &[&TEST_DROP; 1]; //~^ ERROR temporary value dropped while borrowed //~| ERROR temporary value dropped while borrowed + + // Make sure there is no value-based reasoning for unions. + union UnionWithCell { + f1: i32, + f2: ManuallyDrop>, + } + let x: &'static _ = &UnionWithCell { f1: 0 }; + //~^ ERROR temporary value dropped while borrowed } diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index 67ac5922efd96..07d4a135ed43d 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:8:50 + --> $DIR/promote-not.rs:9:50 | LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | ----------^^^^^^^^^- @@ -9,7 +9,7 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:11:18 + --> $DIR/promote-not.rs:12:18 | LL | let x = &mut [1,2,3]; | ^^^^^^^ creates a temporary value which is freed while still in use @@ -19,7 +19,7 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:33:29 + --> $DIR/promote-not.rs:34:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -29,7 +29,7 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:39:29 + --> $DIR/promote-not.rs:40:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -38,8 +38,17 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).1; LL | }; | - temporary value is freed at the end of this statement +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promote-not.rs:47:14 + | +LL | let x = &String::new(); + | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:20:32 + --> $DIR/promote-not.rs:21:32 | LL | let _x: &'static () = &foo(); | ----------- ^^^^^ creates a temporary value which is freed while still in use @@ -49,7 +58,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:28:29 + --> $DIR/promote-not.rs:29:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -59,7 +68,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:46:29 + --> $DIR/promote-not.rs:56:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -70,7 +79,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:47:29 + --> $DIR/promote-not.rs:57:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -81,7 +90,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:50:29 + --> $DIR/promote-not.rs:60:29 | LL | let _val: &'static _ = &(1/0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -92,7 +101,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:51:29 + --> $DIR/promote-not.rs:61:29 | LL | let _val: &'static _ = &(1/(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -103,7 +112,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:52:29 + --> $DIR/promote-not.rs:62:29 | LL | let _val: &'static _ = &((1+1)/(1-1)); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -114,7 +123,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:53:29 + --> $DIR/promote-not.rs:63:29 | LL | let _val: &'static _ = &(i32::MIN/-1); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -125,7 +134,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:54:29 + --> $DIR/promote-not.rs:64:29 | LL | let _val: &'static _ = &(i32::MIN/(0-1)); | ---------- ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -136,7 +145,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:55:29 + --> $DIR/promote-not.rs:65:29 | LL | let _val: &'static _ = &(-128i8/-1); | ---------- ^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -147,7 +156,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:56:29 + --> $DIR/promote-not.rs:66:29 | LL | let _val: &'static _ = &(1%0); | ---------- ^^^^^ creates a temporary value which is freed while still in use @@ -158,7 +167,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:57:29 + --> $DIR/promote-not.rs:67:29 | LL | let _val: &'static _ = &(1%(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -169,7 +178,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:58:29 + --> $DIR/promote-not.rs:68:29 | LL | let _val: &'static _ = &([1,2,3][4]+1); | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -180,7 +189,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:61:29 + --> $DIR/promote-not.rs:72:29 | LL | let _val: &'static _ = &TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -191,7 +200,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:63:29 + --> $DIR/promote-not.rs:74:29 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -202,7 +211,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:63:30 + --> $DIR/promote-not.rs:74:30 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -213,7 +222,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:66:29 + --> $DIR/promote-not.rs:77:29 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -224,7 +233,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:66:31 + --> $DIR/promote-not.rs:77:31 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -235,7 +244,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:69:29 + --> $DIR/promote-not.rs:80:29 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -246,7 +255,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:69:31 + --> $DIR/promote-not.rs:80:31 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement @@ -254,6 +263,18 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1]; | | creates a temporary value which is freed while still in use | type annotation requires that borrow lasts for `'static` -error: aborting due to 24 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:89:26 + | +LL | let x: &'static _ = &UnionWithCell { f1: 0 }; + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 26 previous errors -For more information about this error, try `rustc --explain E0716`. +Some errors have detailed explanations: E0493, E0716. +For more information about an error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/refs-to-cell-in-final.rs b/tests/ui/consts/refs-to-cell-in-final.rs index 6a849ff0df929..ada56a82a5d1f 100644 --- a/tests/ui/consts/refs-to-cell-in-final.rs +++ b/tests/ui/consts/refs-to-cell-in-final.rs @@ -15,4 +15,27 @@ static RAW_SYNC_S: SyncPtr> = SyncPtr { x: &Cell::new(42) }; const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; //~^ ERROR: cannot refer to interior mutable data +// This one does not get promoted because of `Drop`, and then enters interesting codepaths because +// as a value it has no interior mutability, but as a type it does. See +// . Value-based reasoning for interior mutability +// is questionable (https://github.com/rust-lang/unsafe-code-guidelines/issues/493) so for now we +// reject this, though not with a great error message. +pub enum JsValue { + Undefined, + Object(Cell), +} +impl Drop for JsValue { + fn drop(&mut self) {} +} +const UNDEFINED: &JsValue = &JsValue::Undefined; +//~^ERROR: mutable pointer in final value of constant + +// In contrast, this one works since it is being promoted. +const NONE: &'static Option> = &None; +// Making it clear that this is promotion, not "outer scope". +const NONE_EXPLICIT_PROMOTED: &'static Option> = { + let x = &None; + x +}; + fn main() {} diff --git a/tests/ui/consts/refs-to-cell-in-final.stderr b/tests/ui/consts/refs-to-cell-in-final.stderr index fae16fa01251c..b06db3e116ce1 100644 --- a/tests/ui/consts/refs-to-cell-in-final.stderr +++ b/tests/ui/consts/refs-to-cell-in-final.stderr @@ -12,6 +12,12 @@ error[E0492]: constants cannot refer to interior mutable data LL | const RAW_SYNC_C: SyncPtr> = SyncPtr { x: &Cell::new(42) }; | ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value -error: aborting due to 2 previous errors +error: encountered mutable pointer in final value of constant + --> $DIR/refs-to-cell-in-final.rs:30:1 + | +LL | const UNDEFINED: &JsValue = &JsValue::Undefined; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0492`.