From 831ac196398c2dec18cdfb2299d465f64ec05223 Mon Sep 17 00:00:00 2001 From: chaz-kiker 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 ' 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 1c6a83b578305..9a33875d6e493 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 0000000000000..317f0317664b6 --- /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 + Send + 'async_trait>> + where 'me: 'async_trait; +} + +impl Foo for () { + fn bar<'me, 'async_trait, T: Send>(x: &'me T) + -> Pin + 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 0000000000000..51e8f61085b22 --- /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 + 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 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 b59dbb3e76c64..c734051ccf320 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) -> 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) -> bool { - | ^^^^ has type `&std::cell::Cell` which is not `Send` + | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely