about summary refs log tree commit diff
diff options
context:
space:
mode:
authorchaz-kiker <chaz-kiker@lambdastudents.com>2021-07-20 15:04:32 -0500
committerchaz-kiker <chaz-kiker@lambdastudents.com>2021-07-22 15:42:42 -0500
commit831ac196398c2dec18cdfb2299d465f64ec05223 (patch)
treea00c43a0d5cdff89670ac1d2b61a66f23f9bf345
parent5c0ca08c662399c1c864310d1a20867d3ab68027 (diff)
downloadrust-831ac196398c2dec18cdfb2299d465f64ec05223.tar.gz
rust-831ac196398c2dec18cdfb2299d465f64ec05223.zip
Squash all commits.
add test for issue 86507

add stderr for issue 86507

update issue-86507 UI test

add comment for the expected error in UI test file

add proper 'refers to <ref_type>' in suggestion

update diagnostic phrasing; update test to match new phrasing; re-organize logic for checking T: Sync

evaluate additional obligation to figure out if T is Sync

run './x.py test tidy --bless'

incorporate changes from review; reorganize logic for readability
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs35
-rw-r--r--src/test/ui/async-await/issue-86507.rs25
-rw-r--r--src/test/ui/async-await/issue-86507.stderr23
3 files changed, 78 insertions, 5 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 1c6a83b5783..9a33875d6e4 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1857,12 +1857,37 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
             }
             GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
+                // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync`
+                let refers_to_non_sync = match target_ty.kind() {
+                    ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) {
+                        Ok(eval) if !eval.may_apply() => Some(ref_ty),
+                        _ => None,
+                    },
+                    _ => None,
+                };
+
+                let (span_label, span_note) = match refers_to_non_sync {
+                    // if `target_ty` is `&T` and `T` fails to impl `Sync`,
+                    // include suggestions to make `T: Sync` so that `&T: Send`
+                    Some(ref_ty) => (
+                        format!(
+                            "has type `{}` which {}, because `{}` is not `Sync`",
+                            target_ty, trait_explanation, ref_ty
+                        ),
+                        format!(
+                            "captured value {} because `&` references cannot be sent unless their referent is `Sync`",
+                            trait_explanation
+                        ),
+                    ),
+                    None => (
+                        format!("has type `{}` which {}", target_ty, trait_explanation),
+                        format!("captured value {}", trait_explanation),
+                    ),
+                };
+
                 let mut span = MultiSpan::from_span(upvar_span);
-                span.push_span_label(
-                    upvar_span,
-                    format!("has type `{}` which {}", target_ty, trait_explanation),
-                );
-                err.span_note(span, &format!("captured value {}", trait_explanation));
+                span.push_span_label(upvar_span, span_label);
+                err.span_note(span, &span_note);
             }
         }
 
diff --git a/src/test/ui/async-await/issue-86507.rs b/src/test/ui/async-await/issue-86507.rs
new file mode 100644
index 00000000000..317f0317664
--- /dev/null
+++ b/src/test/ui/async-await/issue-86507.rs
@@ -0,0 +1,25 @@
+// edition:2018
+
+use ::core::pin::Pin;
+use ::core::future::Future;
+use ::core::marker::Send;
+
+trait Foo {
+    fn bar<'me, 'async_trait, T: Send>(x: &'me T)
+        -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
+        where 'me: 'async_trait;
+}
+
+impl Foo for () {
+    fn bar<'me, 'async_trait, T: Send>(x: &'me T)
+        -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
+        where 'me:'async_trait {
+            Box::pin( //~ ERROR future cannot be sent between threads safely
+                async move {
+                    let x = x;
+                }
+            )
+         }
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/issue-86507.stderr b/src/test/ui/async-await/issue-86507.stderr
new file mode 100644
index 00000000000..51e8f61085b
--- /dev/null
+++ b/src/test/ui/async-await/issue-86507.stderr
@@ -0,0 +1,23 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-86507.rs:17:13
+   |
+LL | /             Box::pin(
+LL | |                 async move {
+LL | |                     let x = x;
+LL | |                 }
+LL | |             )
+   | |_____________^ future created by async block is not `Send`
+   |
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/issue-86507.rs:19:29
+   |
+LL |                     let x = x;
+   |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
+   = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
+help: consider further restricting type parameter `T`
+   |
+LL |         where 'me:'async_trait, T: std::marker::Sync {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+