Skip to content

Commit edaee7f

Browse files
committed
coverage: Detach MC/DC branch spans from regular branch spans
MC/DC's reliance on the existing branch coverage types is making it much harder to improve branch coverage.
1 parent ed86d89 commit edaee7f

File tree

6 files changed

+101
-52
lines changed

6 files changed

+101
-52
lines changed

compiler/rustc_middle/src/mir/coverage.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ impl Default for ConditionInfo {
314314
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
315315
pub struct MCDCBranchSpan {
316316
pub span: Span,
317-
pub condition_info: ConditionInfo,
317+
/// If `None`, this actually represents a normal branch span inserted for
318+
/// code that was too complex for MC/DC.
319+
pub condition_info: Option<ConditionInfo>,
318320
pub true_marker: BlockMarkerId,
319321
pub false_marker: BlockMarkerId,
320322
}

compiler/rustc_middle/src/mir/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ fn write_coverage_branch_info(
491491
writeln!(
492492
w,
493493
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
494-
condition_info.condition_id
494+
condition_info.map(|info| info.condition_id)
495495
)?;
496496
}
497497

compiler/rustc_mir_build/src/build/coverageinfo.rs

+20-27
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub(crate) struct BranchInfoBuilder {
2222

2323
num_block_markers: usize,
2424
branch_spans: Vec<BranchSpan>,
25+
2526
mcdc_branch_spans: Vec<MCDCBranchSpan>,
2627
mcdc_decision_spans: Vec<MCDCDecisionSpan>,
2728
mcdc_state: Option<MCDCState>,
@@ -95,13 +96,7 @@ impl BranchInfoBuilder {
9596
}
9697
}
9798

98-
fn record_conditions_operation(&mut self, logical_op: LogicalOp, span: Span) {
99-
if let Some(mcdc_state) = self.mcdc_state.as_mut() {
100-
mcdc_state.record_conditions(logical_op, span);
101-
}
102-
}
103-
104-
fn fetch_condition_info(
99+
fn fetch_mcdc_condition_info(
105100
&mut self,
106101
tcx: TyCtxt<'_>,
107102
true_marker: BlockMarkerId,
@@ -121,14 +116,9 @@ impl BranchInfoBuilder {
121116
_ => {
122117
// Do not generate mcdc mappings and statements for decisions with too many conditions.
123118
let rebase_idx = self.mcdc_branch_spans.len() - decision.conditions_num + 1;
124-
let to_normal_branches = self.mcdc_branch_spans.split_off(rebase_idx);
125-
self.branch_spans.extend(to_normal_branches.into_iter().map(
126-
|MCDCBranchSpan { span, true_marker, false_marker, .. }| BranchSpan {
127-
span,
128-
true_marker,
129-
false_marker,
130-
},
131-
));
119+
for branch in &mut self.mcdc_branch_spans[rebase_idx..] {
120+
branch.condition_info = None;
121+
}
132122

133123
// ConditionInfo of this branch shall also be reset.
134124
condition_info = None;
@@ -157,7 +147,7 @@ impl BranchInfoBuilder {
157147
branch_spans,
158148
mcdc_branch_spans,
159149
mcdc_decision_spans,
160-
..
150+
mcdc_state: _,
161151
} = self;
162152

163153
if num_block_markers == 0 {
@@ -355,27 +345,30 @@ impl Builder<'_, '_> {
355345
let true_marker = inject_branch_marker(then_block);
356346
let false_marker = inject_branch_marker(else_block);
357347

358-
if let Some(condition_info) =
359-
branch_info.fetch_condition_info(self.tcx, true_marker, false_marker)
360-
{
348+
if branch_info.mcdc_state.is_some() {
349+
let condition_info =
350+
branch_info.fetch_mcdc_condition_info(self.tcx, true_marker, false_marker);
361351
branch_info.mcdc_branch_spans.push(MCDCBranchSpan {
362352
span: source_info.span,
363353
condition_info,
364354
true_marker,
365355
false_marker,
366356
});
367-
} else {
368-
branch_info.branch_spans.push(BranchSpan {
369-
span: source_info.span,
370-
true_marker,
371-
false_marker,
372-
});
357+
return;
373358
}
359+
360+
branch_info.branch_spans.push(BranchSpan {
361+
span: source_info.span,
362+
true_marker,
363+
false_marker,
364+
});
374365
}
375366

376367
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
377-
if let Some(branch_info) = self.coverage_branch_info.as_mut() {
378-
branch_info.record_conditions_operation(logical_op, span);
368+
if let Some(branch_info) = self.coverage_branch_info.as_mut()
369+
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
370+
{
371+
mcdc_state.record_conditions(logical_op, span);
379372
}
380373
}
381374
}

compiler/rustc_mir_transform/src/coverage/mod.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,21 @@ fn create_mappings<'tcx>(
149149
true_term: term_for_bcb(true_bcb),
150150
false_term: term_for_bcb(false_bcb),
151151
},
152-
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
153-
MappingKind::MCDCBranch {
152+
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info: None } => {
153+
MappingKind::Branch {
154154
true_term: term_for_bcb(true_bcb),
155155
false_term: term_for_bcb(false_bcb),
156-
mcdc_params: condition_info,
157156
}
158157
}
158+
BcbMappingKind::MCDCBranch {
159+
true_bcb,
160+
false_bcb,
161+
condition_info: Some(mcdc_params),
162+
} => MappingKind::MCDCBranch {
163+
true_term: term_for_bcb(true_bcb),
164+
false_term: term_for_bcb(false_bcb),
165+
mcdc_params,
166+
},
159167
BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => {
160168
MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num })
161169
}
@@ -249,7 +257,7 @@ fn inject_mcdc_statements<'tcx>(
249257
for (true_bcb, false_bcb, condition_id) in
250258
coverage_spans.all_bcb_mappings().filter_map(|mapping| match mapping.kind {
251259
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
252-
Some((true_bcb, false_bcb, condition_info.condition_id))
260+
Some((true_bcb, false_bcb, condition_info?.condition_id))
253261
}
254262
_ => None,
255263
})

compiler/rustc_mir_transform/src/coverage/spans.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ pub(super) enum BcbMappingKind {
2121
MCDCBranch {
2222
true_bcb: BasicCoverageBlock,
2323
false_bcb: BasicCoverageBlock,
24-
condition_info: ConditionInfo,
24+
/// If `None`, this actually represents a normal branch mapping inserted
25+
/// for code that was too complex for MC/DC.
26+
condition_info: Option<ConditionInfo>,
2527
},
2628
/// Associates a mcdc decision with its join BCB.
2729
MCDCDecision { end_bcbs: BTreeSet<BasicCoverageBlock>, bitmap_idx: u32, conditions_num: u16 },
@@ -85,6 +87,12 @@ pub(super) fn generate_coverage_spans(
8587
}));
8688

8789
mappings.extend(from_mir::extract_branch_mappings(
90+
mir_body,
91+
hir_info,
92+
basic_coverage_blocks,
93+
));
94+
95+
mappings.extend(from_mir::extract_mcdc_mappings(
8896
mir_body,
8997
hir_info.body_span,
9098
basic_coverage_blocks,

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+56-18
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,10 @@ impl SpanFromMir {
366366
}
367367
}
368368

369-
pub(super) fn extract_branch_mappings(
369+
fn resolve_block_markers(
370+
branch_info: &mir::coverage::BranchInfo,
370371
mir_body: &mir::Body<'_>,
371-
body_span: Span,
372-
basic_coverage_blocks: &CoverageGraph,
373-
) -> Vec<BcbMapping> {
374-
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
375-
return vec![];
376-
};
377-
372+
) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
378373
let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
379374
None,
380375
branch_info.num_block_markers,
@@ -389,6 +384,58 @@ pub(super) fn extract_branch_mappings(
389384
}
390385
}
391386

387+
block_markers
388+
}
389+
390+
// FIXME: There is currently a lot of redundancy between
391+
// `extract_branch_mappings` and `extract_mcdc_mappings`. This is needed so
392+
// that they can each be modified without interfering with the other, but in
393+
// the long term we should try to bring them together again when branch coverage
394+
// and MC/DC coverage support are more mature.
395+
396+
pub(super) fn extract_branch_mappings(
397+
mir_body: &mir::Body<'_>,
398+
hir_info: &ExtractedHirInfo,
399+
basic_coverage_blocks: &CoverageGraph,
400+
) -> Vec<BcbMapping> {
401+
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
402+
403+
let block_markers = resolve_block_markers(branch_info, mir_body);
404+
405+
branch_info
406+
.branch_spans
407+
.iter()
408+
.filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
409+
// For now, ignore any branch span that was introduced by
410+
// expansion. This makes things like assert macros less noisy.
411+
if !raw_span.ctxt().outer_expn_data().is_root() {
412+
return None;
413+
}
414+
let (span, _) =
415+
unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?;
416+
417+
let bcb_from_marker =
418+
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
419+
420+
let true_bcb = bcb_from_marker(true_marker)?;
421+
let false_bcb = bcb_from_marker(false_marker)?;
422+
423+
Some(BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span })
424+
})
425+
.collect::<Vec<_>>()
426+
}
427+
428+
pub(super) fn extract_mcdc_mappings(
429+
mir_body: &mir::Body<'_>,
430+
body_span: Span,
431+
basic_coverage_blocks: &CoverageGraph,
432+
) -> Vec<BcbMapping> {
433+
let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
434+
return vec![];
435+
};
436+
437+
let block_markers = resolve_block_markers(branch_info, mir_body);
438+
392439
let bcb_from_marker =
393440
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
394441

@@ -406,12 +453,6 @@ pub(super) fn extract_branch_mappings(
406453
Some((span, true_bcb, false_bcb))
407454
};
408455

409-
let branch_filter_map = |&BranchSpan { span: raw_span, true_marker, false_marker }| {
410-
check_branch_bcb(raw_span, true_marker, false_marker).map(|(span, true_bcb, false_bcb)| {
411-
BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span }
412-
})
413-
};
414-
415456
let mcdc_branch_filter_map =
416457
|&MCDCBranchSpan { span: raw_span, true_marker, false_marker, condition_info }| {
417458
check_branch_bcb(raw_span, true_marker, false_marker).map(
@@ -446,10 +487,7 @@ pub(super) fn extract_branch_mappings(
446487
})
447488
};
448489

449-
branch_info
450-
.branch_spans
451-
.iter()
452-
.filter_map(branch_filter_map)
490+
std::iter::empty()
453491
.chain(branch_info.mcdc_branch_spans.iter().filter_map(mcdc_branch_filter_map))
454492
.chain(branch_info.mcdc_decision_spans.iter().filter_map(decision_filter_map))
455493
.collect::<Vec<_>>()

0 commit comments

Comments
 (0)