about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs3
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs15
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/debuginfo.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs3
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs16
-rw-r--r--compiler/rustc_mir_transform/src/strip_debuginfo.rs17
-rw-r--r--tests/codegen-llvm/debuginfo-dse.rs23
-rw-r--r--tests/mir-opt/dead-store-elimination/ref.rs4
-rw-r--r--tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff2
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff50
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff4
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir13
-rw-r--r--tests/mir-opt/pre-codegen/dead_on_invalid_place.rs27
-rw-r--r--tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir12
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir42
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir8
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir8
20 files changed, 170 insertions, 101 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 99bb31a68b6..80f4f0fcda1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -155,6 +155,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     self.debug_poison_to_local(bx, *dest);
                 }
             }
+            StmtDebugInfo::InvalidAssign(local) => {
+                self.debug_poison_to_local(bx, *local);
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 8cf89f778a2..d87e3abe3b2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -844,6 +844,9 @@ impl Debug for StmtDebugInfo<'_> {
             StmtDebugInfo::AssignRef(local, place) => {
                 write!(fmt, "{local:?} = &{place:?}")
             }
+            StmtDebugInfo::InvalidAssign(local) => {
+                write!(fmt, "{local:?} = &?")
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 67b4448cfcd..f310e1e5762 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -527,6 +527,20 @@ impl<'tcx> PlaceRef<'tcx> {
         })
     }
 
+    /// Return the place accessed locals that include the base local.
+    pub fn accessed_locals(self) -> impl Iterator<Item = Local> {
+        std::iter::once(self.local).chain(self.projection.iter().filter_map(|proj| match proj {
+            ProjectionElem::Index(local) => Some(*local),
+            ProjectionElem::Deref
+            | ProjectionElem::Field(_, _)
+            | ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Downcast(_, _)
+            | ProjectionElem::OpaqueCast(_)
+            | ProjectionElem::UnwrapUnsafeBinder(_) => None,
+        }))
+    }
+
     /// Generates a new place by appending `more_projections` to the existing ones
     /// and interning the result.
     pub fn project_deeper(
@@ -1057,4 +1071,5 @@ impl<'tcx> ops::DerefMut for StmtDebugInfos<'tcx> {
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum StmtDebugInfo<'tcx> {
     AssignRef(Local, Place<'tcx>),
+    InvalidAssign(Local),
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 47ae23afd55..9654e189f2e 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -406,6 +406,13 @@ macro_rules! make_mir_visitor {
                             location
                         );
                     },
+                    StmtDebugInfo::InvalidAssign(local) => {
+                        self.visit_local(
+                            $(& $mutability)? *local,
+                            PlaceContext::NonUse(NonUseContext::VarDebugInfo),
+                            location
+                        );
+                    }
                 }
             }
 
diff --git a/compiler/rustc_mir_dataflow/src/debuginfo.rs b/compiler/rustc_mir_dataflow/src/debuginfo.rs
index 274c5943946..0d25ce91c9a 100644
--- a/compiler/rustc_mir_dataflow/src/debuginfo.rs
+++ b/compiler/rustc_mir_dataflow/src/debuginfo.rs
@@ -5,16 +5,16 @@ use rustc_middle::mir::*;
 /// Return the set of locals that appear in debuginfo.
 pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet<Local> {
     let mut visitor = DebuginfoLocals(DenseBitSet::new_empty(body.local_decls.len()));
-    visitor.visit_body(body);
+    for debuginfo in body.var_debug_info.iter() {
+        visitor.visit_var_debug_info(debuginfo);
+    }
     visitor.0
 }
 
 struct DebuginfoLocals(DenseBitSet<Local>);
 
 impl Visitor<'_> for DebuginfoLocals {
-    fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) {
-        if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
-            self.0.insert(local);
-        }
+    fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) {
+        self.0.insert(local);
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 037e2720f36..f6aaa65ad9f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -287,9 +287,6 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         if let Some(destination) =
             Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals)
             && !state.contains(destination.local)
-            // FIXME: We can eliminate the statement, but we'll need the statements it depends on
-            // for debuginfos. We need a way to handle this.
-            && !self.debuginfo_locals.contains(destination.local)
         {
             // This store is dead
             return;
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 0f23482ea8b..8b5efb74205 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -657,6 +657,22 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
         self.tcx
     }
 
+    fn visit_statement_debuginfo(
+        &mut self,
+        stmt_debuginfo: &mut StmtDebugInfo<'tcx>,
+        location: Location,
+    ) {
+        match stmt_debuginfo {
+            StmtDebugInfo::AssignRef(local, place) => {
+                if place.as_ref().accessed_locals().any(|local| self.map[local].is_none()) {
+                    *stmt_debuginfo = StmtDebugInfo::InvalidAssign(*local);
+                }
+            }
+            StmtDebugInfo::InvalidAssign(_) => {}
+        }
+        self.super_statement_debuginfo(stmt_debuginfo, location);
+    }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
index 9ede8aa79c4..7fec25ccb52 100644
--- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
@@ -1,5 +1,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::debuginfo::debuginfo_locals;
 use rustc_session::config::MirStripDebugInfo;
 
 /// Conditionally remove some of the VarDebugInfo in MIR.
@@ -30,6 +31,22 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
                     if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE,
             )
         });
+
+        let debuginfo_locals = debuginfo_locals(body);
+        for data in body.basic_blocks.as_mut_preserves_cfg() {
+            for stmt in data.statements.iter_mut() {
+                stmt.debuginfos.retain(|debuginfo| match debuginfo {
+                    StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => {
+                        debuginfo_locals.contains(*local)
+                    }
+                });
+            }
+            data.after_last_stmt_debuginfos.retain(|debuginfo| match debuginfo {
+                StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => {
+                    debuginfo_locals.contains(*local)
+                }
+            });
+        }
     }
 
     fn is_required(&self) -> bool {
diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs
index 1fcb5fcfc54..78e145a3cdf 100644
--- a/tests/codegen-llvm/debuginfo-dse.rs
+++ b/tests/codegen-llvm/debuginfo-dse.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir
+//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled
 //@ revisions: CODEGEN OPTIMIZED
 //@[CODEGEN] compile-flags: -Cno-prepopulate-passes
 // ignore-tidy-linelength
@@ -9,6 +9,13 @@
 #[derive(Clone, Copy)]
 pub struct Foo(i32, i64, i32);
 
+#[repr(C)]
+pub struct Bar<'a> {
+    a: i32,
+    b: i64,
+    foo: &'a Foo,
+}
+
 #[no_mangle]
 fn r#ref(ref_foo: &Foo) -> i32 {
     // CHECK-LABEL: define{{.*}} i32 @ref
@@ -79,10 +86,19 @@ pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo {
 }
 
 #[no_mangle]
+pub fn deref(bar: Bar) -> i32 {
+    // CHECK-LABEL: define {{.*}} i32 @deref
+    // We are unable to represent dereference within this expression.
+    // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression()
+    let deref_dead = &bar.foo.2;
+    bar.a
+}
+
+#[no_mangle]
 pub fn tuple(foo: (i32, &Foo)) -> i32 {
     // CHECK-LABEL: define{{.*}} i32 @tuple
-    // CHECK-SAME: (i32 {{.*}}, ptr {{.*}} [[ARG_tuple_foo_1:%.*]])
-    // CHECK: #dbg_value(ptr [[ARG_tuple_foo_1]], [[VAR_tuple_dead:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value)
+    // Although there is no dereference here, there is a dereference in the MIR.
+    // CHECK: #dbg_value(ptr poison, [[VAR_tuple_dead:![0-9]+]], !DIExpression()
     let tuple_dead = &foo.1.2;
     foo.1.0
 }
@@ -148,6 +164,7 @@ pub fn non_arg_ref(scalar: i32, foo: Foo, a: &i32) -> i32 {
 // CHECK-DAG: [[VAR_ptr_v2]] = !DILocalVariable(name: "ptr_v2"
 // CODEGEN-DAG: [[VAR_val_ref]] = !DILocalVariable(name: "val_ref"
 // CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f"
+// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead"
 // CHECK-DAG: [[VAR_tuple_dead]] = !DILocalVariable(name: "tuple_dead"
 // CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo"
 // CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0"
diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs
index 18d9ea8b84d..2d3200edab9 100644
--- a/tests/mir-opt/dead-store-elimination/ref.rs
+++ b/tests/mir-opt/dead-store-elimination/ref.rs
@@ -11,9 +11,7 @@ pub fn tuple(v: (i32, &Foo)) -> i32 {
     // CHECK-LABEL: fn tuple
     // CHECK: debug _dead => [[dead:_[0-9]+]];
     // CHECK: bb0:
-    // FIXME: Preserve `tmp` for debuginfo, but we can merge it into the debuginfo.
-    // CHECK: [[tmp:_[0-9]+]] = deref_copy (_1.1: &Foo);
-    // CHECK-NEXT: DBG: [[dead]] = &((*[[tmp]]).2: i32)
+    // CHECK: DBG: [[dead]] = &((*_3).2: i32)
     let _dead = &v.1.c;
     v.1.a
 }
diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff
index af28c1b9aa8..0b96569cbe4 100644
--- a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff
+++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff
@@ -13,7 +13,7 @@
   
       bb0: {
 -         StorageLive(_2);
-          _3 = deref_copy (_1.1: &Foo);
+-         _3 = deref_copy (_1.1: &Foo);
 -         _2 = &((*_3).2: i32);
 +         // DBG: _2 = &((*_3).2: i32);
           _4 = deref_copy (_1.1: &Foo);
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index 7fa22524f00..9509739413b 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -16,12 +16,10 @@
 +             let mut _9: *mut A;
 +             let mut _10: usize;
 +             scope 3 (inlined Vec::<A>::as_mut_ptr) {
-+                 let mut _11: &alloc::raw_vec::RawVec<A>;
 +                 scope 4 (inlined alloc::raw_vec::RawVec::<A>::ptr) {
-+                     let mut _12: &alloc::raw_vec::RawVecInner;
 +                     scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<A>) {
 +                         scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<A>) {
-+                             let mut _13: std::ptr::NonNull<u8>;
++                             let mut _11: std::ptr::NonNull<u8>;
 +                             scope 7 (inlined Unique::<u8>::cast::<A>) {
 +                                 scope 8 (inlined NonNull::<u8>::cast::<A>) {
 +                                     scope 9 (inlined NonNull::<u8>::as_ptr) {
@@ -41,15 +39,15 @@
 +                 }
 +             }
 +             scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) {
-+                 let mut _14: usize;
-+                 let mut _15: *mut A;
-+                 let mut _16: bool;
++                 let mut _12: usize;
++                 let mut _13: *mut A;
++                 let mut _14: bool;
 +             }
 +         }
 +     }
 +     scope 15 (inlined drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+         let mut _17: isize;
-+         let mut _18: isize;
++         let mut _15: isize;
++         let mut _16: isize;
 +     }
   
       bb0: {
@@ -64,20 +62,16 @@
 +         StorageLive(_8);
 +         StorageLive(_9);
 +         StorageLive(_11);
-+         StorageLive(_12);
-+         StorageLive(_13);
-+         _13 = copy (((((*_6).0: alloc::raw_vec::RawVec<A>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
-+         _9 = copy _13 as *mut A (Transmute);
-+         StorageDead(_13);
-+         StorageDead(_12);
++         _11 = copy (((((*_6).0: alloc::raw_vec::RawVec<A>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
++         _9 = copy _11 as *mut A (Transmute);
 +         StorageDead(_11);
 +         _10 = copy ((*_6).1: usize);
 +         _8 = *mut [A] from (copy _9, copy _10);
 +         StorageDead(_9);
++         StorageLive(_12);
++         StorageLive(_13);
 +         StorageLive(_14);
-+         StorageLive(_15);
-+         StorageLive(_16);
-+         _14 = const 0_usize;
++         _12 = const 0_usize;
 +         goto -> bb4;
       }
   
@@ -89,33 +83,33 @@
           StorageLive(_5);
           _5 = copy _2;
 -         _0 = drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind unreachable];
-+         StorageLive(_17);
-+         _17 = discriminant((*_5));
-+         switchInt(move _17) -> [0: bb5, otherwise: bb6];
++         StorageLive(_15);
++         _15 = discriminant((*_5));
++         switchInt(move _15) -> [0: bb5, otherwise: bb6];
       }
   
       bb2: {
-+         StorageDead(_16);
-+         StorageDead(_15);
 +         StorageDead(_14);
++         StorageDead(_13);
++         StorageDead(_12);
 +         StorageDead(_8);
 +         StorageDead(_10);
 +         drop(((*_4).0: alloc::raw_vec::RawVec<A>)) -> [return: bb1, unwind unreachable];
 +     }
 + 
 +     bb3: {
-+         _15 = &raw mut (*_8)[_14];
-+         _14 = Add(move _14, const 1_usize);
-+         drop((*_15)) -> [return: bb4, unwind unreachable];
++         _13 = &raw mut (*_8)[_12];
++         _12 = Add(move _12, const 1_usize);
++         drop((*_13)) -> [return: bb4, unwind unreachable];
 +     }
 + 
 +     bb4: {
-+         _16 = Eq(copy _14, copy _10);
-+         switchInt(move _16) -> [0: bb3, otherwise: bb2];
++         _14 = Eq(copy _12, copy _10);
++         switchInt(move _14) -> [0: bb3, otherwise: bb2];
 +     }
 + 
 +     bb5: {
-+         StorageDead(_17);
++         StorageDead(_15);
           StorageDead(_5);
           return;
 +     }
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
index bb81cb4e260..0acb33febe5 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -220,16 +220,12 @@
 +         StorageLive(_49);
 +         StorageLive(_41);
 +         StorageLive(_42);
-+         StorageLive(_43);
-+         StorageLive(_46);
 +         _44 = copy (_19.0: &mut std::future::Ready<()>);
-+         StorageDead(_46);
 +         StorageLive(_47);
 +         _47 = Option::<()>::None;
 +         _42 = copy ((*_44).0: std::option::Option<()>);
 +         ((*_44).0: std::option::Option<()>) = copy _47;
 +         StorageDead(_47);
-+         StorageDead(_43);
 +         StorageLive(_48);
 +         _48 = discriminant(_42);
 +         switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5];
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
index 520c54824e1..98ee46c29b1 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -237,16 +237,12 @@
 +         StorageLive(_51);
 +         StorageLive(_43);
 +         StorageLive(_44);
-+         StorageLive(_45);
-+         StorageLive(_48);
 +         _46 = copy (_19.0: &mut std::future::Ready<()>);
-+         StorageDead(_48);
 +         StorageLive(_49);
 +         _49 = Option::<()>::None;
 +         _44 = copy ((*_46).0: std::option::Option<()>);
 +         ((*_46).0: std::option::Option<()>) = copy _49;
 +         StorageDead(_49);
-+         StorageDead(_45);
 +         StorageLive(_50);
 +         _50 = discriminant(_44);
 +         switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7];
diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir
new file mode 100644
index 00000000000..4a2127178fb
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir
@@ -0,0 +1,13 @@
+// MIR for `invalid_place` after PreCodegen
+
+fn invalid_place(_1: bool) -> bool {
+    debug c1_ref => _2;
+    let mut _0: bool;
+    let mut _2: &bool;
+
+    bb0: {
+        // DBG: _2 = &?;
+        _0 = copy _1;
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs
new file mode 100644
index 00000000000..5abe9fa43a5
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs
@@ -0,0 +1,27 @@
+#![feature(core_intrinsics, custom_mir)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+// EMIT_MIR dead_on_invalid_place.invalid_place.PreCodegen.after.mir
+#[custom_mir(dialect = "runtime")]
+pub fn invalid_place(c: bool) -> bool {
+    // CHECK-LABEL: fn invalid_place
+    // CHECK: debug c1_ref => [[c1_ref:_[0-9]+]];
+    // CHECK: bb0: {
+    // We cannot read the reference, since `c1` is dead.
+    // CHECK-NEXT: DBG: [[c1_ref]] = &?
+    // CHECK-NEXT: _0 = copy _1;
+    // CHECK-NEXT: return;
+    mir! {
+        let _c1_ref: &bool;
+        let c1: bool;
+        debug c1_ref => _c1_ref;
+        {
+            c1 = c;
+            _c1_ref = &c1;
+            RET = c;
+            Return()
+        }
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
index f453741dc6c..66eb1bcfaa6 100644
--- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
@@ -56,11 +56,11 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
                             scope 40 (inlined alloc::raw_vec::RawVec::<impl Sized>::capacity) {
                                 debug self => _37;
                                 let mut _19: usize;
-                                let mut _42: &alloc::raw_vec::RawVecInner;
+                                let mut _39: &alloc::raw_vec::RawVecInner;
                                 scope 41 (inlined std::mem::size_of::<impl Sized>) {
                                 }
                                 scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) {
-                                    debug self => _42;
+                                    debug self => _39;
                                     debug elem_size => _19;
                                     let mut _21: core::num::niche_types::UsizeNoHighBit;
                                     scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) {
@@ -130,7 +130,6 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
                 }
                 scope 18 (inlined alloc::raw_vec::RawVec::<impl Sized>::non_null) {
                     debug self => _31;
-                    let mut _41: &alloc::raw_vec::RawVecInner;
                     scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::<impl Sized>) {
                         let mut _4: std::ptr::NonNull<u8>;
                         scope 20 (inlined Unique::<u8>::cast::<impl Sized>) {
@@ -150,9 +149,7 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
             }
             scope 12 (inlined Vec::<impl Sized>::allocator) {
                 debug self => _29;
-                let mut _39: &alloc::raw_vec::RawVec<impl Sized>;
                 scope 13 (inlined alloc::raw_vec::RawVec::<impl Sized>::allocator) {
-                    let mut _40: &alloc::raw_vec::RawVecInner;
                     scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) {
                     }
                 }
@@ -183,13 +180,10 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
         StorageLive(_3);
         // DBG: _30 = &_2;
         // DBG: _29 = &(_2.0: std::vec::Vec<impl Sized>);
-        // DBG: _39 = &((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>);
-        // DBG: _40 = &(((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner);
         _3 = &raw const ((((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global);
         StorageDead(_3);
         // DBG: _32 = &_2;
         // DBG: _31 = &((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>);
-        // DBG: _41 = &(((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner);
         _4 = copy (((((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
         _5 = copy _4 as *const impl Sized (Transmute);
         _6 = NonNull::<impl Sized> { pointer: copy _5 };
@@ -247,7 +241,7 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
     bb4: {
         // DBG: _38 = &_2;
         // DBG: _37 = &((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>);
-        // DBG: _42 = &(((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner);
+        // DBG: _39 = &(((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner);
         StorageLive(_19);
         _19 = SizeOf(impl Sized);
         switchInt(move _19) -> [0: bb5, otherwise: bb6];
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index 86c729b3e95..2cab8818296 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -71,21 +71,17 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
         // DBG: _16 = &((*_3).3: usize);
         StorageLive(_6);
         // DBG: _17 = &_13;
-        // DBG: _18 = &_15;
+        // DBG: _18 = &?;
         _4 = copy ((*_3).0: usize);
         _5 = copy ((*_3).2: usize);
         _6 = Le(copy _4, copy _5);
-        switchInt(move _6) -> [0: bb1, otherwise: bb2];
+        switchInt(move _6) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
-        goto -> bb4;
-    }
-
-    bb2: {
         StorageLive(_9);
         // DBG: _19 = &_16;
-        // DBG: _20 = &_14;
+        // DBG: _20 = &?;
         StorageLive(_7);
         _7 = copy ((*_3).3: usize);
         StorageLive(_8);
@@ -93,29 +89,25 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
         _9 = Le(move _7, move _8);
         StorageDead(_8);
         StorageDead(_7);
-        switchInt(move _9) -> [0: bb3, otherwise: bb8];
-    }
-
-    bb3: {
-        goto -> bb4;
+        switchInt(move _9) -> [0: bb2, otherwise: bb6];
     }
 
-    bb4: {
+    bb2: {
         StorageLive(_10);
         // DBG: _21 = &_15;
-        // DBG: _22 = &_13;
+        // DBG: _22 = &?;
         _10 = Le(copy _5, copy _4);
-        switchInt(move _10) -> [0: bb5, otherwise: bb6];
+        switchInt(move _10) -> [0: bb3, otherwise: bb4];
     }
 
-    bb5: {
+    bb3: {
         _0 = const false;
-        goto -> bb7;
+        goto -> bb5;
     }
 
-    bb6: {
+    bb4: {
         // DBG: _23 = &_14;
-        // DBG: _24 = &_16;
+        // DBG: _24 = &?;
         StorageLive(_11);
         _11 = copy ((*_3).1: usize);
         StorageLive(_12);
@@ -123,20 +115,20 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
         _0 = Le(move _11, move _12);
         StorageDead(_12);
         StorageDead(_11);
-        goto -> bb7;
+        goto -> bb5;
     }
 
-    bb7: {
+    bb5: {
         StorageDead(_10);
-        goto -> bb9;
+        goto -> bb7;
     }
 
-    bb8: {
+    bb6: {
         _0 = const true;
-        goto -> bb9;
+        goto -> bb7;
     }
 
-    bb9: {
+    bb7: {
         StorageDead(_9);
         StorageDead(_6);
         return;
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
index eebd4a7eb50..2eee8a97db0 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
@@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
             let mut _4: usize;
             scope 3 (inlined Vec::<u8>::as_ptr) {
                 debug self => _1;
-                let mut _6: &alloc::raw_vec::RawVec<u8>;
                 scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
-                    let mut _7: &alloc::raw_vec::RawVecInner;
                     scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
                         scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
                             let mut _2: std::ptr::NonNull<u8>;
@@ -57,14 +55,8 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
     bb0: {
         StorageLive(_2);
         StorageLive(_3);
-        StorageLive(_6);
-        // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
-        StorageLive(_7);
-        // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner);
         _2 = copy (((((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
-        StorageDead(_7);
         _3 = copy _2 as *const u8 (Transmute);
-        StorageDead(_6);
         StorageLive(_4);
         _4 = copy ((*_1).1: usize);
         StorageLive(_5);
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
index eebd4a7eb50..2eee8a97db0 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
@@ -11,9 +11,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
             let mut _4: usize;
             scope 3 (inlined Vec::<u8>::as_ptr) {
                 debug self => _1;
-                let mut _6: &alloc::raw_vec::RawVec<u8>;
                 scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
-                    let mut _7: &alloc::raw_vec::RawVecInner;
                     scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
                         scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
                             let mut _2: std::ptr::NonNull<u8>;
@@ -57,14 +55,8 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
     bb0: {
         StorageLive(_2);
         StorageLive(_3);
-        StorageLive(_6);
-        // DBG: _6 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
-        StorageLive(_7);
-        // DBG: _7 = &(((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner);
         _2 = copy (((((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
-        StorageDead(_7);
         _3 = copy _2 as *const u8 (Transmute);
-        StorageDead(_6);
         StorageLive(_4);
         _4 = copy ((*_1).1: usize);
         StorageLive(_5);