Skip to content

Commit 72dbdaf

Browse files
committed
Auto merge of #103208 - cjgillot:match-fake-read, r=oli-obk,RalfJung
Allow partially moved values in match This PR attempts to unify the behaviour between `let _ = PLACE`, `let _: TY = PLACE;` and `match PLACE { _ => {} }`. The logical conclusion is that the `match` version should not check for uninitialised places nor check that borrows are still live. The `match PLACE {}` case is handled by keeping a `FakeRead` in the unreachable fallback case to verify that `PLACE` has a legal value. Schematically, `match PLACE { arms }` in surface rust becomes in MIR: ```rust PlaceMention(PLACE) match PLACE { // Decision tree for the explicit arms arms, // An extra fallback arm _ => { FakeRead(ForMatchedPlace, PLACE); unreachable } } ``` `match *borrow { _ => {} }` continues to check that `*borrow` is live, but does not read the value. `match *borrow {}` both checks that `*borrow` is live, and fake-reads the value. Continuation of ~rust-lang/rust#102256 ~rust-lang/rust#104844 Fixes rust-lang/rust#99180 rust-lang/rust#53114
2 parents d457cfc + 479374f commit 72dbdaf

7 files changed

+89
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Make sure we find these even with many checks disabled.
2+
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
3+
4+
#![allow(unreachable_code)]
5+
#![feature(never_type)]
6+
7+
fn main() {
8+
let p = {
9+
let b = Box::new(42);
10+
&*b as *const i32 as *const !
11+
};
12+
unsafe {
13+
match *p {} //~ ERROR: entering unreachable code
14+
}
15+
panic!("this should never print");
16+
}
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: entering unreachable code
2+
--> $DIR/dangling_pointer_deref_match_never.rs:LL:CC
3+
|
4+
LL | match *p {}
5+
| ^^ entering unreachable code
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/dangling_pointer_deref_match_never.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+

tests/fail/never_match_never.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This should fail even without validation
2+
//@compile-flags: -Zmiri-disable-validation
3+
4+
#![feature(never_type)]
5+
#![allow(unreachable_code)]
6+
7+
fn main() {
8+
let ptr: *const (i32, !) = &0i32 as *const i32 as *const _;
9+
unsafe { match (*ptr).1 {} } //~ ERROR: entering unreachable code
10+
}

tests/fail/never_match_never.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: entering unreachable code
2+
--> $DIR/never_match_never.rs:LL:CC
3+
|
4+
LL | unsafe { match (*ptr).1 {} }
5+
| ^^^^^^^^ entering unreachable code
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/never_match_never.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// A `_` binding in a match is a nop, so we do not detect that the pointer is dangling.
2+
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
3+
4+
fn main() {
5+
let p = {
6+
let b = Box::new(42);
7+
&*b as *const i32
8+
};
9+
unsafe {
10+
match *p {
11+
_ => {}
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn main() {
2+
#[derive(Copy, Clone)]
3+
enum Void {}
4+
union Uninit<T: Copy> {
5+
value: T,
6+
uninit: (),
7+
}
8+
unsafe {
9+
let x: Uninit<Void> = Uninit { uninit: () };
10+
match x.value {
11+
// rustc warns about un unreachable pattern,
12+
// but is wrong in unsafe code.
13+
#[allow(unreachable_patterns)]
14+
_ => println!("hi from the void!"),
15+
}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hi from the void!

0 commit comments

Comments
 (0)