about summary refs log tree commit diff
diff options
context:
space:
mode:
author1000teslas <47207223+1000teslas@users.noreply.github.com>2021-01-02 22:03:21 +1100
committer1000teslas <47207223+1000teslas@users.noreply.github.com>2021-01-10 16:47:40 +1100
commit5ccef564560df65db0cb761cb27751f15821f1af (patch)
tree39c668fd481b24801f1c91d5b23e227aa482fa67
parentef589490a709984d3be80c9b59a1a10a4dd05e3c (diff)
downloadrust-5ccef564560df65db0cb761cb27751f15821f1af.tar.gz
rust-5ccef564560df65db0cb761cb27751f15821f1af.zip
Explain why borrows can't be held across yield point in async blocks
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs10
-rw-r--r--src/test/ui/async-await/issues/issue-78938-async-block.rs33
-rw-r--r--src/test/ui/async-await/issues/issue-78938-async-block.stderr30
3 files changed, 73 insertions, 0 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 0bb09e26f03..1dd102f4f34 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -1323,6 +1323,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             suggestion,
             Applicability::MachineApplicable,
         );
+        if let Some(generator_kind) = use_span.generator_kind() {
+            if let GeneratorKind::Async(_) = generator_kind {
+                err.note(
+            "borrows cannot be held across a yield point, because the stack space of the current \
+            function is not preserved",
+        );
+                err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \
+        for more information");
+            }
+        }
 
         let msg = match category {
             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs
new file mode 100644
index 00000000000..e3d8eb73772
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs
@@ -0,0 +1,33 @@
+// edition:2018
+
+use std::{sync::Arc, future::Future, pin::Pin, task::{Context,Poll}};
+
+async fn f() {
+    let room_ref = Arc::new(Vec::new());
+
+    let gameloop_handle = spawn(async { //~ ERROR E0373
+        game_loop(Arc::clone(&room_ref))
+    });
+    gameloop_handle.await;
+}
+
+fn game_loop(v: Arc<Vec<usize>>) {}
+
+fn spawn<F>(future: F) -> JoinHandle
+where
+    F: Future + Send + 'static,
+    F::Output: Send + 'static,  
+{
+    loop {}
+}
+
+struct JoinHandle;
+
+impl Future for JoinHandle {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        loop {}
+    }
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr
new file mode 100644
index 00000000000..83cf1a5bc46
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr
@@ -0,0 +1,30 @@
+error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function
+  --> $DIR/issue-78938-async-block.rs:8:39
+   |
+LL |       let gameloop_handle = spawn(async {
+   |  _______________________________________^
+LL | |         game_loop(Arc::clone(&room_ref))
+   | |                               -------- `room_ref` is borrowed here
+LL | |     });
+   | |_____^ may outlive borrowed value `room_ref`
+   |
+   = note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved
+   = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information
+note: function requires argument type to outlive `'static`
+  --> $DIR/issue-78938-async-block.rs:8:33
+   |
+LL |       let gameloop_handle = spawn(async {
+   |  _________________________________^
+LL | |         game_loop(Arc::clone(&room_ref))
+LL | |     });
+   | |_____^
+help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword
+   |
+LL |     let gameloop_handle = spawn(async move {
+LL |         game_loop(Arc::clone(&room_ref))
+LL |     });
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.