Skip to content

Commit 32930d9

Browse files
committed
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.
1 parent 78c5644 commit 32930d9

File tree

5 files changed

+88
-3
lines changed

5 files changed

+88
-3
lines changed

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
8585
"consume {:?}; diag_expr_id={:?}, using parent {:?}",
8686
place_with_id, diag_expr_id, parent
8787
);
88-
self.mark_consumed(parent, place_with_id.into());
88+
// We do not currently support partial drops or reinits, so just ignore
89+
// any places with projections.
90+
if place_with_id.place.projections.is_empty() {
91+
self.mark_consumed(parent, place_with_id.into());
92+
}
8993
}
9094

9195
fn borrow(
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// edition:2021
2+
#![feature(negative_impls)]
3+
#![allow(unused)]
4+
5+
fn main() {
6+
gimme_send(foo());
7+
//~^ ERROR cannot be sent between threads safely
8+
}
9+
10+
fn gimme_send<T: Send>(t: T) {
11+
drop(t);
12+
}
13+
14+
struct NotSend {}
15+
16+
impl Drop for NotSend {
17+
fn drop(&mut self) {}
18+
}
19+
20+
impl !Send for NotSend {}
21+
22+
async fn foo() {
23+
let mut x = (NotSend {},);
24+
drop(x.0);
25+
x.0 = NotSend {};
26+
bar().await;
27+
}
28+
29+
async fn bar() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0277]: `NotSend` cannot be sent between threads safely
2+
--> $DIR/partial-drop-partial-reinit.rs:6:16
3+
|
4+
LL | gimme_send(foo());
5+
| ---------- ^^^^^ `NotSend` cannot be sent between threads safely
6+
| |
7+
| required by a bound introduced by this call
8+
...
9+
LL | async fn foo() {
10+
| - within this `impl Future<Output = ()>`
11+
|
12+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
13+
= note: required because it appears within the type `(NotSend,)`
14+
= note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
15+
= note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
16+
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
17+
= note: required because it appears within the type `impl Future<Output = [async output]>`
18+
= note: required because it appears within the type `impl Future<Output = ()>`
19+
note: required by a bound in `gimme_send`
20+
--> $DIR/partial-drop-partial-reinit.rs:10:18
21+
|
22+
LL | fn gimme_send<T: Send>(t: T) {
23+
| ^^^^ required by this bound in `gimme_send`
24+
25+
error: aborting due to previous error
26+
27+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/generator/partial-drop.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// check-pass
2-
31
#![feature(negative_impls, generators)]
42

53
struct Foo;
@@ -12,6 +10,8 @@ struct Bar {
1210

1311
fn main() {
1412
assert_send(|| {
13+
//~^ ERROR generator cannot be sent between threads safely
14+
// FIXME: it would be nice to make this work.
1515
let guard = Bar { foo: Foo, x: 42 };
1616
drop(guard.foo);
1717
yield;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: generator cannot be sent between threads safely
2+
--> $DIR/partial-drop.rs:12:5
3+
|
4+
LL | assert_send(|| {
5+
| ^^^^^^^^^^^ generator is not `Send`
6+
|
7+
= help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
8+
note: generator is not `Send` as this value is used across a yield
9+
--> $DIR/partial-drop.rs:17:9
10+
|
11+
LL | let guard = Bar { foo: Foo, x: 42 };
12+
| ----- has type `Bar` which is not `Send`
13+
LL | drop(guard.foo);
14+
LL | yield;
15+
| ^^^^^ yield occurs here, with `guard` maybe used later
16+
LL | })
17+
| - `guard` is later dropped here
18+
note: required by a bound in `assert_send`
19+
--> $DIR/partial-drop.rs:21:19
20+
|
21+
LL | fn assert_send<T: Send>(_: T) {}
22+
| ^^^^ required by this bound in `assert_send`
23+
24+
error: aborting due to previous error
25+

0 commit comments

Comments
 (0)