Skip to content

Commit 3aef9e0

Browse files
committed
Fixed coverage issues that I didn't like.
* Avoid adding coverage to unreachable blocks. * Special case for Goto at the end of the body. Make it non-reportable.
1 parent bce5815 commit 3aef9e0

25 files changed

+148
-178
lines changed

compiler/rustc_mir/src/transform/instrument_coverage.rs

Lines changed: 30 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ impl BasicCoverageBlocks {
381381
let successors = IndexVec::from_fn_n(
382382
|bcb| {
383383
let bcb_data = &bcbs[bcb];
384-
let bcb_successors = bcb_filtered_successors(&bcb_data.terminator(mir_body).kind)
384+
let bcb_successors = bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
385385
// TODO(richkadel):
386386
// MAKE SURE WE ONLY RETURN THE SAME SUCCESSORS USED WHEN CREATING THE BCB (THE FIRST SUCCESSOR ONLY,
387387
// UNLESS ITS A SWITCHINT).)
@@ -425,7 +425,7 @@ impl BasicCoverageBlocks {
425425
// each block terminator's `successors()`. Coverage spans must map to actual source code,
426426
// so compiler generated blocks and paths can be ignored. To that end, the CFG traversal
427427
// intentionally omits unwind paths.
428-
let mir_cfg_without_unwind = ShortCircuitPreorder::new(mir_body, bcb_filtered_successors);
428+
let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors);
429429

430430
let mut basic_blocks = Vec::new();
431431
for (bb, data) in mir_cfg_without_unwind {
@@ -1078,7 +1078,17 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
10781078
if let Some(bcb_to_coverage_spans_with_counters) = debug_bcb_to_coverage_spans_with_counters.as_mut() {
10791079
bcb_to_coverage_spans_with_counters.entry(bcb).or_insert_with(|| Vec::new()).push((covspan.clone(), counter_kind.clone()));
10801080
}
1081-
self.inject_statement(counter_kind, self.bcb_last_bb(bcb), make_code_region(file_name, &source_file, span, body_span));
1081+
let mut code_region = None;
1082+
if span.hi() == body_span.hi() {
1083+
// TODO(richkadel): add a comment if this works
1084+
if let TerminatorKind::Goto { .. } = self.bcb_terminator(bcb).kind {
1085+
code_region = Some(make_non_reportable_code_region(file_name, &source_file, span));
1086+
}
1087+
}
1088+
if code_region.is_none() {
1089+
code_region = Some(make_code_region(file_name, &source_file, span, body_span));
1090+
};
1091+
self.inject_statement(counter_kind, self.bcb_last_bb(bcb), code_region.unwrap());
10821092
}
10831093

10841094
// The previous step looped through the `CoverageSpan`s and injected the counter from the
@@ -1218,7 +1228,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
12181228
};
12191229
let edge_labels = |from_bcb| {
12201230
let from_terminator = self.bcb_terminator(from_bcb);
1221-
let edge_labels = from_terminator.kind.fmt_successor_labels();
1231+
let mut edge_labels = from_terminator.kind.fmt_successor_labels();
1232+
edge_labels.retain(|label| label.to_string() != "unreachable");
12221233
let edge_counters = from_terminator.successors().map(|&successor| {
12231234
edge_to_counter.get(&(from_bcb, successor))
12241235
});
@@ -2663,34 +2674,34 @@ fn hash(
26632674
stable_hasher.finish()
26642675
}
26652676

2666-
fn bcb_filtered_successors<'tcx>(term_kind: &'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx> {
2677+
fn bcb_filtered_successors<'a, 'tcx>(body: &'tcx &'a mir::Body<'tcx>, term_kind: &'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
26672678
let mut successors = term_kind.successors();
2668-
match &term_kind {
2679+
box match &term_kind {
26692680
// SwitchInt successors are never unwind, and all of them should be traversed.
26702681
TerminatorKind::SwitchInt { .. } => successors,
26712682
// For all other kinds, return only the first successor, if any, and ignore unwinds.
26722683
// NOTE: `chain(&[])` is required to coerce the `option::iter` (from
26732684
// `next().into_iter()`) into the `mir::Successors` aliased type.
26742685
_ => successors.next().into_iter().chain(&[]),
2675-
}
2686+
}.filter(move |&&successor| body[successor].terminator().kind != TerminatorKind::Unreachable)
26762687
}
26772688

26782689
pub struct ShortCircuitPreorder<
26792690
'a,
26802691
'tcx,
2681-
F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>,
2692+
F: Fn(&'tcx &'a mir::Body<'tcx>, &'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
26822693
> {
2683-
body: &'a mir::Body<'tcx>,
2694+
body: &'tcx &'a mir::Body<'tcx>,
26842695
visited: BitSet<BasicBlock>,
26852696
worklist: Vec<BasicBlock>,
26862697
filtered_successors: F,
26872698
}
26882699

2689-
impl<'a, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>>
2700+
impl<'a, 'tcx, F: Fn(&'tcx &'a mir::Body<'tcx>, &'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>>
26902701
ShortCircuitPreorder<'a, 'tcx, F>
26912702
{
26922703
pub fn new(
2693-
body: &'a mir::Body<'tcx>,
2704+
body: &'tcx &'a mir::Body<'tcx>,
26942705
filtered_successors: F,
26952706
) -> ShortCircuitPreorder<'a, 'tcx, F> {
26962707
let worklist = vec![mir::START_BLOCK];
@@ -2704,7 +2715,7 @@ impl<'a, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>>
27042715
}
27052716
}
27062717

2707-
impl<'a: 'tcx, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>> Iterator
2718+
impl<'a: 'tcx, 'tcx, F: Fn(&'tcx &'a mir::Body<'tcx>, &'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>> Iterator
27082719
for ShortCircuitPreorder<'a, 'tcx, F>
27092720
{
27102721
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
@@ -2718,7 +2729,7 @@ impl<'a: 'tcx, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>>
27182729
let data = &self.body[idx];
27192730

27202731
if let Some(ref term) = data.terminator {
2721-
self.worklist.extend((self.filtered_successors)(&term.kind));
2732+
self.worklist.extend((self.filtered_successors)(&self.body, &term.kind));
27222733
}
27232734

27242735
return Some((idx, data));
@@ -2733,49 +2744,10 @@ impl<'a: 'tcx, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>>
27332744
}
27342745
}
27352746

2736-
// NOTE: Regarding past efforts and revelations when trying to identify `Unreachable` coverage spans
2737-
// from the MIR:
2738-
//
2739-
// TerminatorKind::FalseEdge targets from SwitchInt don't appear to be helpful in identifying
2740-
// unreachable code. I did test the theory, but the following changes were not beneficial. (I
2741-
// assumed that replacing some constants with non-deterministic variables might effect which blocks
2742-
// were targeted by a `FalseEdge` `imaginary_target`. It did not.)
2743-
//
2744-
// Also note that, if there is a way to identify BasicBlocks that are part of the MIR CFG, but not
2745-
// actually reachable, here are some other things to consider:
2746-
//
2747-
// Injecting unreachable code regions will probably require computing the set difference between the
2748-
// basic blocks found without filtering out unreachable blocks, and the basic blocks found with a
2749-
// filter (similar to or as an extension of the `filter_unwind_paths` filter); then computing the
2750-
// `CoverageSpans` without the filter; and then injecting `Counter`s or `Expression`s for
2751-
// blocks that are not unreachable, or injecting `Unreachable` code regions otherwise. This seems
2752-
// straightforward, but not trivial.
2753-
//
2754-
// Alternatively, we might instead want to leave the unreachable blocks in (bypass the filter here),
2755-
// and inject the counters. This will result in counter values of zero (0) for unreachable code
2756-
// (and, notably, the code will be displayed with a red background by `llvm-cov show`).
2757-
//
2758-
// ```rust
2759-
// TerminatorKind::SwitchInt { .. } => {
2760-
// let some_imaginary_target = successors.clone().find_map(|&successor| {
2761-
// let term = mir_body[successor].terminator();
2762-
// if let TerminatorKind::FalseEdge { imaginary_target, .. } = term.kind {
2763-
// if mir_body.predecessors()[imaginary_target].len() == 1 {
2764-
// return Some(imaginary_target);
2765-
// }
2766-
// }
2767-
// None
2768-
// });
2769-
// if let Some(imaginary_target) = some_imaginary_target {
2770-
// box successors.filter(move |&&successor| successor != imaginary_target)
2771-
// } else {
2772-
// box successors
2773-
// }
2774-
// }
2775-
// ```
2776-
//
2777-
// Note this also required changing the closure signature for the `ShortCurcuitPreorder` to:
2747+
// TODO(richkadel): try_error_result.rs
2748+
// When executing the Result as Try>::from_error() returns to one or more
2749+
// Goto that then targets Return.
2750+
// Both the Goto (after error) and the Return have coverage at the last
2751+
// bytepos, 0-length Span.
27782752
//
2779-
// ```rust
2780-
// F: Fn(&'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &BasicBlock> + 'a>,
2781-
// ```
2753+
// How should I eliminate one, and which one, to avoid counting both.

src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
"percent": 100
1717
},
1818
"lines": {
19-
"count": 28,
19+
"count": 24,
2020
"covered": 24,
21-
"percent": 85.71428571428571
21+
"percent": 100
2222
},
2323
"regions": {
2424
"count": 15,
@@ -41,9 +41,9 @@
4141
"percent": 100
4242
},
4343
"lines": {
44-
"count": 28,
44+
"count": 24,
4545
"covered": 24,
46-
"percent": 85.71428571428571
46+
"percent": 100
4747
},
4848
"regions": {
4949
"count": 15,

src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
"percent": 100
1717
},
1818
"lines": {
19-
"count": 20,
19+
"count": 19,
2020
"covered": 18,
21-
"percent": 90
21+
"percent": 94.73684210526315
2222
},
2323
"regions": {
24-
"count": 18,
25-
"covered": 15,
24+
"count": 17,
25+
"covered": 14,
2626
"notcovered": 3,
27-
"percent": 83.33333333333334
27+
"percent": 82.35294117647058
2828
}
2929
}
3030
}
@@ -41,15 +41,15 @@
4141
"percent": 100
4242
},
4343
"lines": {
44-
"count": 20,
44+
"count": 19,
4545
"covered": 18,
46-
"percent": 90
46+
"percent": 94.73684210526315
4747
},
4848
"regions": {
49-
"count": 18,
50-
"covered": 15,
49+
"count": 17,
50+
"covered": 14,
5151
"notcovered": 3,
52-
"percent": 83.33333333333334
52+
"percent": 82.35294117647058
5353
}
5454
}
5555
}

src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.various_conditions.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
"percent": 48.97959183673469
2222
},
2323
"regions": {
24-
"count": 70,
25-
"covered": 19,
24+
"count": 69,
25+
"covered": 18,
2626
"notcovered": 51,
27-
"percent": 27.142857142857142
27+
"percent": 26.08695652173913
2828
}
2929
}
3030
}
@@ -46,10 +46,10 @@
4646
"percent": 48.97959183673469
4747
},
4848
"regions": {
49-
"count": 70,
50-
"covered": 19,
49+
"count": 69,
50+
"covered": 18,
5151
"notcovered": 51,
52-
"percent": 27.142857142857142
52+
"percent": 26.08695652173913
5353
}
5454
}
5555
}

src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_return.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
"percent": 88.23529411764706
2222
},
2323
"regions": {
24-
"count": 10,
25-
"covered": 8,
24+
"count": 9,
25+
"covered": 7,
2626
"notcovered": 2,
27-
"percent": 80
27+
"percent": 77.77777777777779
2828
}
2929
}
3030
}
@@ -46,10 +46,10 @@
4646
"percent": 88.23529411764706
4747
},
4848
"regions": {
49-
"count": 10,
50-
"covered": 8,
49+
"count": 9,
50+
"covered": 7,
5151
"notcovered": 2,
52-
"percent": 80
52+
"percent": 77.77777777777779
5353
}
5454
}
5555
}

