Skip to content

Commit 41b3e59

Browse files
committed
Added primative support for or-patterns in match arm branch-coverage
1 parent 9190c63 commit 41b3e59

File tree

2 files changed

+50
-23
lines changed

2 files changed

+50
-23
lines changed

compiler/rustc_mir_build/src/build/coverageinfo.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,16 @@ struct NotInfo {
4545

4646
pub(crate) struct MatchArm {
4747
pub(crate) source_info: SourceInfo,
48-
pub(crate) pre_binding_block: Option<BasicBlock>,
48+
pub(crate) sub_branches: Vec<MatchArmSubBranch>,
4949
pub(crate) arm_block: BasicBlock,
5050
}
5151

52+
#[derive(Debug)]
53+
pub(crate) struct MatchArmSubBranch {
54+
pub(crate) source_info: SourceInfo,
55+
pub(crate) start_block: Option<BasicBlock>,
56+
}
57+
5258
#[derive(Default)]
5359
struct BlockMarkerGen {
5460
num_block_markers: usize,
@@ -181,26 +187,34 @@ impl CoverageInfoBuilder {
181187
return;
182188
}
183189

184-
// FIXME(#124118) The current implementation of branch coverage for
185-
// match arms can't handle or-patterns.
186-
if arms.iter().any(|arm| arm.pre_binding_block.is_none()) {
190+
let Some(branch_info) = self.branch_info.as_mut() else {
187191
return;
188-
}
192+
};
189193

190194
let branch_arms = arms
191195
.iter()
192-
.map(|&MatchArm { source_info, pre_binding_block, arm_block }| {
193-
let pre_guard_marker =
194-
self.markers.inject_block_marker(cfg, source_info, pre_binding_block.unwrap());
196+
.flat_map(|MatchArm { source_info, sub_branches, arm_block }| {
195197
let arm_taken_marker =
196-
self.markers.inject_block_marker(cfg, source_info, arm_block);
197-
BranchArm { span: source_info.span, pre_guard_marker, arm_taken_marker }
198+
self.markers.inject_block_marker(cfg, *source_info, *arm_block);
199+
let branch_arms = sub_branches
200+
.iter()
201+
.filter_map(|sub_branch| {
202+
let Some(block) = sub_branch.start_block else { return None };
203+
let marker =
204+
self.markers.inject_block_marker(cfg, sub_branch.source_info, block);
205+
Some(BranchArm {
206+
span: sub_branch.source_info.span,
207+
pre_guard_marker: marker,
208+
arm_taken_marker,
209+
})
210+
})
211+
.collect::<Vec<_>>();
212+
213+
branch_arms
198214
})
199215
.collect::<Vec<_>>();
200216

201-
if let Some(branch_info) = self.branch_info.as_mut() {
202-
branch_info.branch_arm_lists.push(branch_arms);
203-
}
217+
branch_info.branch_arm_lists.push(branch_arms);
204218
}
205219

206220
pub(crate) fn into_done(self) -> Box<CoverageInfoHi> {

compiler/rustc_mir_build/src/build/matches/mod.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
//! This also includes code for pattern bindings in `let` statements and
66
//! function parameters.
77
8+
use crate::build::expr::as_place::PlaceBuilder;
9+
use crate::build::scope::DropKind;
10+
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
11+
use crate::build::{
12+
coverageinfo, BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,
13+
};
14+
815
use rustc_data_structures::fx::FxIndexMap;
916
use rustc_data_structures::stack::ensure_sufficient_stack;
1017
use rustc_hir::{BindingMode, ByRef};
@@ -18,12 +25,6 @@ use rustc_span::{BytePos, Pos, Span};
1825
use rustc_target::abi::VariantIdx;
1926
use tracing::{debug, instrument};
2027

21-
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
22-
use crate::build::expr::as_place::PlaceBuilder;
23-
use crate::build::scope::DropKind;
24-
use crate::build::{
25-
BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, coverageinfo,
26-
};
2728

2829
// helper functions, broken out by category:
2930
mod match_pair;
@@ -453,8 +454,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
453454
opt_scrutinee_place,
454455
);
455456

456-
// FIXME: Propagate this info down to codegen
457-
let pre_binding_block = branch.sub_branches[0].otherwise_block;
457+
let sub_branches: Vec<_> = branch
458+
.sub_branches
459+
.iter()
460+
.map(|b| coverageinfo::MatchArmSubBranch {
461+
source_info: this.source_info(b.span),
462+
start_block: b.start_block,
463+
})
464+
.collect();
458465

459466
let arm_block = this.bind_pattern(
460467
outer_source_info,
@@ -468,7 +475,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
468475
if let Some(coverage_match_arms) = coverage_match_arms.as_mut() {
469476
coverage_match_arms.push(coverageinfo::MatchArm {
470477
source_info: this.source_info(arm.pattern.span),
471-
pre_binding_block: Some(pre_binding_block),
478+
sub_branches,
472479
arm_block,
473480
})
474481
}
@@ -1391,6 +1398,8 @@ pub(crate) struct ArmHasGuard(pub(crate) bool);
13911398
#[derive(Debug)]
13921399
struct MatchTreeSubBranch<'tcx> {
13931400
span: Span,
1401+
/// The first block in this sub branch.
1402+
start_block: Option<BasicBlock>,
13941403
/// The block that is branched to if the corresponding subpattern matches.
13951404
success_block: BasicBlock,
13961405
/// The block to branch to if this arm had a guard and the guard fails.
@@ -1441,6 +1450,7 @@ impl<'tcx> MatchTreeSubBranch<'tcx> {
14411450
debug_assert!(candidate.match_pairs.is_empty());
14421451
MatchTreeSubBranch {
14431452
span: candidate.extra_data.span,
1453+
start_block: candidate.false_edge_start_block,
14441454
success_block: candidate.pre_binding_block.unwrap(),
14451455
otherwise_block: candidate.otherwise_block.unwrap(),
14461456
bindings: parent_data
@@ -1860,7 +1870,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18601870
});
18611871
for candidate in candidates_to_expand.iter_mut() {
18621872
if !candidate.subcandidates.is_empty() {
1863-
self.merge_trivial_subcandidates(candidate);
1873+
// FIXME: Support merging trival candidates in branch coverage instrumentation
1874+
if self.coverage_info.is_none() {
1875+
self.merge_trivial_subcandidates(candidate);
1876+
}
18641877
self.remove_never_subcandidates(candidate);
18651878
}
18661879
}

0 commit comments

Comments
 (0)