Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 43 additions & 18 deletions compiler/rustc_mir_build/src/builder/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,36 +326,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);

let state_place = scrutinee_place_builder.to_place(this);
let state_result = this.temp(state_ty, expr_span);
let state_result_place = Place::from(state_result);

// This is logic for the labeled block: a block is a drop scope, hence
// `in_scope`, and a labeled block can be broken out of with a `break 'label`,
// hence the `in_breakable_scope`.
//
// The state update is still modeled like `state = 'blk: { ... }`: normal
// match arm results and ordinary breaks to the block are first written to
// `state_result_place`, then written back to `state_place`. This avoids
// building an overlapping assignment like `state = state`.
//
// Then `in_const_continuable_scope` stores information for the lowering of
// `#[const_continue]`, and finally the match is lowered in the standard way.
// `#[const_continue]`, which still updates the actual `state_place` directly
// so it can jump to the statically known next match branch.
unpack!(
body_block = this.in_scope(
(region_scope, source_info),
LintLevel::Inherited,
move |this| {
this.in_breakable_scope(None, state_place, expr_span, |this| {
Some(this.in_const_continuable_scope(
Box::from(arms),
built_tree.clone(),
state_place,
expr_span,
|this| {
this.lower_match_arms(
state_place,
scrutinee_place_builder,
scrutinee_span,
arms,
built_tree,
this.source_info(match_span),
this.in_const_continuable_scope(
Box::from(arms),
built_tree.clone(),
state_place,
expr_span,
|this| {
let block = this
.in_breakable_scope(
None,
state_result_place,
expr_span,
|this| {
Some(this.lower_match_arms(
state_result_place,
scrutinee_place_builder,
scrutinee_span,
arms,
built_tree,
this.source_info(match_span),
))
},
)
},
))
})
.into_block();

this.cfg.push_assign(
block,
source_info,
state_place,
Rvalue::Use(
this.consume_by_copy_or_move(state_result_place),
),
);
block.unit()
},
)
}
)
);
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_mir_transform/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ impl<'a, 'tcx> Lint<'a, 'tcx> {
}
}

/// Checks whether reading `src` while assigning to `dest` would violate MIR's
/// non-overlap requirement for assignments.
fn places_conflict_for_assignment<'tcx>(dest: Place<'tcx>, src: Place<'tcx>) -> bool {
dest == src || (dest.local == src.local && !dest.is_indirect() && !src.is_indirect())
}

impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
if context.is_use() {
Expand Down Expand Up @@ -96,11 +102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
// The sides of an assignment must not alias.
if forbid_aliasing {
VisitPlacesWith(|src: Place<'tcx>, _| {
if *dest == src
|| (dest.local == src.local
&& !dest.is_indirect()
&& !src.is_indirect())
{
if places_conflict_for_assignment(*dest, src) {
self.fail(
location,
format!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ fn break_to_block_unit() -> u8 {
let mut _0: u8;
let mut _1: i32;
let mut _2: !;
let mut _3: i32;
scope 1 {
debug state => _1;
}
Expand All @@ -22,7 +23,7 @@ fn break_to_block_unit() -> u8 {

bb2: {
PlaceMention(_1);
_1 = const 2_i32;
_3 = const 2_i32;
goto -> bb5;
}

Expand All @@ -44,6 +45,7 @@ fn break_to_block_unit() -> u8 {
}

bb7: {
_1 = copy _3;
goto -> bb1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ fn infinite_a(_1: u8) -> () {
debug state => _1;
let mut _0: ();
let mut _2: !;
let _3: u8;
let mut _3: u8;
let _4: u8;
scope 1 {
debug a => _3;
debug a => _4;
}

bb0: {
Expand All @@ -20,10 +21,10 @@ fn infinite_a(_1: u8) -> () {

bb2: {
PlaceMention(_1);
StorageLive(_3);
_3 = copy _1;
_1 = copy _3;
StorageDead(_3);
StorageLive(_4);
_4 = copy _1;
_3 = copy _4;
StorageDead(_4);
goto -> bb4;
}

Expand All @@ -33,6 +34,7 @@ fn infinite_a(_1: u8) -> () {
}

bb4: {
_1 = copy _3;
goto -> bb1;
}

Expand Down
38 changes: 20 additions & 18 deletions tests/mir-opt/building/loop_match_diverges.simple.built.after.mir
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ fn simple(_1: State) -> State {
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: !;
let mut _4: State;
let mut _5: !;
let mut _6: isize;
let mut _7: bool;
let mut _8: !;
let mut _9: isize;
let mut _10: !;
let mut _11: isize;
let mut _12: !;

bb0: {
StorageLive(_2);
Expand Down Expand Up @@ -60,14 +61,14 @@ fn simple(_1: State) -> State {
}

bb10: {
StorageLive(_6);
_6 = const true;
switchInt(move _6) -> [0: bb17, otherwise: bb16];
StorageLive(_7);
_7 = const true;
switchInt(move _7) -> [0: bb17, otherwise: bb16];
}

bb11: {
_1 = State::B;
_5 = discriminant(_1);
_6 = discriminant(_1);
falseEdge -> [real: bb12, imaginary: bb13];
}

Expand All @@ -89,7 +90,7 @@ fn simple(_1: State) -> State {

bb16: {
_1 = State::C;
_8 = discriminant(_1);
_9 = discriminant(_1);
falseEdge -> [real: bb18, imaginary: bb19];
}

Expand All @@ -106,7 +107,7 @@ fn simple(_1: State) -> State {
}

bb20: {
StorageDead(_6);
StorageDead(_7);
goto -> bb8;
}

Expand All @@ -120,7 +121,7 @@ fn simple(_1: State) -> State {

bb23: {
_1 = State::A;
_10 = discriminant(_1);
_11 = discriminant(_1);
falseEdge -> [real: bb24, imaginary: bb25];
}

Expand All @@ -133,7 +134,7 @@ fn simple(_1: State) -> State {
}

bb26: {
StorageDead(_6);
StorageDead(_7);
goto -> bb11;
}

Expand All @@ -146,7 +147,7 @@ fn simple(_1: State) -> State {
}

bb29: {
StorageDead(_6);
StorageDead(_7);
goto -> bb32;
}

Expand All @@ -159,11 +160,12 @@ fn simple(_1: State) -> State {
}

bb32: {
_1 = move _4;
goto -> bb35;
}

bb33: {
StorageDead(_6);
StorageDead(_7);
goto -> bb34;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// MIR for `helper` after built

fn helper() -> u8 {
let mut _0: u8;
let mut _1: u8;
let mut _2: !;
let mut _3: u8;
let mut _4: !;
scope 1 {
debug state => _1;
}

bb0: {
StorageLive(_1);
_1 = const 0_u8;
FakeRead(ForLet(None), _1);
StorageLive(_2);
goto -> bb1;
}

bb1: {
falseUnwind -> [real: bb2, unwind: bb11];
}

bb2: {
PlaceMention(_1);
_3 = copy _1;
goto -> bb7;
}

bb3: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}

bb4: {
unreachable;
}

bb5: {
goto -> bb6;
}

bb6: {
goto -> bb8;
}

bb7: {
goto -> bb8;
}

bb8: {
_1 = copy _3;
goto -> bb1;
}

bb9: {
unreachable;
}

bb10: {
StorageDead(_2);
StorageDead(_1);
return;
}

bb11 (cleanup): {
resume;
}
}
20 changes: 20 additions & 0 deletions tests/mir-opt/building/loop_match_no_self_assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//@ skip-filecheck
#![allow(incomplete_features, unused_labels)]
#![feature(loop_match)]
#![crate_type = "lib"]

// Regression test for <https://github.com/rust-lang/rust/issues/143806>
// This used to avoid building invalid MIR with a self-assignment like `_1 = copy _1`.

// EMIT_MIR loop_match_no_self_assign.helper.built.after.mir
fn helper() -> u8 {
let mut state = 0u8;
#[loop_match]
'a: loop {
state = 'blk: {
match state {
_ => break 'blk state,
}
}
}
Comment thread
cijiugechu marked this conversation as resolved.
}
19 changes: 19 additions & 0 deletions tests/ui/loop-match/no-self-assign-ice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/143806>
//@ check-pass
//@ compile-flags: -Zlint-mir

#![feature(loop_match)]

fn main() {}

fn helper() -> u8 {
let mut state = 0u8;
#[loop_match]
'a: loop {
state = 'blk: {
match state {
_ => break 'blk state,
}
}
}
}
Loading