about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs30
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0626.md32
-rw-r--r--tests/ui/coroutine/coroutine-with-nll.stderr8
-rw-r--r--tests/ui/coroutine/issue-48048.stderr8
-rw-r--r--tests/ui/coroutine/pattern-borrow.stderr7
-rw-r--r--tests/ui/coroutine/self_referential_gen_block.stderr3
-rw-r--r--tests/ui/coroutine/yield-in-args.stderr8
-rw-r--r--tests/ui/coroutine/yield-while-iterating.stderr7
-rw-r--r--tests/ui/coroutine/yield-while-local-borrowed.stderr15
-rw-r--r--tests/ui/nll/issue-55850.stderr8
10 files changed, 115 insertions, 11 deletions
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 8eb44458137..80deea14685 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -1,7 +1,9 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use rustc_errors::Applicability;
 use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle};
+use rustc_hir as hir;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -382,13 +384,35 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         yield_span: Span,
     ) -> Diag<'infcx> {
         let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
-        struct_span_code_err!(
+        let mut diag = struct_span_code_err!(
             self.dcx(),
             span,
             E0626,
             "borrow may still be in use when {coroutine_kind:#} yields",
-        )
-        .with_span_label(yield_span, "possible yield occurs here")
+        );
+        diag.span_label(
+            self.infcx.tcx.def_span(self.body.source.def_id()),
+            format!("within this {coroutine_kind:#}"),
+        );
+        diag.span_label(yield_span, "possible yield occurs here");
+        if matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)) {
+            let hir::Closure { capture_clause, fn_decl_span, .. } = self
+                .infcx
+                .tcx
+                .hir_node_by_def_id(self.body.source.def_id().expect_local())
+                .expect_closure();
+            let span = match capture_clause {
+                rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(),
+                rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(),
+            };
+            diag.span_suggestion_verbose(
+                span,
+                "add `static` to mark this coroutine as unmovable",
+                "static ",
+                Applicability::MaybeIncorrect,
+            );
+        }
+        diag
     }
 
     pub(crate) fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> Diag<'infcx> {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0626.md b/compiler/rustc_error_codes/src/error_codes/E0626.md
index 28d543350ff..71c1f811aa7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0626.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0626.md
@@ -1,4 +1,4 @@
-This error occurs because a borrow in a coroutine persists across a
+This error occurs because a borrow in a movable coroutine persists across a
 yield point.
 
 Erroneous code example:
@@ -15,19 +15,35 @@ let mut b = #[coroutine] || {
 Pin::new(&mut b).resume(());
 ```
 
-At present, it is not permitted to have a yield that occurs while a
-borrow is still in scope. To resolve this error, the borrow must
-either be "contained" to a smaller scope that does not overlap the
-yield or else eliminated in another way. So, for example, we might
-resolve the previous example by removing the borrow and just storing
-the integer by value:
+Coroutines may be either unmarked, or marked with `static`. If it is unmarked,
+then the coroutine is considered "movable". At present, it is not permitted to
+have a yield in a movable coroutine that occurs while a borrow is still in
+scope. To resolve this error, the coroutine may be marked `static`:
+
+```
+# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
+# use std::ops::Coroutine;
+# use std::pin::Pin;
+let mut b = #[coroutine] static || { // <-- note the static keyword
+    let a = &String::from("hello, world");
+    yield ();
+    println!("{}", a);
+};
+let mut b = std::pin::pin!(b);
+b.as_mut().resume(());
+```
+
+If the coroutine must remain movable, for example to be used as `Unpin`
+without pinning it on the stack or in an allocation, we can alternatively
+resolve the previous example by removing the borrow and just storing the
+type by value:
 
 ```
 # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
 # use std::ops::Coroutine;
 # use std::pin::Pin;
 let mut b = #[coroutine] || {
-    let a = 3;
+    let a = String::from("hello, world");
     yield ();
     println!("{}", a);
 };
diff --git a/tests/ui/coroutine/coroutine-with-nll.stderr b/tests/ui/coroutine/coroutine-with-nll.stderr
index 3f3d51da311..ee3a8f45f44 100644
--- a/tests/ui/coroutine/coroutine-with-nll.stderr
+++ b/tests/ui/coroutine/coroutine-with-nll.stderr
@@ -1,11 +1,19 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/coroutine-with-nll.rs:8:17
    |
