Skip to content

Commit 9a5cd84

Browse files
authored
Unrolled build for rust-lang#124217
Rollup merge of rust-lang#124217 - Zalathar:pre-branch, r=oli-obk coverage: Prepare for improved branch coverage When trying to rebase my new branch coverage work (including rust-lang#124154) on top of the introduction of MC/DC coverage (rust-lang#123409), I found it a lot harder than anticipated. With the benefit of hindsight, the branch coverage code and MC/DC code have become more interdependent than I'm happy with. This PR therefore disentangles them a bit, so that it will be easier for both areas of code to evolve independently without interference. --- This PR also includes a few extra branch coverage tests that I had sitting around from my current branch coverage work. They mostly just demonstrate that certain language constructs listed in rust-lang#124118 currently don't have branch coverage support. ``@rustbot`` label +A-code-coverage
2 parents 25087e0 + 2b6adb0 commit 9a5cd84

26 files changed

+993
-94
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

+55-48
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use rustc_middle::mir::coverage::{
77
BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageKind, MCDCBranchSpan,
88
MCDCDecisionSpan,
99
};
10-
use rustc_middle::mir::{self, BasicBlock, UnOp};
10+
use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
1111
use rustc_middle::thir::{ExprId, ExprKind, LogicalOp, Thir};
1212
use rustc_middle::ty::TyCtxt;
1313
use rustc_span::def_id::LocalDefId;
1414
use rustc_span::Span;
1515

16-
use crate::build::Builder;
16+
use crate::build::{Builder, CFG};
1717
use crate::errors::MCDCExceedsConditionNumLimit;
1818

1919
pub(crate) struct BranchInfoBuilder {
@@ -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;
@@ -144,20 +134,50 @@ impl BranchInfoBuilder {
144134
condition_info
145135
}
146136

137+
fn add_two_way_branch<'tcx>(
138+
&mut self,
139+
cfg: &mut CFG<'tcx>,
140+
source_info: SourceInfo,
141+
true_block: BasicBlock,
142+
false_block: BasicBlock,
143+
) {
144+
let true_marker = self.inject_block_marker(cfg, source_info, true_block);
145+
let false_marker = self.inject_block_marker(cfg, source_info, false_block);
146+
147+
self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker });
148+
}
149+
147150
fn next_block_marker_id(&mut self) -> BlockMarkerId {
148151
let id = BlockMarkerId::from_usize(self.num_block_markers);
149152
self.num_block_markers += 1;
150153
id
151154
}
152155

156+
fn inject_block_marker(
157+
&mut self,
158+
cfg: &mut CFG<'_>,
159+
source_info: SourceInfo,
160+
block: BasicBlock,
161+
) -> BlockMarkerId {
162+
let id = self.next_block_marker_id();
163+
164+
let marker_statement = mir::Statement {
165+
source_info,
166+
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
167+
};
168+
cfg.push(block, marker_statement);
169+
170+
id
171+
}
172+
153173
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
154174
let Self {
155175
nots: _,
156176
num_block_markers,
157177
branch_spans,
158178
mcdc_branch_spans,
159179
mcdc_decision_spans,
160-
..
180+
mcdc_state: _,
161181
} = self;
162182

163183
if num_block_markers == 0 {
@@ -325,7 +345,7 @@ impl Builder<'_, '_> {
325345
mut else_block: BasicBlock,
326346
) {
327347
// Bail out if branch coverage is not enabled for this function.
328-
let Some(branch_info) = self.coverage_branch_info.as_ref() else { return };
348+
let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
329349

330350
// If this condition expression is nested within one or more `!` expressions,
331351
// replace it with the enclosing `!` collected by `visit_unary_not`.
@@ -335,47 +355,34 @@ impl Builder<'_, '_> {
335355
std::mem::swap(&mut then_block, &mut else_block);
336356
}
337357
}
338-
let source_info = self.source_info(self.thir[expr_id].span);
339-
340-
// Now that we have `source_info`, we can upgrade to a &mut reference.
341-
let branch_info = self.coverage_branch_info.as_mut().expect("upgrading & to &mut");
342-
343-
let mut inject_branch_marker = |block: BasicBlock| {
344-
let id = branch_info.next_block_marker_id();
345-
346-
let marker_statement = mir::Statement {
347-
source_info,
348-
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
349-
};
350-
self.cfg.push(block, marker_statement);
351358

352-
id
353-
};
354-
355-
let true_marker = inject_branch_marker(then_block);
356-
let false_marker = inject_branch_marker(else_block);
359+
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
357360

358-
if let Some(condition_info) =
359-
branch_info.fetch_condition_info(self.tcx, true_marker, false_marker)
360-
{
361+
// Separate path for handling branches when MC/DC is enabled.
362+
if branch_info.mcdc_state.is_some() {
363+
let mut inject_block_marker =
364+
|block| branch_info.inject_block_marker(&mut self.cfg, source_info, block);
365+
let true_marker = inject_block_marker(then_block);
366+
let false_marker = inject_block_marker(else_block);
367+
let condition_info =
368+
branch_info.fetch_mcdc_condition_info(self.tcx, true_marker, false_marker);
361369
branch_info.mcdc_branch_spans.push(MCDCBranchSpan {
362370
span: source_info.span,
363371
condition_info,
364372
true_marker,
365373
false_marker,
366374
});
367-
} else {
368-
branch_info.branch_spans.push(BranchSpan {
369-
span: source_info.span,
370-
true_marker,
371-
false_marker,
372-
});
375+
return;
373376
}
377+
378+
branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
374379
}
375380

376381
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);
382+
if let Some(branch_info) = self.coverage_branch_info.as_mut()
383+
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
384+
{
385+
mcdc_state.record_conditions(logical_op, span);
379386
}
380387
}
381388
}

compiler/rustc_mir_transform/src/coverage/mod.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod tests;
99

1010
use self::counters::{CounterIncrementSite, CoverageCounters};
1111
use self::graph::{BasicCoverageBlock, CoverageGraph};
12-
use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans};
12+
use self::spans::{BcbBranchPair, BcbMapping, BcbMappingKind, CoverageSpans};
1313

1414
use crate::MirPass;
1515

@@ -141,21 +141,25 @@ fn create_mappings<'tcx>(
141141

142142
let mut mappings = Vec::new();
143143

144-
mappings.extend(coverage_spans.all_bcb_mappings().filter_map(
144+
mappings.extend(coverage_spans.mappings.iter().filter_map(
145145
|BcbMapping { kind: bcb_mapping_kind, span }| {
146146
let kind = match *bcb_mapping_kind {
147147
BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
148-
BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
149-
true_term: term_for_bcb(true_bcb),
150-
false_term: term_for_bcb(false_bcb),
151-
},
152-
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
153-
MappingKind::MCDCBranch {
148+
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info: None } => {
149+
MappingKind::Branch {
154150
true_term: term_for_bcb(true_bcb),
155151
false_term: term_for_bcb(false_bcb),
156-
mcdc_params: condition_info,
157152
}
158153
}
154+
BcbMappingKind::MCDCBranch {
155+
true_bcb,
156+
false_bcb,
157+
condition_info: Some(mcdc_params),
158+
} => MappingKind::MCDCBranch {
159+
true_term: term_for_bcb(true_bcb),
160+
false_term: term_for_bcb(false_bcb),
161+
mcdc_params,
162+
},
159163
BcbMappingKind::MCDCDecision { bitmap_idx, conditions_num, .. } => {
160164
MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num })
161165
}
@@ -165,6 +169,16 @@ fn create_mappings<'tcx>(
165169
},
166170
));
167171

172+
mappings.extend(coverage_spans.branch_pairs.iter().filter_map(
173+
|&BcbBranchPair { span, true_bcb, false_bcb }| {
174+
let true_term = term_for_bcb(true_bcb);
175+
let false_term = term_for_bcb(false_bcb);
176+
let kind = MappingKind::Branch { true_term, false_term };
177+
let code_region = make_code_region(source_map, file_name, span, body_span)?;
178+
Some(Mapping { kind, code_region })
179+
},
180+
));
181+
168182
mappings
169183
}
170184

@@ -233,7 +247,7 @@ fn inject_mcdc_statements<'tcx>(
233247

234248
// Inject test vector update first because `inject_statement` always insert new statement at head.
235249
for (end_bcbs, bitmap_idx) in
236-
coverage_spans.all_bcb_mappings().filter_map(|mapping| match &mapping.kind {
250+
coverage_spans.mappings.iter().filter_map(|mapping| match &mapping.kind {
237251
BcbMappingKind::MCDCDecision { end_bcbs, bitmap_idx, .. } => {
238252
Some((end_bcbs, *bitmap_idx))
239253
}
@@ -247,9 +261,9 @@ fn inject_mcdc_statements<'tcx>(
247261
}
248262

249263
for (true_bcb, false_bcb, condition_id) in
250-
coverage_spans.all_bcb_mappings().filter_map(|mapping| match mapping.kind {
264+
coverage_spans.mappings.iter().filter_map(|mapping| match mapping.kind {
251265
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, condition_info } => {
252-
Some((true_bcb, false_bcb, condition_info.condition_id))
266+
Some((true_bcb, false_bcb, condition_info?.condition_id))
253267
}
254268
_ => None,
255269
})

compiler/rustc_mir_transform/src/coverage/spans.rs

+34-13
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ mod from_mir;
1515
pub(super) enum BcbMappingKind {
1616
/// Associates an ordinary executable code span with its corresponding BCB.
1717
Code(BasicCoverageBlock),
18-
/// Associates a branch span with BCBs for its true and false arms.
19-
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
18+
19+
// Ordinary branch mappings are stored separately, so they don't have a
20+
// variant in this enum.
21+
//
2022
/// Associates a mcdc branch span with condition info besides fields for normal branch.
2123
MCDCBranch {
2224
true_bcb: BasicCoverageBlock,
2325
false_bcb: BasicCoverageBlock,
24-
condition_info: ConditionInfo,
26+
/// If `None`, this actually represents a normal branch mapping inserted
27+
/// for code that was too complex for MC/DC.
28+
condition_info: Option<ConditionInfo>,
2529
},
2630
/// Associates a mcdc decision with its join BCB.
2731
MCDCDecision { end_bcbs: BTreeSet<BasicCoverageBlock>, bitmap_idx: u32, conditions_num: u16 },
@@ -33,9 +37,20 @@ pub(super) struct BcbMapping {
3337
pub(super) span: Span,
3438
}
3539

40+
/// This is separate from [`BcbMappingKind`] to help prepare for larger changes
41+
/// that will be needed for improved branch coverage in the future.
42+
/// (See <https://github.com/rust-lang/rust/pull/124217>.)
43+
#[derive(Debug)]
44+
pub(super) struct BcbBranchPair {
45+
pub(super) span: Span,
46+
pub(super) true_bcb: BasicCoverageBlock,
47+
pub(super) false_bcb: BasicCoverageBlock,
48+
}
49+
3650
pub(super) struct CoverageSpans {
3751
bcb_has_mappings: BitSet<BasicCoverageBlock>,
38-
mappings: Vec<BcbMapping>,
52+
pub(super) mappings: Vec<BcbMapping>,
53+
pub(super) branch_pairs: Vec<BcbBranchPair>,
3954
test_vector_bitmap_bytes: u32,
4055
}
4156

@@ -44,10 +59,6 @@ impl CoverageSpans {
4459
self.bcb_has_mappings.contains(bcb)
4560
}
4661

47-
pub(super) fn all_bcb_mappings(&self) -> impl Iterator<Item = &BcbMapping> {
48-
self.mappings.iter()
49-
}
50-
5162
pub(super) fn test_vector_bitmap_bytes(&self) -> u32 {
5263
self.test_vector_bitmap_bytes
5364
}
@@ -63,6 +74,7 @@ pub(super) fn generate_coverage_spans(
6374
basic_coverage_blocks: &CoverageGraph,
6475
) -> Option<CoverageSpans> {
6576
let mut mappings = vec![];
77+
let mut branch_pairs = vec![];
6678

6779
if hir_info.is_async_fn {
6880
// An async function desugars into a function that returns a future,
@@ -84,14 +96,20 @@ pub(super) fn generate_coverage_spans(
8496
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
8597
}));
8698

87-
mappings.extend(from_mir::extract_branch_mappings(
99+
branch_pairs.extend(from_mir::extract_branch_pairs(
100+
mir_body,
101+
hir_info,
102+
basic_coverage_blocks,
103+
));
104+
105+
mappings.extend(from_mir::extract_mcdc_mappings(
88106
mir_body,
89107
hir_info.body_span,
90108
basic_coverage_blocks,
91109
));
92110
}
93111

94-
if mappings.is_empty() {
112+
if mappings.is_empty() && branch_pairs.is_empty() {
95113
return None;
96114
}
97115

@@ -104,8 +122,7 @@ pub(super) fn generate_coverage_spans(
104122
for BcbMapping { kind, span: _ } in &mappings {
105123
match *kind {
106124
BcbMappingKind::Code(bcb) => insert(bcb),
107-
BcbMappingKind::Branch { true_bcb, false_bcb }
108-
| BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => {
125+
BcbMappingKind::MCDCBranch { true_bcb, false_bcb, .. } => {
109126
insert(true_bcb);
110127
insert(false_bcb);
111128
}
@@ -118,8 +135,12 @@ pub(super) fn generate_coverage_spans(
118135
}
119136
}
120137
}
138+
for &BcbBranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
139+
insert(true_bcb);
140+
insert(false_bcb);
141+
}
121142

122-
Some(CoverageSpans { bcb_has_mappings, mappings, test_vector_bitmap_bytes })
143+
Some(CoverageSpans { bcb_has_mappings, mappings, branch_pairs, test_vector_bitmap_bytes })
123144
}
124145

125146
#[derive(Debug)]

0 commit comments

Comments
 (0)