about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Holk <ericholk@microsoft.com>2022-01-05 14:11:37 -0800
committerEric Holk <ericholk@microsoft.com>2022-01-18 14:25:30 -0800
commit32930d9ea7cc79239daa19a040cbae9867053af8 (patch)
tree1fac2ecc51a35832b9c8f968ee19c53d6892be98
parent78c5644de5ffea9d64200bd28eac7e49ca2c8f33 (diff)
downloadrust-32930d9ea7cc79239daa19a040cbae9867053af8.tar.gz
rust-32930d9ea7cc79239daa19a040cbae9867053af8.zip
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.
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs6
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.rs29
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.stderr27
-rw-r--r--src/test/ui/generator/partial-drop.rs4
-rw-r--r--src/test/ui/generator/partial-drop.stderr25
5 files changed, 88 insertions, 3 deletions
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index 2548b608092..845cd01a44e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -85,7 +85,11 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
             "consume {:?}; diag_expr_id={:?}, using 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(
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs
new file mode 100644
index 00000000000..73f0ca8153c
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs
@@ -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() {}
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
new file mode 100644
index 00000000000..2097642eb24
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
@@ -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`.
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
index a2f616aa313..c8c07ba41c7 100644
--- a/src/test/ui/generator/partial-drop.rs
+++ b/src/test/ui/generator/partial-drop.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(negative_impls, generators)]
 
 struct Foo;
@@ -12,6 +10,8 @@ struct Bar {
 
 fn main() {
     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 };
         drop(guard.foo);
         yield;
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
new file mode 100644
index 00000000000..93112f52208
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -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
+