From 831ac196398c2dec18cdfb2299d465f64ec05223 Mon Sep 17 00:00:00 2001
From: chaz-kiker <chaz-kiker@lambdastudents.com>
Date: Tue, 20 Jul 2021 15:04:32 -0500
Subject: [PATCH 1/2] 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
---
 .../src/traits/error_reporting/suggestions.rs | 35 ++++++++++++++++---
 src/test/ui/async-await/issue-86507.rs        | 25 +++++++++++++
 src/test/ui/async-await/issue-86507.stderr    | 23 ++++++++++++
 3 files changed, 78 insertions(+), 5 deletions(-)
 create mode 100644 src/test/ui/async-await/issue-86507.rs
 create mode 100644 src/test/ui/async-await/issue-86507.stderr

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
+

From a1518f091552afdf370c699a359af0b7d34e402d Mon Sep 17 00:00:00 2001
From: chaz-kiker <chaz-kiker@lambdastudents.com>
Date: Fri, 23 Jul 2021 12:30:52 -0500
Subject: [PATCH 2/2] update clippy ui test 'future_not_send.stderr' to match
 the new diagnostic messages

---
 src/tools/clippy/tests/ui/future_not_send.stderr | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
index b59dbb3e76c..c734051ccf3 100644
--- a/src/tools/clippy/tests/ui/future_not_send.stderr
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -55,11 +55,11 @@ note: captured value is not `Send`
 LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                          ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
-note: captured value is not `Send`
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
   --> $DIR/future_not_send.rs:20:40
    |
 LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
-   |                                        ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`
+   |                                        ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
    = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely