about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authordianqk <dianqk@dianqk.net>2025-07-19 18:49:47 +0800
committerdianqk <dianqk@dianqk.net>2025-10-02 14:58:59 +0800
commit8da04285cf6fe61587e16155a8b224dba64bf0be (patch)
tree4d4c98956c6bd938cd5ffe9bbfb7928a2f229a12 /compiler
parent1bd89bd42e0bb6f29b8af5d6bdf3f756196bb8ee (diff)
downloadrust-8da04285cf6fe61587e16155a8b224dba64bf0be.tar.gz
rust-8da04285cf6fe61587e16155a8b224dba64bf0be.zip
mir-opt: Eliminate dead statements even if they are used by debuginfos
Diffstat (limited to 'compiler')
-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
8 files changed, 66 insertions, 8 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 {