about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKyle Huey <khuey@kylehuey.com>2024-08-03 21:23:35 -0700
committerKyle Huey <khuey@kylehuey.com>2024-08-03 21:23:35 -0700
commit709406fc6c792bd5dd0d07fbc59c4437b3d47f95 (patch)
treed3fb71f143025348749b9eef0c62c4baf05e8951
parenta6043039ad3aef48e08d72a3e32545accdee427a (diff)
downloadrust-709406fc6c792bd5dd0d07fbc59c4437b3d47f95.tar.gz
rust-709406fc6c792bd5dd0d07fbc59c4437b3d47f95.zip
When deduplicating unreachable blocks, erase the source information.
After deduplication the block conceptually belongs to multiple locations
in the source. Although these blocks are unreachable, in #123341 we did
come across a real side effect, an unreachable block that survives into
the compiled code can cause a debugger to set a breakpoint on the wrong
instruction. Erasing the source information ensures that a debugger will
never be misled into thinking that the unreachable block is worth setting
a breakpoint on, especially after #128627.

Technically we don't need to erase the source information if all the
deduplicated blocks have identical source information, but tracking
that seems like more effort than it's worth.
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs11
1 files changed, 11 insertions, 0 deletions
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 5bbe3bb747f..4fe8cf6213f 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -31,6 +31,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_span::DUMMY_SP;
 use smallvec::SmallVec;
 
 pub enum SimplifyCfg {
@@ -318,6 +319,7 @@ pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) {
     let mut orig_index = 0;
     let mut used_index = 0;
     let mut kept_unreachable = None;
+    let mut deduplicated_unreachable = false;
     basic_blocks.raw.retain(|bbdata| {
         let orig_bb = BasicBlock::new(orig_index);
         if !reachable.contains(orig_bb) {
@@ -330,6 +332,7 @@ pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) {
             let kept_unreachable = *kept_unreachable.get_or_insert(used_bb);
             if kept_unreachable != used_bb {
                 replacements[orig_index] = kept_unreachable;
+                deduplicated_unreachable = true;
                 orig_index += 1;
                 return false;
             }
@@ -341,6 +344,14 @@ pub(crate) fn remove_dead_blocks(body: &mut Body<'_>) {
         true
     });
 
+    // If we deduplicated unreachable blocks we erase their source_info as we
+    // can no longer attribute their code to a particular location in the
+    // source.
+    if deduplicated_unreachable {
+        basic_blocks[kept_unreachable.unwrap()].terminator_mut().source_info =
+            SourceInfo { span: DUMMY_SP, scope: OUTERMOST_SOURCE_SCOPE };
+    }
+
     for block in basic_blocks {
         for target in block.terminator_mut().successors_mut() {
             *target = replacements[target.index()];