Skip to content

Commit 27d6f55

Browse files
committed
Auto merge of #65345 - davidtwco:issue-64130-async-send-sync-error-improvements, r=nikomatsakis
async/await: improve not-send errors, part 2 Part of #64130. Fixes #65667. This PR improves the errors introduced in #64895 so that they have specialized messages for `Send` and `Sync`. r? @nikomatsakis
2 parents 90b957a + 5cd9f22 commit 27d6f55

19 files changed

+502
-147
lines changed

src/libcore/marker.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::hash::Hasher;
2929
/// [arc]: ../../std/sync/struct.Arc.html
3030
/// [ub]: ../../reference/behavior-considered-undefined.html
3131
#[stable(feature = "rust1", since = "1.0.0")]
32+
#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")]
3233
#[rustc_on_unimplemented(
3334
message="`{Self}` cannot be sent between threads safely",
3435
label="`{Self}` cannot be sent between threads safely"
@@ -440,6 +441,7 @@ pub macro Copy($item:item) { /* compiler built-in */ }
440441
/// [ub]: ../../reference/behavior-considered-undefined.html
441442
/// [transmute]: ../../std/mem/fn.transmute.html
442443
#[stable(feature = "rust1", since = "1.0.0")]
444+
#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")]
443445
#[lang = "sync"]
444446
#[rustc_on_unimplemented(
445447
message="`{Self}` cannot be shared between threads safely",

src/librustc/traits/error_reporting.rs

+223-83
Large diffs are not rendered by default.

src/librustc_errors/diagnostic.rs

+10
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,20 @@ impl Diagnostic {
498498
self
499499
}
500500

501+
pub fn clear_code(&mut self) -> &mut Self {
502+
self.code = None;
503+
self
504+
}
505+
501506
pub fn get_code(&self) -> Option<DiagnosticId> {
502507
self.code.clone()
503508
}
504509

510+
pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
511+
self.message[0] = (msg.into(), Style::NoStyle);
512+
self
513+
}
514+
505515
pub fn message(&self) -> String {
506516
self.message.iter().map(|i| i.0.as_str()).collect::<String>()
507517
}

src/libstd/future.rs

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T:
2626
#[doc(hidden)]
2727
#[unstable(feature = "gen_future", issue = "50547")]
2828
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
29-
#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
3029
struct GenFuture<T: Generator<Yield = ()>>(T);
3130

3231
// We rely on the fact that async/await futures are immovable in order to create

