1
Fork 0

Auto merge of #124223 - Zalathar:conditional-let, r=compiler-errors

coverage: Branch coverage support for let-else and if-let

This PR adds branch coverage instrumentation for let-else and if-let, including let-chains.

This lifts two of the limitations listed at #124118.
This commit is contained in:
bors 2024-05-07 22:28:51 +00:00
commit 5486f0c1c2
6 changed files with 64 additions and 13 deletions

View file

@ -1,17 +1,18 @@
mod mcdc;
use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
use rustc_middle::thir::{ExprId, ExprKind, Thir};
use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::LocalDefId;
use crate::build::coverageinfo::mcdc::MCDCInfoBuilder;
use crate::build::{Builder, CFG};
mod mcdc;
pub(crate) struct BranchInfoBuilder {
/// Maps condition expressions to their enclosing `!`, for better instrumentation.
nots: FxHashMap<ExprId, NotInfo>,
@ -155,7 +156,7 @@ impl BranchInfoBuilder {
}
}
impl Builder<'_, '_> {
impl<'tcx> Builder<'_, 'tcx> {
/// If branch coverage is enabled, inject marker statements into `then_block`
/// and `else_block`, and record their IDs in the table of branch spans.
pub(crate) fn visit_coverage_branch_condition(
@ -195,4 +196,23 @@ impl Builder<'_, '_> {
branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
}
/// If branch coverage is enabled, inject marker statements into `true_block`
/// and `false_block`, and record their IDs in the table of branches.
///
/// Used to instrument let-else and if-let (including let-chains) for branch coverage.
pub(crate) fn visit_coverage_conditional_let(
&mut self,
pattern: &Pat<'tcx>, // Pattern that has been matched when the true path is taken
true_block: BasicBlock,
false_block: BasicBlock,
) {
// Bail out if branch coverage is not enabled for this function.
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
// FIXME(#124144) This may need special handling when MC/DC is enabled.
let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
}
}

View file

@ -2000,6 +2000,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
false,
);
// If branch coverage is enabled, record this branch.
self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block);
post_guard_block.unit()
}
@ -2492,6 +2495,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
true,
);
// If branch coverage is enabled, record this branch.
this.visit_coverage_conditional_let(pattern, matching, failure);
this.break_for_else(failure, this.source_info(initializer_span));
matching.unit()
});