+LL |     || {
+   |     -- within this coroutine
+...
 LL |         let b = &mut true;
    |                 ^^^^^^^^^
 LL |
 LL |         yield ();
    |         -------- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     static || {
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coroutine/issue-48048.stderr b/tests/ui/coroutine/issue-48048.stderr
index 199ecf4ca6a..8231dbef7f6 100644
--- a/tests/ui/coroutine/issue-48048.stderr
+++ b/tests/ui/coroutine/issue-48048.stderr
@@ -1,10 +1,18 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/issue-48048.rs:9:9
    |
+LL |     #[coroutine] || {
+   |                  -- within this coroutine
+...
 LL |         x.0({
    |         ^^^
 LL |             yield;
    |             ----- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     #[coroutine] static || {
+   |                  ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coroutine/pattern-borrow.stderr b/tests/ui/coroutine/pattern-borrow.stderr
index 9e7b330d79d..a3954b0b8ad 100644
--- a/tests/ui/coroutine/pattern-borrow.stderr
+++ b/tests/ui/coroutine/pattern-borrow.stderr
@@ -1,10 +1,17 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/pattern-borrow.rs:9:24
    |
+LL |     #[coroutine] move || {
+   |                  ------- within this coroutine
 LL |         if let Test::A(ref _a) = test {
    |                        ^^^^^^
 LL |             yield ();
    |             -------- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     #[coroutine] static move || {
+   |                  ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coroutine/self_referential_gen_block.stderr b/tests/ui/coroutine/self_referential_gen_block.stderr
index e23d653d0d4..2f53e7c84a1 100644
--- a/tests/ui/coroutine/self_referential_gen_block.stderr
+++ b/tests/ui/coroutine/self_referential_gen_block.stderr
@@ -1,6 +1,9 @@
 error[E0626]: borrow may still be in use when `gen` block yields
   --> $DIR/self_referential_gen_block.rs:9:21
    |
+LL |         let mut x = gen {
+   |                     --- within this `gen` block
+LL |             let y = 42;
 LL |             let z = &y;
    |                     ^^
 LL |             yield 43;
diff --git a/tests/ui/coroutine/yield-in-args.stderr b/tests/ui/coroutine/yield-in-args.stderr
index 1d2c54f9bdb..1cc3c83deb3 100644
--- a/tests/ui/coroutine/yield-in-args.stderr
+++ b/tests/ui/coroutine/yield-in-args.stderr
@@ -1,8 +1,16 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/yield-in-args.rs:9:13
    |
+LL |     || {
+   |     -- within this coroutine
+LL |         let b = true;
 LL |         foo(&b, yield);
    |             ^^  ----- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     static || {
+   |     ++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coroutine/yield-while-iterating.stderr b/tests/ui/coroutine/yield-while-iterating.stderr
index f81c914c4bd..a92237e44c1 100644
--- a/tests/ui/coroutine/yield-while-iterating.stderr
+++ b/tests/ui/coroutine/yield-while-iterating.stderr
@@ -1,10 +1,17 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/yield-while-iterating.rs:13:18
    |
+LL |     let _b =#[coroutine]  move || {
+   |                           ------- within this coroutine
 LL |         for p in &x {
    |                  ^^
 LL |             yield();
    |             ------- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     let _b =#[coroutine]  static move || {
+   |                           ++++++
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
   --> $DIR/yield-while-iterating.rs:58:20
diff --git a/tests/ui/coroutine/yield-while-local-borrowed.stderr b/tests/ui/coroutine/yield-while-local-borrowed.stderr
index 8fe981de929..b42ca3ba461 100644
--- a/tests/ui/coroutine/yield-while-local-borrowed.stderr
+++ b/tests/ui/coroutine/yield-while-local-borrowed.stderr
@@ -1,20 +1,35 @@
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/yield-while-local-borrowed.rs:13:17
    |
+LL |     let mut b = #[coroutine] move || {
+   |                              ------- within this coroutine
 LL |         let a = &mut 3;
    |                 ^^^^^^
 LL |
 LL |         yield ();
    |         -------- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     let mut b = #[coroutine] static move || {
+   |                              ++++++
 
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/yield-while-local-borrowed.rs:40:21
    |
+LL |     let mut b = #[coroutine] move || {
+   |                              ------- within this coroutine
+...
 LL |             let b = &a;
    |                     ^^
 LL |
 LL |             yield ();
    |             -------- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     let mut b = #[coroutine] static move || {
+   |                              ++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/issue-55850.stderr b/tests/ui/nll/issue-55850.stderr
index 3d43817f4d8..5a9c7799197 100644
--- a/tests/ui/nll/issue-55850.stderr
+++ b/tests/ui/nll/issue-55850.stderr
@@ -10,8 +10,16 @@ LL |         yield &s[..]
 error[E0626]: borrow may still be in use when coroutine yields
   --> $DIR/issue-55850.rs:28:16
    |
+LL |     GenIter(#[coroutine] move || {
+   |                          ------- within this coroutine
+LL |         let mut s = String::new();
 LL |         yield &s[..]
    |         -------^---- possible yield occurs here
+   |
+help: add `static` to mark this coroutine as unmovable
+   |
+LL |     GenIter(#[coroutine] static move || {
+   |                          ++++++
 
 error: aborting due to 2 previous errors