Skip to content
Open
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
6 changes: 6 additions & 0 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2462,8 +2462,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug!("Exiting guard building context with locals: {:?}", guard_frame);

for &(_, temp, _) in fake_borrows {
// We put fake reads of fake borrows on the guard's failure path to make sure
// they're reachable if we continue matching (#161578) and we put them on the
// success path to make sure we can create by-value bindings. This won't keep fake
// borrows live on paths where the guard diverges unconditionally, but that should
// be sound since we can't continue matching or make bindings after diverging.
let cause = FakeReadCause::ForMatchGuard;
self.cfg.push_fake_read(guard_true_block, guard_end, cause, Place::from(temp));
self.cfg.push_fake_read(guard_false_block, guard_end, cause, Place::from(temp));
}

self.cfg.goto(guard_false_block, source_info, sub_branch.otherwise_block);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ fn full_tested_match() -> () {
bb13: {
StorageDead(_7);
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
goto -> bb9;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ fn full_tested_match2() -> () {
bb13: {
StorageDead(_7);
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
goto -> bb9;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ fn main() -> () {
bb17: {
StorageDead(_8);
StorageDead(_7);
FakeRead(ForMatchGuard, _3);
goto -> bb13;
}

Expand Down Expand Up @@ -165,6 +166,7 @@ fn main() -> () {
StorageDead(_13);
StorageDead(_12);
StorageDead(_11);
FakeRead(ForMatchGuard, _3);
goto -> bb10;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ fn constant_eq(_1: &str, _2: bool) -> u32 {

bb17: {
StorageDead(_13);
FakeRead(ForMatchGuard, _6);
FakeRead(ForMatchGuard, _7);
FakeRead(ForMatchGuard, _8);
falseEdge -> [real: bb3, imaginary: bb5];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 {

bb13: {
StorageDead(_8);
FakeRead(ForMatchGuard, _3);
falseEdge -> [real: bb1, imaginary: bb3];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ yields ()

bb9: {
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
FakeRead(ForMatchGuard, _4);
goto -> bb6;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ yields ()

bb5: {
StorageDead(_6);
FakeRead(ForMatchGuard, _3);
FakeRead(ForMatchGuard, _4);
falseEdge -> [real: bb1, imaginary: bb1];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- falseEdge -> [real: bb3, imaginary: bb3];
+ goto -> bb2;
}
Expand Down Expand Up @@ -194,6 +196,8 @@
StorageDead(_12);
StorageDead(_8);
StorageDead(_6);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- falseEdge -> [real: bb1, imaginary: bb1];
+ goto -> bb1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@
StorageDead(_9);
StorageDead(_8);
StorageDead(_6);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- falseEdge -> [real: bb3, imaginary: bb3];
+ goto -> bb2;
}
Expand Down Expand Up @@ -194,6 +196,8 @@
StorageDead(_12);
StorageDead(_8);
StorageDead(_6);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- falseEdge -> [real: bb1, imaginary: bb1];
+ goto -> bb1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,15 @@

bb6: {
StorageDead(_8);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- FakeRead(ForMatchGuard, _5);
- FakeRead(ForMatchGuard, _6);
- falseEdge -> [real: bb1, imaginary: bb1];
+ nop;
+ nop;
+ nop;
+ nop;
+ goto -> bb1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,15 @@

bb6: {
StorageDead(_8);
- FakeRead(ForMatchGuard, _3);
- FakeRead(ForMatchGuard, _4);
- FakeRead(ForMatchGuard, _5);
- FakeRead(ForMatchGuard, _6);
- falseEdge -> [real: bb1, imaginary: bb1];
+ nop;
+ nop;
+ nop;
+ nop;
+ goto -> bb1;
}

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/match/divergent-guard-soundness-failure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/161578>: the fake borrow on `x`
//! below was ignored previously because the fake read keeping it live was unreachable.

fn main() {
let mut x: Option<Box<u64>> = Some(Box::new(7));
match x {
Some(_) if { x = None; false } && return => {}
//~^ ERROR: cannot assign `x` in match guard
Some(_) if { x = None; false } || return => {}
//~^ ERROR: cannot assign `x` in match guard
Some(_) if false && ({ x = None; false } || return) => {}
//~^ ERROR: cannot assign `x` in match guard
Some(b) => println!("{b}"),
None => println!("none"),
}
}
29 changes: 29 additions & 0 deletions tests/ui/match/divergent-guard-soundness-failure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0510]: cannot assign `x` in match guard
--> $DIR/divergent-guard-soundness-failure.rs:7:22
|
LL | match x {
| - value is immutable in match guard
LL | Some(_) if { x = None; false } && return => {}
| ^ cannot assign

error[E0510]: cannot assign `x` in match guard
--> $DIR/divergent-guard-soundness-failure.rs:9:22
|
LL | match x {
| - value is immutable in match guard
...
LL | Some(_) if { x = None; false } || return => {}
| ^ cannot assign

error[E0510]: cannot assign `x` in match guard
--> $DIR/divergent-guard-soundness-failure.rs:11:32
|
LL | match x {
| - value is immutable in match guard
...
LL | Some(_) if false && ({ x = None; false } || return) => {}
| ^ cannot assign

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0510`.
15 changes: 15 additions & 0 deletions tests/ui/match/divergent-guard-soundness-success.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Test to document strange behavior related to <https://github.com/rust-lang/rust/issues/161578>:
//! in these gaurds, the guard's success and failures are both unreachable after mutating `x`. This
//! means the fake reads on the fake borrow on `x` are unreachable when assigning to `x`, so `x` can
//! be overwritten. This is fine since we don't create bindings and don't continue matching.
//@ check-pass

fn main() {
let mut x: Option<&u64> = Some(&7);
match x {
Some(&y) if { x = None; return } => {}
Some(&y) if true || { x = None; return } => {}
Some(b) => println!("{b}"),
None => println!("none"),
}
}
Loading