Skip to content

Commit 5f40a4f

Browse files
committed
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 rust-lang#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: &[[email protected]:2:13: 2:22], _2: bool) -> () { debug x => _2; let mut _0: (); bb0: { Coverage::Expression(4294967295) = 1 - 2; return; } ... } ```
1 parent 2f320a2 commit 5f40a4f

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

compiler/rustc_mir_transform/src/simplify.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
315315
/// with `0` executions.
316316
///
317317
/// If there are no live `Counter` `Coverage` statements remaining, we remove
318-
/// dead `Coverage` statements along with the dead blocks. Since at least one
318+
/// `Coverage` statements along with the dead blocks. Since at least one
319319
/// counter per function is required by LLVM (and necessary, to add the
320320
/// `function_hash` to the counter's call to the LLVM intrinsic
321321
/// `instrprof.increment()`).
@@ -342,6 +342,16 @@ fn save_unreachable_coverage(
342342
}
343343
}
344344

345+
for block in &mut basic_blocks.raw[..first_dead_block] {
346+
for statement in &mut block.statements {
347+
let StatementKind::Coverage(_) = &statement.kind else { continue };
348+
let instance = statement.source_info.scope.inlined_instance(source_scopes);
349+
if !live.contains(&instance) {
350+
statement.make_nop();
351+
}
352+
}
353+
}
354+
345355
if live.is_empty() {
346356
return;
347357
}
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
1| |// Regression test for issue #98833.
2-
2| |// compile-flags: -Zinline-mir
2+
2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off
33
3| |
44
4| 1|fn main() {
55
5| 1| println!("{}", live::<false>());
6-
6| 1|}
7-
7| |
8-
8| |#[inline]
9-
9| 1|fn live<const B: bool>() -> u32 {
10-
10| 1| if B {
11-
11| 0| dead()
12-
12| | } else {
13-
13| 1| 0
14-
14| | }
15-
15| 1|}
16-
16| |
17-
17| |#[inline]
18-
18| 0|fn dead() -> u32 {
19-
19| 0| 42
20-
20| 0|}
6+
6| 1|
7+
7| 1| let f = |x: bool| {
8+
8| | debug_assert!(
9+
9| | x
10+
10| | );
11+
11| 1| };
12+
12| 1| f(false);
13+
13| 1|}
14+
14| |
15+
15| |#[inline]
16+
16| 1|fn live<const B: bool>() -> u32 {
17+
17| 1| if B {
18+
18| 0| dead()
19+
19| | } else {
20+
20| 1| 0
21+
21| | }
22+
22| 1|}
23+
23| |
24+
24| |#[inline]
25+
25| 0|fn dead() -> u32 {
26+
26| 0| 42
27+
27| 0|}
2128

src/test/run-make-fulldeps/coverage/inline-dead.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
// Regression test for issue #98833.
2-
// compile-flags: -Zinline-mir
2+
// compile-flags: -Zinline-mir -Cdebug-assertions=off
33

44
fn main() {
55
println!("{}", live::<false>());
6+
7+
let f = |x: bool| {
8+
debug_assert!(
9+
x
10+
);
11+
};
12+
f(false);
613
}
714

815
#[inline]

0 commit comments

Comments
 (0)