diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index cf8a0fdb97e2..cfa315fe61ab 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -90,6 +90,7 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_macros::newtype_index; +use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; @@ -922,7 +923,11 @@ fn op_to_prop_const<'tcx>( let pointer = mplace.ptr().into_pointer_or_addr().ok()?; let (alloc_id, offset) = pointer.into_parts(); intern_const_alloc_for_constprop(ecx, alloc_id).ok()?; - return Some(ConstValue::Indirect { alloc_id, offset }); + if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) { + // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything + // by `GlobalAlloc::Memory`, so do fall through to copying if needed. + return Some(ConstValue::Indirect { alloc_id, offset }); + } } // Everything failed: create a new allocation to hold the data. diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff new file mode 100644 index 000000000000..f853942bbb66 --- /dev/null +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-abort.diff @@ -0,0 +1,19 @@ +- // MIR for `indirect_static` before GVN ++ // MIR for `indirect_static` after GVN + + fn indirect_static() -> () { + let mut _0: (); + let mut _1: &std::option::Option; + let mut _2: u8; + + bb0: { + _1 = const {ALLOC0: &Option}; + _2 = (((*_1) as variant#1).0: u8); + return; + } + } + + ALLOC0 (static: A, size: 2, align: 1) { + 00 __ │ .░ + } + diff --git a/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff new file mode 100644 index 000000000000..f853942bbb66 --- /dev/null +++ b/tests/mir-opt/gvn.indirect_static.GVN.panic-unwind.diff @@ -0,0 +1,19 @@ +- // MIR for `indirect_static` before GVN ++ // MIR for `indirect_static` after GVN + + fn indirect_static() -> () { + let mut _0: (); + let mut _1: &std::option::Option; + let mut _2: u8; + + bb0: { + _1 = const {ALLOC0: &Option}; + _2 = (((*_1) as variant#1).0: u8); + return; + } + } + + ALLOC0 (static: A, size: 2, align: 1) { + 00 __ │ .░ + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 7ce851905e06..10a66ced026e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -597,6 +597,18 @@ fn fn_pointers() { opaque(cg); } +/// Verify that we do not create a `ConstValue::Indirect` backed by a static's AllocId. +#[custom_mir(dialect = "analysis")] +fn indirect_static() { + static A: Option = None; + + mir!({ + let ptr = Static(A); + let out = Field::(Variant(*ptr, 1), 0); + Return() + }) +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -614,6 +626,7 @@ fn main() { assert_eq!(direct, indirect); repeat(); fn_pointers(); + indirect_static(); } #[inline(never)] @@ -639,3 +652,4 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.duplicate_slice.GVN.diff // EMIT_MIR gvn.repeat.GVN.diff // EMIT_MIR gvn.fn_pointers.GVN.diff +// EMIT_MIR gvn.indirect_static.GVN.diff