Skip to content

Commit

Permalink
coverage: Make MCDC take in account last RHS of condition-coverage
Browse files Browse the repository at this point in the history
Condition coverage extends branch coverage to treat the specific case
of last operands of boolean decisions not involved in control flow.
This is ultimately made for MCDC to be exhaustive on all boolean expressions.

This patch adds a call to `visit_branch_coverage_operation` to track the
top-level operand of the said decisions, and changes
`visit_coverage_standalone_condition` so MCDC branch registration is called
when enabled on these _last RHS_ cases.
  • Loading branch information
RenjiSann committed Jun 19, 2024
1 parent acd6e4c commit 6c7c824
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 23 deletions.
68 changes: 45 additions & 23 deletions compiler/rustc_mir_build/src/build/coverageinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,35 @@ impl BranchInfoBuilder {
}
}

fn add_two_way_branch<'tcx>(
fn register_two_way_branch<'tcx>(
&mut self,
tcx: TyCtxt<'tcx>,
cfg: &mut CFG<'tcx>,
source_info: SourceInfo,
true_block: BasicBlock,
false_block: BasicBlock,
) {
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);

self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker });
// Separate path for handling branches when MC/DC is enabled.
if let Some(mcdc_info) = self.mcdc_info.as_mut() {
let inject_block_marker =
|source_info, block| self.markers.inject_block_marker(cfg, source_info, block);
mcdc_info.visit_evaluated_condition(
tcx,
source_info,
true_block,
false_block,
inject_block_marker,
);
} else {
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);

self.branch_spans.push(BranchSpan {
span: source_info.span,
true_marker,
false_marker,
});
}
}

pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
Expand Down Expand Up @@ -205,7 +223,14 @@ impl<'tcx> Builder<'_, 'tcx> {
mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block),
);

branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
// Separate path for handling branches when MC/DC is enabled.
branch_info.register_two_way_branch(
self.tcx,
&mut self.cfg,
source_info,
true_block,
false_block,
);

let join_block = self.cfg.start_new_block();
self.cfg.goto(true_block, source_info, join_block);
Expand Down Expand Up @@ -236,22 +261,13 @@ impl<'tcx> Builder<'_, 'tcx> {

let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };

// Separate path for handling branches when MC/DC is enabled.
if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() {
let inject_block_marker = |source_info, block| {
branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block)
};
mcdc_info.visit_evaluated_condition(
self.tcx,
source_info,
then_block,
else_block,
inject_block_marker,
);
return;
}

branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
branch_info.register_two_way_branch(
self.tcx,
&mut self.cfg,
source_info,
then_block,
else_block,
);
}

/// If branch coverage is enabled, inject marker statements into `true_block`
Expand All @@ -270,6 +286,12 @@ impl<'tcx> Builder<'_, 'tcx> {
// 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);
branch_info.register_two_way_branch(
self.tcx,
&mut self.cfg,
source_info,
true_block,
false_block,
);
}
}
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::LogicalOp { op, lhs, rhs } => {
let condition_scope = this.local_scope();
let source_info = this.source_info(expr.span);

this.visit_coverage_branch_operation(op, expr.span);

// We first evaluate the left-hand side of the predicate ...
let (then_block, else_block) =
this.in_if_then_scope(condition_scope, expr.span, |this| {
Expand Down

0 comments on commit 6c7c824

Please sign in to comment.