src/libsyntax_pos/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ symbols! {
660660
_Self,
661661
self_in_typedefs,
662662
self_struct_ctor,
663+
send_trait,
663664
should_panic,
664665
simd,
665666
simd_extract,
@@ -697,6 +698,7 @@ symbols! {
697698
sty,
698699
sub_with_overflow,
699700
suggestion,
701+
sync_trait,
700702
target_feature,
701703
target_has_atomic,
702704
target_has_atomic_load_store,

src/test/ui/async-await/async-fn-nonsend.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ fn assert_send(_: impl Send) {}
4848

4949
pub fn pass_assert() {
5050
assert_send(local_dropped_before_await());
51-
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
51+
//~^ ERROR future cannot be sent between threads safely
5252
assert_send(non_send_temporary_in_match());
53-
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
53+
//~^ ERROR future cannot be sent between threads safely
5454
assert_send(non_sync_with_method_call());
55-
//~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
56-
//~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
55+
//~^ ERROR future cannot be sent between threads safely
56+
//~^^ ERROR future cannot be sent between threads safely
5757
}

src/test/ui/async-await/async-fn-nonsend.stderr

+50-41
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,88 @@
1-
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
1+
error: future cannot be sent between threads safely
22
--> $DIR/async-fn-nonsend.rs:50:5
33
|
44
LL | fn assert_send(_: impl Send) {}
55
| ----------- ---- required by this bound in `assert_send`
66
...
77
LL | assert_send(local_dropped_before_await());
8-
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
8+
| ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
99
|
1010
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
11-
= note: required because it appears within the type `impl std::fmt::Debug`
12-
= note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}`
13-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]`
14-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]>`
15-
= note: required because it appears within the type `impl std::future::Future`
16-
= note: required because it appears within the type `impl std::future::Future`
11+
note: future is not `Send` as this value is used across an await
12+
--> $DIR/async-fn-nonsend.rs:25:5
13+
|
14+
LL | let x = non_send();
15+
| - has type `impl std::fmt::Debug`
16+
LL | drop(x);
17+
LL | fut().await;
18+
| ^^^^^^^^^^^ await occurs here, with `x` maybe used later
19+
LL | }
20+
| - `x` is later dropped here
1721

18-
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
22+
error: future cannot be sent between threads safely
1923
--> $DIR/async-fn-nonsend.rs:52:5
2024
|
2125
LL | fn assert_send(_: impl Send) {}
2226
| ----------- ---- required by this bound in `assert_send`
2327
...
2428
LL | assert_send(non_send_temporary_in_match());
25-
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
29+
| ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
2630
|
2731
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
28-
= note: required because it appears within the type `impl std::fmt::Debug`
29-
= note: required because it appears within the type `{impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}`
30-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]`
31-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]>`
32-
= note: required because it appears within the type `impl std::future::Future`
33-
= note: required because it appears within the type `impl std::future::Future`
32+
note: future is not `Send` as this value is used across an await
33+
--> $DIR/async-fn-nonsend.rs:34:20
34+
|
35+
LL | match Some(non_send()) {
36+
| ---------- has type `impl std::fmt::Debug`
37+
LL | Some(_) => fut().await,
38+
| ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later
39+
...
40+
LL | }
41+
| - `non_send()` is later dropped here
3442

35-
error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
43+
error: future cannot be sent between threads safely
3644
--> $DIR/async-fn-nonsend.rs:54:5
3745
|
3846
LL | fn assert_send(_: impl Send) {}
3947
| ----------- ---- required by this bound in `assert_send`
4048
...
4149
LL | assert_send(non_sync_with_method_call());
42-
| ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
50+
| ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
4351
|
4452
= help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
45-
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
46-
= note: required because it appears within the type `std::fmt::Formatter<'_>`
47-
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
48-
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
49-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
50-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
51-
= note: required because it appears within the type `impl std::future::Future`
52-
= note: required because it appears within the type `impl std::future::Future`
53+
note: future is not `Send` as this value is used across an await
54+
--> $DIR/async-fn-nonsend.rs:43:9
55+
|
56+
LL | let f: &mut std::fmt::Formatter = panic!();
57+
| - has type `&mut std::fmt::Formatter<'_>`
58+
LL | if non_sync().fmt(f).unwrap() == () {
59+
LL | fut().await;
60+
| ^^^^^^^^^^^ await occurs here, with `f` maybe used later
61+
LL | }
62+
LL | }
63+
| - `f` is later dropped here
5364

54-
error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
65+
error: future cannot be sent between threads safely
5566
--> $DIR/async-fn-nonsend.rs:54:5
5667
|
5768
LL | fn assert_send(_: impl Send) {}
5869
| ----------- ---- required by this bound in `assert_send`
5970
...
6071
LL | assert_send(non_sync_with_method_call());
61-
| ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
72+
| ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
6273
|
6374
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
64-
= note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
65-
= note: required because it appears within the type `core::fmt::Void`
66-
= note: required because it appears within the type `&core::fmt::Void`
67-
= note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
68-
= note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
69-
= note: required because it appears within the type `std::fmt::Formatter<'_>`
70-
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
71-
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
72-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
73-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
74-
= note: required because it appears within the type `impl std::future::Future`
75-
= note: required because it appears within the type `impl std::future::Future`
75+
note: future is not `Send` as this value is used across an await
76+
--> $DIR/async-fn-nonsend.rs:43:9
77+
|
78+
LL | let f: &mut std::fmt::Formatter = panic!();
79+
| - has type `&mut std::fmt::Formatter<'_>`
80+
LL | if non_sync().fmt(f).unwrap() == () {
81+
LL | fut().await;
82+
| ^^^^^^^^^^^ await occurs here, with `f` maybe used later
83+
LL | }
84+
LL | }
85+
| - `f` is later dropped here
7686

7787
error: aborting due to 4 previous errors
7888

79-
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(optin_builtin_traits)]
2+
// edition:2018
3+
4+
// This tests the the specialized async-await-specific error when futures don't implement an
5+
// auto trait (which is specifically Sync) due to some type that was captured.
6+
7+
struct Foo;
8+
9+
impl !Sync for Foo {}
10+
11+
fn is_sync<T: Sync>(t: T) { }
12+
13+
async fn bar() {
14+
let x = Foo;
15+
baz().await;
16+
}
17+
18+
async fn baz() { }
19+
20+
fn main() {
21+
is_sync(bar());
22+
//~^ ERROR future cannot be shared between threads safely
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: future cannot be shared between threads safely
2+
--> $DIR/issue-64130-1-sync.rs:21:5
3+
|
4+
LL | fn is_sync<T: Sync>(t: T) { }
5+
| ------- ---- required by this bound in `is_sync`
6+
...
7+
LL | is_sync(bar());
8+
| ^^^^^^^ future returned by `bar` is not `Sync`
9+
|
10+
= help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo`
11+
note: future is not `Sync` as this value is used across an await
12+
--> $DIR/issue-64130-1-sync.rs:15:5
13+
|
14+
LL | let x = Foo;
15+
| - has type `Foo`
16+
LL | baz().await;
17+
| ^^^^^^^^^^^ await occurs here, with `x` maybe used later
18+
LL | }
19+
| - `x` is later dropped here
20+
21+
error: aborting due to previous error
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(optin_builtin_traits)]
2+
// edition:2018
3+
4+
// This tests the the specialized async-await-specific error when futures don't implement an
5+
// auto trait (which is specifically Send) due to some type that was captured.
6+
7+
struct Foo;
8+
9+
impl !Send for Foo {}
10+
11+
fn is_send<T: Send>(t: T) { }
12+
13+
async fn bar() {
14+
let x = Foo;
15+
baz().await;
16+
}
17+
18+
async fn baz() { }
19+
20+
fn main() {
21+
is_send(bar());
22+
//~^ ERROR future cannot be sent between threads safely
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: future cannot be sent between threads safely
2+
--> $DIR/issue-64130-2-send.rs:21:5
3+
|
4+
LL | fn is_send<T: Send>(t: T) { }
5+
| ------- ---- required by this bound in `is_send`
6+
...
7+
LL | is_send(bar());
8+
| ^^^^^^^ future returned by `bar` is not `Send`
9+
|
10+
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo`
11+
note: future is not `Send` as this value is used across an await
12+
--> $DIR/issue-64130-2-send.rs:15:5
13+
|
14+
LL | let x = Foo;
15+
| - has type `Foo`
16+
LL | baz().await;
17+
| ^^^^^^^^^^^ await occurs here, with `x` maybe used later
18+
LL | }
19+
| - `x` is later dropped here
20+
21+
error: aborting due to previous error
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![feature(optin_builtin_traits)]
2+
// edition:2018
3+
4+
// This tests the the unspecialized async-await-specific error when futures don't implement an
5+
// auto trait (which is not Send or Sync) due to some type that was captured.
6+
7+
auto trait Qux { }
8+
9+
struct Foo;
10+
11+
impl !Qux for Foo {}
12+
13+
fn is_qux<T: Qux>(t: T) { }
14+
15+
async fn bar() {
16+
let x = Foo;
17+
baz().await;
18+
}
19+
20+
async fn baz() { }
21+
22+
fn main() {
23+
is_qux(bar());
24+
//~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
2+
--> $DIR/issue-64130-3-other.rs:23:5
3+
|
4+
LL | fn is_qux<T: Qux>(t: T) { }
5+
| ------ --- required by this bound in `is_qux`
6+
...
7+
LL | is_qux(bar());
8+
| ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`
9+
|
10+
= help: the following implementations were found:
11+
<Foo as Qux>
12+
note: future does not implement `Qux` as this value is used across an await
13+
--> $DIR/issue-64130-3-other.rs:17:5
14+
|
15+
LL | let x = Foo;
16+
| - has type `Foo`
17+
LL | baz().await;
18+
| ^^^^^^^^^^^ await occurs here, with `x` maybe used later
19+
LL | }
20+
| - `x` is later dropped here
21+
22+
error: aborting due to previous error
23+
24+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// edition:2018
2+
use std::any::Any;
3+
use std::future::Future;
4+
5+
struct Client(Box<dyn Any + Send>);
6+
7+
impl Client {
8+
fn status(&self) -> u16 {
9+
200
10+
}
11+
}
12+
13+
async fn get() { }
14+
15+
pub fn foo() -> impl Future + Send {
16+
//~^ ERROR future cannot be sent between threads safely
17+
let client = Client(Box::new(true));
18+
async move {
19+
match client.status() {
20+
200 => {
21+
let _x = get().await;
22+
},
23+
_ => (),
24+
}
25+
}
26+
}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)