Skip to content

Commit 4a01a38

Browse files
Rollup merge of rust-lang#111087 - ibraheemdev:patch-15, r=dtolnay
Implement `Sync` for `mpsc::Sender` `mpsc::Sender` is currently `!Sync` because the previous implementation contained an optimization where the channel started out as single-producer and was dynamically upgraded on the first clone, which relied on a unique reference to the sender. This optimization is one of the main reasons the old implementation was so complex and was removed in rust-lang#93563. `mpsc::Sender` can now soundly implement `Sync`. Note for any potential confusion, this chance does *not* add MPMC behavior. This only affects the already `Send + Clone` *sender*, not *receiver*. It's technically possible to rely on the `!Sync` behavior in the same way as a `PhantomData<*mut T>`, but that seems very unlikely in practice. Either way, this change is insta-stable and needs an FCP. `@rustbot` label +T-libs-api -T-libs
2 parents 1d67eba + 4ceca09 commit 4a01a38

9 files changed

+61
-81
lines changed

library/std/src/sync/mpsc/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ pub struct Sender<T> {
347347
#[stable(feature = "rust1", since = "1.0.0")]
348348
unsafe impl<T: Send> Send for Sender<T> {}
349349

350-
#[stable(feature = "rust1", since = "1.0.0")]
351-
impl<T> !Sync for Sender<T> {}
350+
#[stable(feature = "mpsc_sender_sync", since = "CURRENT_RUSTC_VERSION")]
351+
unsafe impl<T: Send> Sync for Sender<T> {}
352352

353353
/// The sending-half of Rust's synchronous [`sync_channel`] type.
354354
///

tests/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr

+19-12
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
error[E0277]: `Sender<i32>` cannot be shared between threads safely
2-
--> $DIR/issue-70935-complex-spans.rs:13:45
1+
error[E0277]: `*mut ()` cannot be shared between threads safely
2+
--> $DIR/issue-70935-complex-spans.rs:18:23
33
|
4-
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
5-
| ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
4+
LL | fn foo(x: NotSync) -> impl Future + Send {
5+
| ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
66
|
7-
= help: the trait `Sync` is not implemented for `Sender<i32>`
8-
= note: required for `&Sender<i32>` to implement `Send`
7+
= help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
8+
note: required because it appears within the type `PhantomData<*mut ()>`
9+
--> $SRC_DIR/core/src/marker.rs:LL:COL
10+
note: required because it appears within the type `NotSync`
11+
--> $DIR/issue-70935-complex-spans.rs:12:8
12+
|
13+
LL | struct NotSync(PhantomData<*mut ()>);
14+
| ^^^^^^^
15+
= note: required for `&NotSync` to implement `Send`
916
note: required because it's used within this closure
10-
--> $DIR/issue-70935-complex-spans.rs:17:13
17+
--> $DIR/issue-70935-complex-spans.rs:22:13
1118
|
12-
LL | baz(|| async{
19+
LL | baz(|| async {
1320
| ^^
1421
note: required because it's used within this `async fn` body
15-
--> $DIR/issue-70935-complex-spans.rs:10:67
22+
--> $DIR/issue-70935-complex-spans.rs:15:67
1623
|
1724
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
1825
| ___________________________________________________________________^
1926
LL | | }
2027
| |_^
2128
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
2229
note: required because it's used within this `async` block
23-
--> $DIR/issue-70935-complex-spans.rs:16:5
30+
--> $DIR/issue-70935-complex-spans.rs:21:5
2431
|
2532
LL | / async move {
26-
LL | | baz(|| async{
27-
LL | | foo(tx.clone());
33+
LL | | baz(|| async {
34+
LL | | foo(x.clone());
2835
LL | | }).await;
2936
LL | | }
3037
| |_____^

tests/ui/async-await/issue-70935-complex-spans.drop_tracking_mir.stderr

+19-12
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
error[E0277]: `Sender<i32>` cannot be shared between threads safely
2-
--> $DIR/issue-70935-complex-spans.rs:13:45
1+
error[E0277]: `*mut ()` cannot be shared between threads safely
2+
--> $DIR/issue-70935-complex-spans.rs:18:23
33
|
4-
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
5-
| ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
4+
LL | fn foo(x: NotSync) -> impl Future + Send {
5+
| ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
66
|
7-
= help: the trait `Sync` is not implemented for `Sender<i32>`
8-
= note: required for `&Sender<i32>` to implement `Send`
7+
= help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
8+
note: required because it appears within the type `PhantomData<*mut ()>`
9+
--> $SRC_DIR/core/src/marker.rs:LL:COL
10+
note: required because it appears within the type `NotSync`
11+
--> $DIR/issue-70935-complex-spans.rs:12:8
12+
|
13+
LL | struct NotSync(PhantomData<*mut ()>);
14+
| ^^^^^^^
15+
= note: required for `&NotSync` to implement `Send`
916
note: required because it's used within this closure
10-
--> $DIR/issue-70935-complex-spans.rs:17:13
17+
--> $DIR/issue-70935-complex-spans.rs:22:13
1118
|
12-
LL | baz(|| async{
19+
LL | baz(|| async {
1320
| ^^
1421
note: required because it's used within this `async fn` body
15-
--> $DIR/issue-70935-complex-spans.rs:10:67
22+
--> $DIR/issue-70935-complex-spans.rs:15:67
1623
|
1724
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
1825
| ___________________________________________________________________^
1926
LL | | }
2027
| |_^
2128
= note: required because it captures the following types: `impl Future<Output = ()>`
2229
note: required because it's used within this `async` block
23-
--> $DIR/issue-70935-complex-spans.rs:16:5
30+
--> $DIR/issue-70935-complex-spans.rs:21:5
2431
|
2532
LL | / async move {
26-
LL | | baz(|| async{
27-
LL | | foo(tx.clone());
33+
LL | | baz(|| async {
34+
LL | | foo(x.clone());
2835
LL | | }).await;
2936
LL | | }
3037
| |_____^
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error: future cannot be sent between threads safely
2-
--> $DIR/issue-70935-complex-spans.rs:13:45
2+
--> $DIR/issue-70935-complex-spans.rs:18:23
33
|
4-
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
5-
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
4+
LL | fn foo(x: NotSync) -> impl Future + Send {
5+
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
66
|
7-
= help: the trait `Sync` is not implemented for `Sender<i32>`
7+
= help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
88
note: future is not `Send` as this value is used across an await
9-
--> $DIR/issue-70935-complex-spans.rs:19:12
9+
--> $DIR/issue-70935-complex-spans.rs:24:12
1010
|
11-
LL | baz(|| async{
11+
LL | baz(|| async {
1212
| _____________-
13-
LL | | foo(tx.clone());
13+
LL | | foo(x.clone());
1414
LL | | }).await;
1515
| | - ^^^^^- the value is later dropped here
1616
| | | |
1717
| |_________| await occurs here, with the value maybe used later
18-
| has type `[closure@$DIR/issue-70935-complex-spans.rs:17:13: 17:15]` which is not `Send`
18+
| has type `[closure@$DIR/issue-70935-complex-spans.rs:22:13: 22:15]` which is not `Send`
1919

2020
error: aborting due to previous error
2121

tests/ui/async-await/issue-70935-complex-spans.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@
66
// with newlines which lead complex diagnostics.
77

88
use std::future::Future;
9+
use std::marker::PhantomData;
10+
11+
#[derive(Clone)]
12+
struct NotSync(PhantomData<*mut ()>);
13+
unsafe impl Send for NotSync {}
914

1015
async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
1116
}
1217

13-
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
18+
fn foo(x: NotSync) -> impl Future + Send {
1419
//[no_drop_tracking]~^ ERROR future cannot be sent between threads safely
15-
//[drop_tracking,drop_tracking_mir]~^^ ERROR `Sender<i32>` cannot be shared between threads
20+
//[drop_tracking,drop_tracking_mir]~^^ ERROR `*mut ()` cannot be shared between threads
1621
async move {
17-
baz(|| async{
18-
foo(tx.clone());
22+
baz(|| async {
23+
foo(x.clone());
1924
}).await;
2025
}
2126
}
@@ -24,6 +29,6 @@ fn bar(_s: impl Future + Send) {
2429
}
2530

2631
fn main() {
27-
let (tx, _rx) = std::sync::mpsc::channel();
28-
bar(foo(tx));
32+
let x = NotSync(PhantomData);
33+
bar(foo(x));
2934
}

tests/ui/closures/closure-move-sync.rs

-6
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,4 @@ fn bar() {
1313
t.join().unwrap();
1414
}
1515

16-
fn foo() {
17-
let (tx, _rx) = channel();
18-
thread::spawn(|| tx.send(()).unwrap());
19-
//~^ ERROR `Sender<()>` cannot be shared between threads safely
20-
}
21-
2216
fn main() {}

tests/ui/closures/closure-move-sync.stderr

+1-19
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,6 @@ LL | let t = thread::spawn(|| {
2020
note: required by a bound in `spawn`
2121
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
2222

23-
error[E0277]: `Sender<()>` cannot be shared between threads safely
24-
--> $DIR/closure-move-sync.rs:18:19
25-
|
26-
LL | thread::spawn(|| tx.send(()).unwrap());
27-
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely
28-
| |
29-
| required by a bound introduced by this call
30-
|
31-
= help: the trait `Sync` is not implemented for `Sender<()>`
32-
= note: required for `&Sender<()>` to implement `Send`
33-
note: required because it's used within this closure
34-
--> $DIR/closure-move-sync.rs:18:19
35-
|
36-
LL | thread::spawn(|| tx.send(()).unwrap());
37-
| ^^
38-
note: required by a bound in `spawn`
39-
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
40-
41-
error: aborting due to 2 previous errors
23+
error: aborting due to previous error
4224

4325
For more information about this error, try `rustc --explain E0277`.

tests/ui/stdlib-unit-tests/not-sync.rs

-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,4 @@ fn main() {
1717

1818
test::<Receiver<i32>>();
1919
//~^ ERROR `std::sync::mpsc::Receiver<i32>` cannot be shared between threads safely [E0277]
20-
test::<Sender<i32>>();
21-
//~^ ERROR `Sender<i32>` cannot be shared between threads safely [E0277]
2220
}

tests/ui/stdlib-unit-tests/not-sync.stderr

+1-14
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,6 @@ note: required by a bound in `test`
6565
LL | fn test<T: Sync>() {}
6666
| ^^^^ required by this bound in `test`
6767

68-
error[E0277]: `Sender<i32>` cannot be shared between threads safely
69-
--> $DIR/not-sync.rs:20:12
70-
|
71-
LL | test::<Sender<i32>>();
72-
| ^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely
73-
|
74-
= help: the trait `Sync` is not implemented for `Sender<i32>`
75-
note: required by a bound in `test`
76-
--> $DIR/not-sync.rs:5:12
77-
|
78-
LL | fn test<T: Sync>() {}
79-
| ^^^^ required by this bound in `test`
80-
81-
error: aborting due to 6 previous errors
68+
error: aborting due to 5 previous errors
8269

8370
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)