Skip to content

Commit

Permalink
Rollup merge of #87322 - chazkiker2:fix/suggestion-ref-sync-send, r=e…
Browse files Browse the repository at this point in the history
…stebank

fix: clarify suggestion that `&T` must refer to `T: Sync` for `&T: Send`

### Description

- [x] fix #86507
- [x] add UI test for relevant code from issue
- [x] change `rustc_trait_selection/src/traits/error_reporting/suggestions.rs` to include a more clear suggestion when `&T` fails to satisfy `Send` bounds due to the fact that `T` fails to implement `Sync`
- [x] update UI test in Clippy: `src/tools/tests/ui/future_not_send.stderr`
  • Loading branch information
JohnTitor committed Jul 23, 2021
2 parents 82a14e5 + a1518f0 commit 3fc79fd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/test/ui/async-await/issue-86507.rs
Original file line number Diff line number Diff line change
@@ -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() { }
23 changes: 23 additions & 0 deletions src/test/ui/async-await/issue-86507.stderr
Original file line number Diff line number Diff line change
@@ -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

4 changes: 2 additions & 2 deletions src/tools/clippy/tests/ui/future_not_send.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 3fc79fd

Please sign in to comment.