Skip to content

Commit e5f83d2

Browse files
committed
Auto merge of #84797 - richkadel:cover-unreachable-statements, r=tmandry
Report coverage `0` of dead blocks Fixes: #84018 With `-Z instrument-coverage`, coverage reporting of dead blocks (for example, blocks dropped because a conditional branch is dropped, based on const evaluation) is now supported. If `instrument-coverage` is enabled, `simplify::remove_dead_blocks()` finds all dropped coverage `Statement`s and adds their `code_region`s as `Unreachable` coverage `Statement`s to the `START_BLOCK`, so they are still included in the coverage map. Check out the resulting changes in the test coverage reports in this PR (in [commit 1](0b0d293)). r? `@tmandry` cc: `@wesleywiser`
2 parents ac888e8 + 0b0d293 commit e5f83d2

21 files changed

+102
-65
lines changed

compiler/rustc_mir/src/transform/const_goto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto {
4747
// if we applied optimizations, we potentially have some cfg to cleanup to
4848
// make it easier for further passes
4949
if should_simplify {
50-
simplify_cfg(body);
50+
simplify_cfg(tcx, body);
5151
simplify_locals(body, tcx);
5252
}
5353
}

compiler/rustc_mir/src/transform/deduplicate_blocks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
2626
if has_opts_to_apply {
2727
let mut opt_applier = OptApplier { tcx, duplicates };
2828
opt_applier.visit_body(body);
29-
simplify_cfg(body);
29+
simplify_cfg(tcx, body);
3030
}
3131
}
3232
}

compiler/rustc_mir/src/transform/early_otherwise_branch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
164164
// Since this optimization adds new basic blocks and invalidates others,
165165
// clean up the cfg to make it nicer for other passes
166166
if should_cleanup {
167-
simplify_cfg(body);
167+
simplify_cfg(tcx, body);
168168
}
169169
}
170170
}

compiler/rustc_mir/src/transform/generator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>(
964964

965965
// Make sure we remove dead blocks to remove
966966
// unrelated code from the resume part of the function
967-
simplify::remove_dead_blocks(&mut body);
967+
simplify::remove_dead_blocks(tcx, &mut body);
968968

969969
dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
970970

@@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>(
11371137

11381138
// Make sure we remove dead blocks to remove
11391139
// unrelated code from the drop part of the function
1140-
simplify::remove_dead_blocks(body);
1140+
simplify::remove_dead_blocks(tcx, body);
11411141

11421142
dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
11431143
}

compiler/rustc_mir/src/transform/inline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline {
5757
if inline(tcx, body) {
5858
debug!("running simplify cfg on {:?}", body.source);
5959
CfgSimplifier::new(body).simplify();
60-
remove_dead_blocks(body);
60+
remove_dead_blocks(tcx, body);
6161
}
6262
}
6363
}

compiler/rustc_mir/src/transform/match_branches.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
167167
}
168168

169169
if should_cleanup {
170-
simplify_cfg(body);
170+
simplify_cfg(tcx, body);
171171
}
172172
}
173173
}

compiler/rustc_mir/src/transform/multiple_return_terminators.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
3838
}
3939
}
4040

41-
simplify::remove_dead_blocks(body)
41+
simplify::remove_dead_blocks(tcx, body)
4242
}
4343
}

compiler/rustc_mir/src/transform/remove_unneeded_drops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
3636
// if we applied optimizations, we potentially have some cfg to cleanup to
3737
// make it easier for further passes
3838
if should_simplify {
39-
simplify_cfg(body);
39+
simplify_cfg(tcx, body);
4040
}
4141
}
4242
}

compiler/rustc_mir/src/transform/simplify.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
3030
use crate::transform::MirPass;
3131
use rustc_index::vec::{Idx, IndexVec};
32+
use rustc_middle::mir::coverage::*;
3233
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
3334
use rustc_middle::mir::*;
3435
use rustc_middle::ty::TyCtxt;
@@ -46,9 +47,9 @@ impl SimplifyCfg {
4647
}
4748
}
4849

49-
pub fn simplify_cfg(body: &mut Body<'_>) {
50+
pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
5051
CfgSimplifier::new(body).simplify();
51-
remove_dead_blocks(body);
52+
remove_dead_blocks(tcx, body);
5253

5354
// FIXME: Should probably be moved into some kind of pass manager
5455
body.basic_blocks_mut().raw.shrink_to_fit();
@@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
5960
Cow::Borrowed(&self.label)
6061
}
6162

62-
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
63+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
6364
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
64-
simplify_cfg(body);
65+
simplify_cfg(tcx, body);
6566
}
6667
}
6768

@@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
286287
}
287288
}
288289

289-
pub fn remove_dead_blocks(body: &mut Body<'_>) {
290+
pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
290291
let reachable = traversal::reachable_as_bitset(body);
291292
let num_blocks = body.basic_blocks().len();
292293
if num_blocks == reachable.count() {
@@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
306307
}
307308
used_blocks += 1;
308309
}
310+
311+
if tcx.sess.instrument_coverage() {
312+
save_unreachable_coverage(basic_blocks, used_blocks);
313+
}
314+
309315
basic_blocks.raw.truncate(used_blocks);
310316

311317
for block in basic_blocks {
@@ -315,6 +321,32 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
315321
}
316322
}
317323

324+
fn save_unreachable_coverage(
325+
basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
326+
first_dead_block: usize,
327+
) {
328+
// retain coverage info for dead blocks, so coverage reports will still
329+
// report `0` executions for the uncovered code regions.
330+
let mut dropped_coverage = Vec::new();
331+
for dead_block in first_dead_block..basic_blocks.len() {
332+
for statement in basic_blocks[BasicBlock::new(dead_block)].statements.iter() {
333+
if let StatementKind::Coverage(coverage) = &statement.kind {
334+
if let Some(code_region) = &coverage.code_region {
335+
dropped_coverage.push((statement.source_info, code_region.clone()));
336+
}
337+
}
338+
}
339+
}
340+
for (source_info, code_region) in dropped_coverage {
341+
basic_blocks[START_BLOCK].statements.push(Statement {
342+
source_info,
343+
kind: StatementKind::Coverage(box Coverage {
344+
kind: CoverageKind::Unreachable,
345+
code_region: Some(code_region),
346+
}),
347+
})
348+
}
349+
}
318350
pub struct SimplifyLocals;
319351

320352
impl<'tcx> MirPass<'tcx> for SimplifyLocals {

compiler/rustc_mir/src/transform/simplify_try.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
558558

559559
if did_remove_blocks {
560560
// We have dead blocks now, so remove those.
561-
simplify::remove_dead_blocks(body);
561+
simplify::remove_dead_blocks(tcx, body);
562562
}
563563
}
564564
}

0 commit comments

Comments
 (0)