Skip to content

Commit 154037f

Browse files
committed
Auto merge of #144783 - folkertdev:loop-match-diverging-loop, r=SparrowLii
fix `#[loop_match]` on diverging loop tracking issue: #132306 fixes #144492 fixes #144493 fixes #144781 this generated invalid MIR before. issue #143806 still has an issue where we assign `state = state` which is invalid in MIR. Fixing that problem is tricky, so I'd like to do that separately. r? `@bjorn3`
2 parents c0bb3b9 + 3e76b58 commit 154037f

File tree

7 files changed

+419
-4
lines changed

7 files changed

+419
-4
lines changed

compiler/rustc_mir_build/src/builder/expr/into.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
293293
this.diverge_from(loop_block);
294294

295295
// Logic for `match`.
296-
let scrutinee_place_builder =
297-
unpack!(body_block = this.as_place_builder(body_block, scrutinee));
298296
let scrutinee_span = this.thir.exprs[scrutinee].span;
297+
let scrutinee_place_builder = unpack!(
298+
body_block = this.lower_scrutinee(body_block, scrutinee, scrutinee_span)
299+
);
300+
299301
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
300302

301303
let mut patterns = Vec::with_capacity(arms.len());
@@ -343,7 +345,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
343345
expr_span,
344346
|this| {
345347
this.lower_match_arms(
346-
destination,
348+
state_place,
347349
scrutinee_place_builder,
348350
scrutinee_span,
349351
arms,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
388388
}
389389

390390
/// Evaluate the scrutinee and add the PlaceMention for it.
391-
fn lower_scrutinee(
391+
pub(crate) fn lower_scrutinee(
392392
&mut self,
393393
mut block: BasicBlock,
394394
scrutinee_id: ExprId,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// MIR for `break_to_block_unit` after built
2+
3+
fn break_to_block_unit() -> u8 {
4+
let mut _0: u8;
5+
let mut _1: i32;
6+
let mut _2: !;
7+
scope 1 {
8+
debug state => _1;
9+
}
10+
11+
bb0: {
12+
StorageLive(_1);
13+
_1 = const 0_i32;
14+
FakeRead(ForLet(None), _1);
15+
StorageLive(_2);
16+
goto -> bb1;
17+
}
18+
19+
bb1: {
20+
falseUnwind -> [real: bb2, unwind: bb10];
21+
}
22+
23+
bb2: {
24+
PlaceMention(_1);
25+
_1 = const 2_i32;
26+
goto -> bb5;
27+
}
28+
29+
bb3: {
30+
FakeRead(ForMatchedPlace(None), _1);
31+
unreachable;
32+
}
33+
34+
bb4: {
35+
goto -> bb6;
36+
}
37+
38+
bb5: {
39+
goto -> bb6;
40+
}
41+
42+
bb6: {
43+
goto -> bb7;
44+
}
45+
46+
bb7: {
47+
goto -> bb1;
48+
}
49+
50+
bb8: {
51+
unreachable;
52+
}
53+
54+
bb9: {
55+
StorageDead(_2);
56+
StorageDead(_1);
57+
return;
58+
}
59+
60+
bb10 (cleanup): {
61+
resume;
62+
}
63+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// MIR for `infinite_a` after built
2+
3+
fn infinite_a(_1: u8) -> () {
4+
debug state => _1;
5+
let mut _0: ();
6+
let mut _2: !;
7+
let _3: u8;
8+
scope 1 {
9+
debug a => _3;
10+
}
11+
12+
bb0: {
13+
StorageLive(_2);
14+
goto -> bb1;
15+
}
16+
17+
bb1: {
18+
falseUnwind -> [real: bb2, unwind: bb7];
19+
}
20+
21+
bb2: {
22+
PlaceMention(_1);
23+
StorageLive(_3);
24+
_3 = copy _1;
25+
_1 = copy _3;
26+
StorageDead(_3);
27+
goto -> bb4;
28+
}
29+
30+
bb3: {
31+
FakeRead(ForMatchedPlace(None), _1);
32+
unreachable;
33+
}
34+
35+
bb4: {
36+
goto -> bb1;
37+
}
38+
39+
bb5: {
40+
unreachable;
41+
}
42+
43+
bb6: {
44+
StorageDead(_2);
45+
return;
46+
}
47+
48+
bb7 (cleanup): {
49+
resume;
50+
}
51+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// skip-filecheck
2+
#![allow(incomplete_features)]
3+
#![feature(loop_match)]
4+
#![crate_type = "lib"]
5+
6+
// Test that a #[loop_match] without an explicit break from the loop generates valid MIR.
7+
8+
enum State {
9+
A,
10+
B,
11+
C,
12+
}
13+
14+
// EMIT_MIR loop_match_diverges.simple.built.after.mir
15+
fn simple(mut state: State) -> State {
16+
#[loop_match]
17+
'a: loop {
18+
state = 'blk: {
19+
match state {
20+
State::A => {
21+
#[const_continue]
22+
break 'blk State::B;
23+
}
24+
State::B => {
25+
if true {
26+
#[const_continue]
27+
break 'blk State::C;
28+
} else {
29+
#[const_continue]
30+
break 'blk State::A;
31+
}
32+
}
33+
State::C => break 'a,
34+
}
35+
};
36+
}
37+
38+
state
39+
}
40+
41+
// EMIT_MIR loop_match_diverges.break_to_block_unit.built.after.mir
42+
#[unsafe(no_mangle)]
43+
fn break_to_block_unit() -> u8 {
44+
let mut state = 0;
45+
#[loop_match]
46+
loop {
47+
state = 'blk: {
48+
match state {
49+
_ => 'b: {
50+
break 'b 2;
51+
}
52+
}
53+
}
54+
}
55+
}
56+
57+
// EMIT_MIR loop_match_diverges.infinite_a.built.after.mir
58+
#[unsafe(no_mangle)]
59+
fn infinite_a(mut state: u8) {
60+
#[loop_match]
61+
loop {
62+
state = 'blk: {
63+
match state {
64+
a => a,
65+
}
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)