diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 82b883a99a11c..78bcc47d9d0de 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -295,9 +295,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(loop_block); // Logic for `match`. - let scrutinee_place_builder = - unpack!(body_block = this.as_place_builder(body_block, scrutinee)); let scrutinee_span = this.thir.exprs[scrutinee].span; + let scrutinee_place_builder = unpack!( + body_block = this.lower_scrutinee(body_block, scrutinee, scrutinee_span) + ); + let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); @@ -345,7 +347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, |this| { this.lower_match_arms( - destination, + state_place, scrutinee_place_builder, scrutinee_span, arms, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2c29b8628417f..e863f94af7ea0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -407,7 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Evaluate the scrutinee and add the PlaceMention for it. - fn lower_scrutinee( + pub(crate) fn lower_scrutinee( &mut self, mut block: BasicBlock, scrutinee_id: ExprId, diff --git a/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir new file mode 100644 index 0000000000000..6d779e46146c7 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir @@ -0,0 +1,63 @@ +// MIR for `break_to_block_unit` after built + +fn break_to_block_unit() -> u8 { + let mut _0: u8; + let mut _1: i32; + let mut _2: !; + scope 1 { + debug state => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + FakeRead(ForLet(None), _1); + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb10]; + } + + bb2: { + PlaceMention(_1); + _1 = const 2_i32; + goto -> bb5; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb6; + } + + bb5: { + goto -> bb6; + } + + bb6: { + goto -> bb7; + } + + bb7: { + goto -> bb1; + } + + bb8: { + unreachable; + } + + bb9: { + StorageDead(_2); + StorageDead(_1); + return; + } + + bb10 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir new file mode 100644 index 0000000000000..e3766744790be --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir @@ -0,0 +1,51 @@ +// MIR for `infinite_a` after built + +fn infinite_a(_1: u8) -> () { + debug state => _1; + let mut _0: (); + let mut _2: !; + let _3: u8; + scope 1 { + debug a => _3; + } + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb7]; + } + + bb2: { + PlaceMention(_1); + StorageLive(_3); + _3 = copy _1; + _1 = copy _3; + StorageDead(_3); + goto -> bb4; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb1; + } + + bb5: { + unreachable; + } + + bb6: { + StorageDead(_2); + return; + } + + bb7 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.rs b/tests/mir-opt/building/loop_match_diverges.rs new file mode 100644 index 0000000000000..774e195c33c96 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.rs @@ -0,0 +1,68 @@ +// skip-filecheck +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +enum State { + A, + B, + C, +} + +// EMIT_MIR loop_match_diverges.simple.built.after.mir +fn simple(mut state: State) -> State { + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + State::A => { + #[const_continue] + break 'blk State::B; + } + State::B => { + if true { + #[const_continue] + break 'blk State::C; + } else { + #[const_continue] + break 'blk State::A; + } + } + State::C => break 'a, + } + }; + } + + state +} + +// EMIT_MIR loop_match_diverges.break_to_block_unit.built.after.mir +#[unsafe(no_mangle)] +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +// EMIT_MIR loop_match_diverges.infinite_a.built.after.mir +#[unsafe(no_mangle)] +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir new file mode 100644 index 0000000000000..26476ad776274 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir @@ -0,0 +1,187 @@ +// MIR for `simple` after built + +fn simple(_1: State) -> State { + debug state => _1; + let mut _0: State; + let _2: (); + let mut _3: isize; + let mut _4: !; + let mut _5: isize; + let mut _6: bool; + let mut _7: !; + let mut _8: isize; + let mut _9: !; + let mut _10: isize; + let mut _11: !; + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb37]; + } + + bb2: { + PlaceMention(_1); + _3 = discriminant(_1); + switchInt(move _3) -> [0: bb4, 1: bb6, 2: bb8, otherwise: bb3]; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + falseEdge -> [real: bb11, imaginary: bb6]; + } + + bb5: { + goto -> bb3; + } + + bb6: { + falseEdge -> [real: bb10, imaginary: bb8]; + } + + bb7: { + goto -> bb3; + } + + bb8: { + _2 = const (); + goto -> bb36; + } + + bb9: { + goto -> bb3; + } + + bb10: { + StorageLive(_6); + _6 = const true; + switchInt(move _6) -> [0: bb17, otherwise: bb16]; + } + + bb11: { + _1 = State::B; + _5 = discriminant(_1); + falseEdge -> [real: bb12, imaginary: bb13]; + } + + bb12: { + goto -> bb10; + } + + bb13: { + goto -> bb34; + } + + bb14: { + unreachable; + } + + bb15: { + goto -> bb32; + } + + bb16: { + _1 = State::C; + _8 = discriminant(_1); + falseEdge -> [real: bb18, imaginary: bb19]; + } + + bb17: { + goto -> bb23; + } + + bb18: { + goto -> bb20; + } + + bb19: { + goto -> bb33; + } + + bb20: { + StorageDead(_6); + goto -> bb8; + } + + bb21: { + unreachable; + } + + bb22: { + goto -> bb29; + } + + bb23: { + _1 = State::A; + _10 = discriminant(_1); + falseEdge -> [real: bb24, imaginary: bb25]; + } + + bb24: { + goto -> bb26; + } + + bb25: { + goto -> bb33; + } + + bb26: { + StorageDead(_6); + goto -> bb11; + } + + bb27: { + unreachable; + } + + bb28: { + goto -> bb29; + } + + bb29: { + StorageDead(_6); + goto -> bb32; + } + + bb30: { + unreachable; + } + + bb31: { + goto -> bb32; + } + + bb32: { + goto -> bb35; + } + + bb33: { + StorageDead(_6); + goto -> bb34; + } + + bb34: { + goto -> bb35; + } + + bb35: { + goto -> bb1; + } + + bb36: { + StorageDead(_2); + _0 = move _1; + return; + } + + bb37 (cleanup): { + resume; + } +} diff --git a/tests/ui/loop-match/diverges.rs b/tests/ui/loop-match/diverges.rs new file mode 100644 index 0000000000000..f1b3ffb2076bd --- /dev/null +++ b/tests/ui/loop-match/diverges.rs @@ -0,0 +1,44 @@ +//@ build-pass +//@ compile-flags: -Zvalidate-mir +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +fn break_to_block_value() -> u8 { + let mut state = 0u8; + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + _ => break 'blk state, + } + } + } +} + +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +}