Skip to content

Commit b2c20b5

Browse files
committed
Auto merge of #84295 - richkadel:continue-coverage, r=tmandry
Add coverage to continue statements `continue` statements were missing coverage. This was particularly noticeable in a match pattern that contained only a `continue` statement, leaving the branch appear uncounted. This PR addresses the problem and adds tests to prove it. r? `@tmandry` cc: `@wesleywiser`
2 parents e888a57 + d1d7fb1 commit b2c20b5

File tree

4 files changed

+161
-2
lines changed

4 files changed

+161
-2
lines changed

compiler/rustc_mir_build/src/build/scope.rs

+15
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
618618
}
619619
} else {
620620
assert!(value.is_none(), "`return` and `break` should have a destination");
621+
if self.tcx.sess.instrument_coverage() {
622+
// Unlike `break` and `return`, which push an `Assign` statement to MIR, from which
623+
// a Coverage code region can be generated, `continue` needs no `Assign`; but
624+
// without one, the `InstrumentCoverage` MIR pass cannot generate a code region for
625+
// `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR.
626+
self.add_dummy_assignment(&span, block, source_info);
627+
}
621628
}
622629

623630
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
@@ -643,6 +650,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
643650
self.cfg.start_new_block().unit()
644651
}
645652

653+
// Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue`
654+
// statement.
655+
fn add_dummy_assignment(&mut self, span: &Span, block: BasicBlock, source_info: SourceInfo) {
656+
let local_decl = LocalDecl::new(self.tcx.mk_unit(), *span).internal();
657+
let temp_place = Place::from(self.local_decls.push(local_decl));
658+
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
659+
}
660+
646661
crate fn exit_top_scope(
647662
&mut self,
648663
mut block: BasicBlock,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
1| |#![allow(unused_assignments, unused_variables)]
2+
2| |
3+
3| 1|fn main() {
4+
4| 1| let is_true = std::env::args().len() == 1;
5+
5| 1|
6+
6| 1| let mut x = 0;
7+
7| 11| for _ in 0..10 {
8+
^10
9+
8| 10| match is_true {
10+
9| | true => {
11+
10| 10| continue;
12+
11| | }
13+
12| 0| _ => {
14+
13| 0| x = 1;
15+
14| 0| }
16+
15| 0| }
17+
16| 0| x = 3;
18+
17| | }
19+
18| 11| for _ in 0..10 {
20+
^10
21+
19| 10| match is_true {
22+
20| 0| false => {
23+
21| 0| x = 1;
24+
22| 0| }
25+
23| | _ => {
26+
24| 10| continue;
27+
25| | }
28+
26| | }
29+
27| 0| x = 3;
30+
28| | }
31+
29| 11| for _ in 0..10 {
32+
^10
33+
30| 10| match is_true {
34+
31| 10| true => {
35+
32| 10| x = 1;
36+
33| 10| }
37+
34| | _ => {
38+
35| 0| continue;
39+
36| | }
40+
37| | }
41+
38| 10| x = 3;
42+
39| | }
43+
40| 11| for _ in 0..10 {
44+
^10
45+
41| 10| if is_true {
46+
42| 10| continue;
47+
43| 0| }
48+
44| 0| x = 3;
49+
45| | }
50+
46| 11| for _ in 0..10 {
51+
^10
52+
47| 10| match is_true {
53+
48| 0| false => {
54+
49| 0| x = 1;
55+
50| 0| }
56+
51| 10| _ => {
57+
52| 10| let _ = x;
58+
53| 10| }
59+
54| | }
60+
55| 10| x = 3;
61+
56| | }
62+
57| 1| for _ in 0..10 {
63+
58| 1| match is_true {
64+
59| 0| false => {
65+
60| 0| x = 1;
66+
61| 0| }
67+
62| | _ => {
68+
63| 1| break;
69+
64| | }
70+
65| | }
71+
66| 0| x = 3;
72+
67| | }
73+
68| | let _ = x;
74+
69| 1|}
75+

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
2020
19| 2|}
2121
------------------
22-
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
22+
| used_crate::used_only_from_bin_crate_generic_function::<&str>:
2323
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
2424
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
2525
| 19| 1|}
2626
------------------
27-
| used_crate::used_only_from_bin_crate_generic_function::<&str>:
27+
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
2828
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
2929
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
3030
| 19| 1|}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#![allow(unused_assignments, unused_variables)]
2+
3+
fn main() {
4+
let is_true = std::env::args().len() == 1;
5+
6+
let mut x = 0;
7+
for _ in 0..10 {
8+
match is_true {
9+
true => {
10+
continue;
11+
}
12+
_ => {
13+
x = 1;
14+
}
15+
}
16+
x = 3;
17+
}
18+
for _ in 0..10 {
19+
match is_true {
20+
false => {
21+
x = 1;
22+
}
23+
_ => {
24+
continue;
25+
}
26+
}
27+
x = 3;
28+
}
29+
for _ in 0..10 {
30+
match is_true {
31+
true => {
32+
x = 1;
33+
}
34+
_ => {
35+
continue;
36+
}
37+
}
38+
x = 3;
39+
}
40+
for _ in 0..10 {
41+
if is_true {
42+
continue;
43+
}
44+
x = 3;
45+
}
46+
for _ in 0..10 {
47+
match is_true {
48+
false => {
49+
x = 1;
50+
}
51+
_ => {
52+
let _ = x;
53+
}
54+
}
55+
x = 3;
56+
}
57+
for _ in 0..10 {
58+
match is_true {
59+
false => {
60+
x = 1;
61+
}
62+
_ => {
63+
break;
64+
}
65+
}
66+
x = 3;
67+
}
68+
let _ = x;
69+
}

0 commit comments

Comments
 (0)