about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2022-07-25 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2022-07-25 14:14:49 +0200
commit5f40a4f7a0aa6552e615fe89a6018e36c93f672e (patch)
tree9b60a65fee4fb440a11b88cb7edeaa0836b5bfb9 /compiler/rustc_mir_transform/src
parent2f320a224e827b400be25966755a621779f797cc (diff)
downloadrust-5f40a4f7a0aa6552e615fe89a6018e36c93f672e.tar.gz
rust-5f40a4f7a0aa6552e615fe89a6018e36c93f672e.zip
Remove reachable coverage without counters
Remove reachable coverage without counters to maintain invariant that
either there is no coverage at all or there is a live coverage counter
left that provides the function source hash.

The motivating example would be a following closure:

```rust
    let f = |x: bool| {
        debug_assert!(x);
    };
```

Which, with span changes from #93967, with disabled debug assertions,
after the final CFG simplifications but before removal of dead blocks,
gives rise to MIR:

```rust
fn main::{closure#0}(_1: &[closure@a.rs:2:13: 2:22], _2: bool) -> () {
    debug x => _2;
    let mut _0: ();

    bb0: {
        Coverage::Expression(4294967295) = 1 - 2;
        return;
    }

    ...
}
```
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs12
1 files changed, 11 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d305960b485..180f4c7dcd6 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -315,7 +315,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 /// with `0` executions.
 ///
 /// If there are no live `Counter` `Coverage` statements remaining, we remove
-/// dead `Coverage` statements along with the dead blocks. Since at least one
+/// `Coverage` statements along with the dead blocks. Since at least one
 /// counter per function is required by LLVM (and necessary, to add the
 /// `function_hash` to the counter's call to the LLVM intrinsic
 /// `instrprof.increment()`).
@@ -342,6 +342,16 @@ fn save_unreachable_coverage(
         }
     }
 
+    for block in &mut basic_blocks.raw[..first_dead_block] {
+        for statement in &mut block.statements {
+            let StatementKind::Coverage(_) = &statement.kind else { continue };
+            let instance = statement.source_info.scope.inlined_instance(source_scopes);
+            if !live.contains(&instance) {
+                statement.make_nop();
+            }
+        }
+    }
+
     if live.is_empty() {
         return;
     }