mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 04:08:40 +00:00
Safely handle partial drops
We previously weren't tracking partial re-inits while being too aggressive around partial drops. With this change, we simply ignore partial drops, which is the safer, more conservative choice.
This commit is contained in:
parent
78c5644de5
commit
32930d9ea7
@ -85,7 +85,11 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
|
|||||||
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
|
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
|
||||||
place_with_id, diag_expr_id, parent
|
place_with_id, diag_expr_id, parent
|
||||||
);
|
);
|
||||||
self.mark_consumed(parent, place_with_id.into());
|
// We do not currently support partial drops or reinits, so just ignore
|
||||||
|
// any places with projections.
|
||||||
|
if place_with_id.place.projections.is_empty() {
|
||||||
|
self.mark_consumed(parent, place_with_id.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrow(
|
fn borrow(
|
||||||
|
29
src/test/ui/async-await/partial-drop-partial-reinit.rs
Normal file
29
src/test/ui/async-await/partial-drop-partial-reinit.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// edition:2021
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
gimme_send(foo());
|
||||||
|
//~^ ERROR cannot be sent between threads safely
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gimme_send<T: Send>(t: T) {
|
||||||
|
drop(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NotSend {}
|
||||||
|
|
||||||
|
impl Drop for NotSend {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl !Send for NotSend {}
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
let mut x = (NotSend {},);
|
||||||
|
drop(x.0);
|
||||||
|
x.0 = NotSend {};
|
||||||
|
bar().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bar() {}
|
27
src/test/ui/async-await/partial-drop-partial-reinit.stderr
Normal file
27
src/test/ui/async-await/partial-drop-partial-reinit.stderr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
error[E0277]: `NotSend` cannot be sent between threads safely
|
||||||
|
--> $DIR/partial-drop-partial-reinit.rs:6:16
|
||||||
|
|
|
||||||
|
LL | gimme_send(foo());
|
||||||
|
| ---------- ^^^^^ `NotSend` cannot be sent between threads safely
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
...
|
||||||
|
LL | async fn foo() {
|
||||||
|
| - within this `impl Future<Output = ()>`
|
||||||
|
|
|
||||||
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
|
||||||
|
= note: required because it appears within the type `(NotSend,)`
|
||||||
|
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
|
||||||
|
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
|
||||||
|
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
|
||||||
|
= note: required because it appears within the type `impl Future<Output = [async output]>`
|
||||||
|
= note: required because it appears within the type `impl Future<Output = ()>`
|
||||||
|
note: required by a bound in `gimme_send`
|
||||||
|
--> $DIR/partial-drop-partial-reinit.rs:10:18
|
||||||
|
|
|
||||||
|
LL | fn gimme_send<T: Send>(t: T) {
|
||||||
|
| ^^^^ required by this bound in `gimme_send`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -1,5 +1,3 @@
|
|||||||
// check-pass
|
|
||||||
|
|
||||||
#![feature(negative_impls, generators)]
|
#![feature(negative_impls, generators)]
|
||||||
|
|
||||||
struct Foo;
|
struct Foo;
|
||||||
@ -12,6 +10,8 @@ struct Bar {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_send(|| {
|
assert_send(|| {
|
||||||
|
//~^ ERROR generator cannot be sent between threads safely
|
||||||
|
// FIXME: it would be nice to make this work.
|
||||||
let guard = Bar { foo: Foo, x: 42 };
|
let guard = Bar { foo: Foo, x: 42 };
|
||||||
drop(guard.foo);
|
drop(guard.foo);
|
||||||
yield;
|
yield;
|
||||||
|
25
src/test/ui/generator/partial-drop.stderr
Normal file
25
src/test/ui/generator/partial-drop.stderr
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
error: generator cannot be sent between threads safely
|
||||||
|
--> $DIR/partial-drop.rs:12:5
|
||||||
|
|
|
||||||
|
LL | assert_send(|| {
|
||||||
|
| ^^^^^^^^^^^ generator is not `Send`
|
||||||
|
|
|
||||||
|
= help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
|
||||||
|
note: generator is not `Send` as this value is used across a yield
|
||||||
|
--> $DIR/partial-drop.rs:17:9
|
||||||
|
|
|
||||||
|
LL | let guard = Bar { foo: Foo, x: 42 };
|
||||||
|
| ----- has type `Bar` which is not `Send`
|
||||||
|
LL | drop(guard.foo);
|
||||||
|
LL | yield;
|
||||||
|
| ^^^^^ yield occurs here, with `guard` maybe used later
|
||||||
|
LL | })
|
||||||
|
| - `guard` is later dropped here
|
||||||
|
note: required by a bound in `assert_send`
|
||||||
|
--> $DIR/partial-drop.rs:21:19
|
||||||
|
|
|
||||||
|
LL | fn assert_send<T: Send>(_: T) {}
|
||||||
|
| ^^^^ required by this bound in `assert_send`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Reference in New Issue
Block a user