Skip to content

Commit 448e52d

Browse files
committed
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.
1 parent 83ca4b7 commit 448e52d

File tree

5 files changed

+160
-2
lines changed

5 files changed

+160
-2
lines changed

compiler/rustc_mir_build/src/build/scope.rs

+10
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
618618
}
619619
} else {
620620
assert!(value.is_none(), "`return` and `break` should have a destination");
621+
// `continue` statements generate no MIR statement with the `continue` statement's Span,
622+
// and the `InstrumentCoverage` statement will have no way to generate a coverage
623+
// code region for the `continue` statement, unless we add a dummy `Assign` here:
624+
let mut local_decl = LocalDecl::new(self.tcx.mk_unit(), span);
625+
local_decl = local_decl.immutable();
626+
let temp = self.local_decls.push(local_decl);
627+
let temp_place = Place::from(temp);
628+
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
629+
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
630+
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(temp) });
621631
}
622632

623633
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;

src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ fn main() -> () {
88
let mut _4: !; // in scope 0 at $DIR/loop_test.rs:13:5: 16:6
99
let mut _5: (); // in scope 0 at $DIR/loop_test.rs:6:1: 17:2
1010
let _6: i32; // in scope 0 at $DIR/loop_test.rs:14:13: 14:14
11+
let _7: (); // in scope 0 at $DIR/loop_test.rs:15:9: 15:17
1112
scope 1 {
1213
debug x => _6; // in scope 1 at $DIR/loop_test.rs:14:13: 14:14
1314
}
@@ -42,6 +43,9 @@ fn main() -> () {
4243
StorageLive(_6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
4344
_6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18
4445
FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
46+
StorageLive(_7); // scope 1 at $DIR/loop_test.rs:15:9: 15:17
47+
_7 = const (); // scope 1 at $DIR/loop_test.rs:15:9: 15:17
48+
StorageDead(_7); // scope 1 at $DIR/loop_test.rs:15:9: 15:17
4549
StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6
4650
goto -> bb3; // scope 0 at $DIR/loop_test.rs:1:1: 1:1
4751
}
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)