Skip to content

Commit 40284a3

Browse files
committed
coverage: Treat each match arm as a "branch" for branch coverage
1 parent 67a774a commit 40284a3

12 files changed

+254
-65
lines changed

compiler/rustc_mir_build/src/build/coverageinfo.rs

+31
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ struct NotInfo {
3838
is_flipped: bool,
3939
}
4040

41+
pub(crate) struct MatchArm {
42+
pub(crate) source_info: SourceInfo,
43+
pub(crate) pre_binding_block: Option<BasicBlock>,
44+
pub(crate) arm_block: BasicBlock,
45+
}
46+
4147
impl BranchInfoBuilder {
4248
/// Creates a new branch info builder, but only if branch coverage instrumentation
4349
/// is enabled and `def_id` represents a function that is eligible for coverage.
@@ -152,6 +158,31 @@ impl BranchInfoBuilder {
152158
self.branch_arm_lists.push(vec![arm(true_marker), arm(false_marker)]);
153159
}
154160

161+
pub(crate) fn add_match_arms(&mut self, cfg: &mut CFG<'_>, arms: &[MatchArm]) {
162+
// Match expressions with 0-1 arms don't have any branches for their arms.
163+
if arms.len() < 2 {
164+
return;
165+
}
166+
167+
// FIXME(#124118) The current implementation of branch coverage for
168+
// match arms can't handle or-patterns.
169+
if arms.iter().any(|arm| arm.pre_binding_block.is_none()) {
170+
return;
171+
}
172+
173+
let branch_arms = arms
174+
.iter()
175+
.map(|&MatchArm { source_info, pre_binding_block, arm_block }| {
176+
let pre_guard_marker =
177+
self.inject_block_marker(cfg, source_info, pre_binding_block.unwrap());
178+
let arm_taken_marker = self.inject_block_marker(cfg, source_info, arm_block);
179+
BranchArm { span: source_info.span, pre_guard_marker, arm_taken_marker }
180+
})
181+
.collect::<Vec<_>>();
182+
183+
self.branch_arm_lists.push(branch_arms);
184+
}
185+
155186
fn next_block_marker_id(&mut self) -> BlockMarkerId {
156187
let id = BlockMarkerId::from_usize(self.num_block_markers);
157188
self.num_block_markers += 1;

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

+20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! This also includes code for pattern bindings in `let` statements and
66
//! function parameters.
77
8+
use crate::build::coverageinfo;
89
use crate::build::expr::as_place::PlaceBuilder;
910
use crate::build::scope::DropKind;
1011
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
@@ -461,6 +462,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
461462
outer_source_info: SourceInfo,
462463
fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
463464
) -> BlockAnd<()> {
465+
let mut coverage_match_arms = self.coverage_branch_info.is_some().then_some(vec![]);
466+
464467
let arm_end_blocks: Vec<_> = arm_candidates
465468
.into_iter()
466469
.map(|(arm, candidate)| {
@@ -495,6 +498,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
495498
opt_scrutinee_place,
496499
);
497500

501+
let pre_binding_block = candidate.pre_binding_block;
502+
498503
let arm_block = this.bind_pattern(
499504
outer_source_info,
500505
candidate,
@@ -504,6 +509,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
504509
false,
505510
);
506511

512+
if let Some(coverage_match_arms) = coverage_match_arms.as_mut() {
513+
coverage_match_arms.push(coverageinfo::MatchArm {
514+
source_info: this.source_info(arm.pattern.span),
515+
pre_binding_block,
516+
arm_block,
517+
})
518+
}
519+
507520
this.fixed_temps_scope = old_dedup_scope;
508521

509522
if let Some(source_scope) = scope {
@@ -515,6 +528,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
515528
})
516529
.collect();
517530

531+
if let Some(coverage_match_arms) = coverage_match_arms {
532+
self.coverage_branch_info
533+
.as_mut()
534+
.expect("checked when creating `coverage_match_arms`")
535+
.add_match_arms(&mut self.cfg, &coverage_match_arms);
536+
}
537+
518538
// all the arm blocks will rejoin here
519539
let end_block = self.cfg.start_new_block();
520540

+22-11
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
11
Function name: guard_simple::never_taken
2-
Raw bytes (56): 0x[01, 01, 04, 01, 05, 11, 09, 0f, 0d, 05, 09, 08, 01, 08, 01, 02, 1e, 20, 05, 02, 02, 0e, 00, 1e, 05, 00, 22, 00, 24, 11, 01, 0e, 00, 1e, 20, 09, 06, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
2+
Raw bytes (80): 0x[01, 01, 09, 07, 01, 17, 05, 0d, 09, 01, 05, 17, 11, 0d, 09, 11, 09, 23, 0d, 05, 09, 0a, 01, 08, 01, 02, 1e, 20, 01, 02, 02, 09, 00, 0a, 20, 05, 0e, 00, 0e, 00, 1e, 05, 00, 22, 00, 24, 20, 11, 12, 01, 09, 00, 0a, 11, 00, 0e, 00, 1e, 20, 09, 1a, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 1f, 02, 01, 00, 02]
33
Number of files: 1
44
- file 0 => global file 1
5-
Number of expressions: 4
6-
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
7-
- expression 1 operands: lhs = Counter(4), rhs = Counter(2)
8-
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
9-
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
10-
Number of file 0 mappings: 8
5+
Number of expressions: 9
6+
- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(0)
7+
- expression 1 operands: lhs = Expression(5, Add), rhs = Counter(1)
8+
- expression 2 operands: lhs = Counter(3), rhs = Counter(2)
9+
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
10+
- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4)
11+
- expression 5 operands: lhs = Counter(3), rhs = Counter(2)
12+
- expression 6 operands: lhs = Counter(4), rhs = Counter(2)
13+
- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(3)
14+
- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
15+
Number of file 0 mappings: 10
1116
- Code(Counter(0)) at (prev + 8, 1) to (start + 2, 30)
12-
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 2, 14) to (start + 0, 30)
17+
- Branch { true: Counter(0), false: Expression(0, Sub) } at (prev + 2, 9) to (start + 0, 10)
18+
true = c0
19+
false = (((c3 + c2) + c1) - c0)
20+
- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 14) to (start + 0, 30)
1321
true = c1
1422
false = (c0 - c1)
1523
- Code(Counter(1)) at (prev + 0, 34) to (start + 0, 36)
16-
- Code(Counter(4)) at (prev + 1, 14) to (start + 0, 30)
17-
- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 30)
24+
- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 1, 9) to (start + 0, 10)
25+
true = c4
26+
false = ((c3 + c2) - c4)
27+
- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 30)
28+
- Branch { true: Counter(2), false: Expression(6, Sub) } at (prev + 0, 14) to (start + 0, 30)
1829
true = c2
1930
false = (c4 - c2)
2031
- Code(Counter(2)) at (prev + 0, 34) to (start + 0, 36)
2132
- Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16)
22-
- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2)
33+
- Code(Expression(7, Add)) at (prev + 2, 1) to (start + 0, 2)
2334
= ((c1 + c2) + c3)
2435

tests/coverage/branch/guard-simple.coverage

+2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
LL| 1| _ if black_box(false) => {}
1111
^0
1212
------------------
13+
| Branch (LL:9): [True: 1, False: 0]
1314
| Branch (LL:14): [True: 0, False: 1]
1415
------------------
1516
LL| 1| _ if black_box(false) => {}
1617
^0
1718
------------------
19+
| Branch (LL:9): [True: 1, False: 0]
1820
| Branch (LL:14): [True: 0, False: 1]
1921
------------------
2022
LL| 1| _ => {}

tests/coverage/branch/guard.cov-map

+31-15
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,48 @@
11
Function name: guard::branch_match_guard
2-
Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02]
2+
Raw bytes (120): 0x[01, 01, 0d, 1b, 0d, 33, 11, 05, 09, 03, 19, 19, 0d, 1b, 1d, 33, 11, 05, 09, 05, 09, 2b, 15, 2f, 11, 33, 0d, 05, 09, 10, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 20, 15, 03, 01, 09, 00, 10, 15, 00, 14, 02, 0a, 20, 19, 0e, 03, 09, 00, 10, 0d, 00, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 12, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 20, 1d, 16, 03, 09, 00, 10, 11, 00, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 33, 03, 0e, 02, 0a, 27, 04, 01, 00, 02]
33
Number of files: 1
44
- file 0 => global file 1
5-
Number of expressions: 6
6-
- expression 0 operands: lhs = Counter(6), rhs = Counter(3)
7-
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
8-
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
9-
- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
10-
- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
11-
- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
12-
Number of file 0 mappings: 13
5+
Number of expressions: 13
6+
- expression 0 operands: lhs = Expression(6, Add), rhs = Counter(3)
7+
- expression 1 operands: lhs = Expression(12, Add), rhs = Counter(4)
8+
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
9+
- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(6)
10+
- expression 4 operands: lhs = Counter(6), rhs = Counter(3)
11+
- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(7)
12+
- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4)
13+
- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
14+
- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
15+
- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5)
16+
- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
17+
- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
18+
- expression 12 operands: lhs = Counter(1), rhs = Counter(2)
19+
Number of file 0 mappings: 16
1320
- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
1421
- Code(Counter(7)) at (prev + 3, 11) to (start + 0, 12)
15-
- Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10)
16-
- Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15)
22+
- Branch { true: Counter(5), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 16)
23+
true = c5
24+
false = (((c1 + c2) + c4) + c3)
25+
- Code(Counter(5)) at (prev + 0, 20) to (start + 2, 10)
26+
- Branch { true: Counter(6), false: Expression(3, Sub) } at (prev + 3, 9) to (start + 0, 16)
27+
true = c6
28+
false = ((((c1 + c2) + c4) + c3) - c6)
29+
- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 15)
1730
- Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25)
18-
- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30)
31+
- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 20) to (start + 0, 30)
1932
true = c3
2033
false = (c6 - c3)
2134
- Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10)
22-
- Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15)
35+
- Branch { true: Counter(7), false: Expression(5, Sub) } at (prev + 3, 9) to (start + 0, 16)
36+
true = c7
37+
false = (((c1 + c2) + c4) - c7)
38+
- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 15)
2339
- Code(Counter(7)) at (prev + 0, 20) to (start + 0, 25)
2440
- Branch { true: Counter(4), false: Counter(2) } at (prev + 0, 20) to (start + 0, 30)
2541
true = c4
2642
false = c2
2743
- Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10)
28-
- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10)
44+
- Code(Expression(12, Add)) at (prev + 3, 14) to (start + 2, 10)
2945
= (c1 + c2)
30-
- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2)
46+
- Code(Expression(9, Add)) at (prev + 4, 1) to (start + 0, 2)
3147
= ((((c1 + c2) + c3) + c4) + c5)
3248

tests/coverage/branch/guard.coverage

+5
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,22 @@
1414
LL| |
1515
LL| 1| match x {
1616
LL| 1| Some(0) => {
17+
------------------
18+
| Branch (LL:9): [True: 1, False: 3]
19+
------------------
1720
LL| 1| println!("zero");
1821
LL| 1| }
1922
LL| 3| Some(x) if x % 2 == 0 => {
2023
^2
2124
------------------
25+
| Branch (LL:9): [True: 3, False: 0]
2226
| Branch (LL:20): [True: 2, False: 1]
2327
------------------
2428
LL| 2| println!("is nonzero and even");
2529
LL| 2| }
2630
LL| 1| Some(x) if x % 3 == 0 => {
2731
------------------
32+
| Branch (LL:9): [True: 1, False: 0]
2833
| Branch (LL:20): [True: 1, False: 0]
2934
------------------
3035
LL| 1| println!("is nonzero and odd, but divisible by 3");

0 commit comments

Comments
 (0)