src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
15| 2| _
1717
16| | in
1818
17| 3| 0..2
19-
18| 0| {
20-
19| 0| let z
21-
20| 0| ;
22-
21| 0| match
19+
18| | {
20+
19| | let z
21+
20| | ;
22+
21| | match
2323
22| 2| countdown
2424
23| | {
2525
24| 1| x

src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
17| 6| _
1818
18| | in
1919
19| 6| 0..10
20-
20| 0| {
20+
20| | {
2121
21| 6| countdown
2222
22| 6| -= 1
2323
23| 6| ;
@@ -33,5 +33,5 @@
3333
32| 5| }
3434
33| 5| }
3535
34| 0| Ok(())
36-
35| 2|}
36+
35| 1|}
3737

src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.various_conditions.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,5 @@
6666
64| | } else {
6767
65| 0| return;
6868
66| | };
69-
67| 2|}
69+
67| 1|}
7070

src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_return.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
33| | ;
3434
34| | }
3535
35| 0| Ok(())
36-
36| 2|}
36+
36| 1|}
3737
37| |
3838
38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
3939
39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux

src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ Counter in file 0 7:9 -> 9:26, #1
33
Counter in file 0 10:8 -> 10:15, (#1 + 0)
44
Counter in file 0 10:16 -> 12:6, #2
55
Counter in file 0 12:6 -> 12:7, (#1 - #2)
6-
Counter in file 0 15:9 -> 15:10, (((#2 + (#1 - #2)) + (#3 + #4)) - (#6 + #5))
6+
Counter in file 0 15:9 -> 15:10, (((#2 + (#1 - #2)) + (#3 + #4)) - #5)
77
Counter in file 0 17:9 -> 17:13, ((#2 + (#1 - #2)) + (#3 + #4))
8-
Counter in file 0 17:13 -> 17:13, #6
9-
Counter in file 0 22:13 -> 22:22, ((((#2 + (#1 - #2)) + (#3 + #4)) - (#6 + #5)) + 0)
8+
Counter in file 0 22:13 -> 22:22, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0)
109
Counter in file 0 24:13 -> 24:14, #3
11-
Counter in file 0 26:17 -> 28:18, ((((#2 + (#1 - #2)) + (#3 + #4)) - (#6 + #5)) + 0)
12-
Counter in file 0 28:18 -> 28:19, ((((#2 + (#1 - #2)) + (#3 + #4)) - (#6 + #5)) - #3)
10+
Counter in file 0 26:17 -> 28:18, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0)
11+
Counter in file 0 28:18 -> 28:19, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) - #3)
1312
Counter in file 0 30:13 -> 37:14, (#3 + 0)
1413
Counter in file 0 40:13 -> 40:15, #4
1514
Counter in file 0 42:6 -> 42:7, (#2 + (#1 - #2))
@@ -23,7 +22,6 @@ Combined regions:
2322
12:6 -> 12:7 (count=0)
2423
15:9 -> 15:10 (count=2)
2524
17:9 -> 17:13 (count=3)
26-
17:13 -> 17:13 (count=0)
2725
22:13 -> 22:22 (count=2)
2826
24:13 -> 24:14 (count=1)
2927
26:17 -> 28:18 (count=2)
@@ -42,7 +40,7 @@ Segment at 12:7 (count = 0), Skipped
4240
Segment at 15:9 (count = 2), RegionEntry
4341
Segment at 15:10 (count = 0), Skipped
4442
Segment at 17:9 (count = 3), RegionEntry
45-
Segment at 17:13 (count = 0), Gap
43+
Segment at 17:13 (count = 0), Skipped
4644
Segment at 22:13 (count = 2), RegionEntry
4745
Segment at 22:22 (count = 0), Skipped
4846
Segment at 24:13 (count = 1), RegionEntry

0 commit comments

Comments
 (0)