-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Make closure capturing have consistent and correct behaviour around patterns #138961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2759284
647e8bd
f4fc4a7
af3aaba
00a0e86
972b851
5f73b21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// This test serves to document the change in semantics introduced by #138961. | ||
// | ||
// A corollary of partial-pattern.rs: while the tuple access showcases the | ||
// utility, it is actually the dereference performed by the pattern that | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The utility of what? |
||
// matters. | ||
|
||
fn main() { | ||
// the inner reference is dangling | ||
let x: &&u32 = unsafe { | ||
let x: u32 = 42; | ||
&&* &raw const x | ||
}; | ||
|
||
let _ = || { //~ ERROR: encountered a dangling reference | ||
match x { | ||
&&_y => {}, | ||
} | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) | ||
--> tests/fail/upvars/deref-in-pattern.rs:LL:CC | ||
| | ||
LL | let _ = || { | ||
| _____________^ | ||
LL | | match x { | ||
LL | | &&_y => {}, | ||
LL | | } | ||
LL | | }; | ||
| |_____^ constructing invalid value: encountered a dangling reference (use-after-free) | ||
| | ||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | ||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | ||
= note: BACKTRACE: | ||
= note: inside `main` at tests/fail/upvars/deref-in-pattern.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,27 @@ | ||||||
// This test serves to document the change in semantics introduced by #138961. | ||||||
// | ||||||
// Previously, the closure would capture the entirety of x, and access *(*x).0 | ||||||
// when called. Now, the closure only captures *(*x).0, which means that | ||||||
// a &*(*x).0 reborrow happens when the closure is constructed. | ||||||
// | ||||||
// Hence, if one of the references is dangling, this constitutes newly introduced UB | ||||||
// in the case where the closure doesn't get called. This isn't a big deal, | ||||||
// because why opsem only now considers this to be UB, the unsafe code | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// guidelines have long recommended against any handling of dangling references. | ||||||
|
||||||
fn main() { | ||||||
// the inner references are dangling | ||||||
let x: &(&u32, &u32) = unsafe { | ||||||
let a = 21; | ||||||
let b = 37; | ||||||
let ra = &* &raw const a; | ||||||
let rb = &* &raw const b; | ||||||
&(ra, rb) | ||||||
}; | ||||||
|
||||||
let _ = || { //~ ERROR: encountered a dangling reference | ||||||
match x { | ||||||
(&_y, _) => {}, | ||||||
} | ||||||
}; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) | ||
--> tests/fail/upvars/partial-pattern.rs:LL:CC | ||
| | ||
LL | let _ = || { | ||
| _____________^ | ||
LL | | match x { | ||
LL | | (&_y, _) => {}, | ||
LL | | } | ||
LL | | }; | ||
| |_____^ constructing invalid value: encountered a dangling reference (use-after-free) | ||
| | ||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | ||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | ||
= note: BACKTRACE: | ||
= note: inside `main` at tests/fail/upvars/partial-pattern.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Motivated by #138961, this shows how invalid discriminants interact with | ||
// closure captures. | ||
#![feature(never_type)] | ||
|
||
#[repr(C)] | ||
#[allow(dead_code)] | ||
enum E { | ||
V0, // discriminant: 0 | ||
V1, // 1 | ||
V2(!), // 2 | ||
} | ||
|
||
fn main() { | ||
assert_eq!(std::mem::size_of::<E>(), 4); | ||
|
||
let val = 2u32; | ||
let ptr = (&raw const val).cast::<E>(); | ||
let r = unsafe { &*ptr }; | ||
let f = || { | ||
// After #138961, constructing the closure performs a reborrow of r. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since these are issue numbers in the rustc repo, but these tests will be mirrored to the Miri repo, please use full URLs instead of just issue numbers to avoid any ambiguity. |
||
// Nevertheless, the discriminant is only actually inspected when the closure | ||
// is called. | ||
match r { //~ ERROR: read discriminant of an uninhabited enum variant | ||
E::V0 => {} | ||
E::V1 => {} | ||
E::V2(_) => {} | ||
} | ||
}; | ||
|
||
f(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
error: Undefined Behavior: read discriminant of an uninhabited enum variant | ||
--> tests/fail/upvars/uninhabited-variant.rs:LL:CC | ||
| | ||
LL | match r { | ||
| ^ read discriminant of an uninhabited enum variant | ||
| | ||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | ||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | ||
= note: BACKTRACE: | ||
= note: inside closure at tests/fail/upvars/uninhabited-variant.rs:LL:CC | ||
note: inside `main` | ||
--> tests/fail/upvars/uninhabited-variant.rs:LL:CC | ||
| | ||
LL | f(); | ||
| ^^^ | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
//@ known-bug: #119786 | ||
//@ edition:2021 | ||
|
||
fn enum_upvar() { | ||
type T = impl Copy; | ||
let foo: T = Some((1u32, 2u32)); | ||
let x = move || { | ||
match foo { | ||
None => (), | ||
Some(_) => (), | ||
} | ||
}; | ||
} | ||
|
||
pub fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
//@ known-bug: #119786 | ||
//@ edition:2021 | ||
|
||
fn enum_upvar() { | ||
type T = impl Copy; | ||
let foo: T = Some((1u32, 2u32)); | ||
let x = move || { | ||
match foo { | ||
None => (), | ||
Some((a, b)) => (), | ||
} | ||
}; | ||
} | ||
|
||
pub fn main() {} |
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename the folder to
closures
or so, "upvars" is a very much rustc-internal jargon.