Skip to content

Commit 0df87b3

Browse files
Rollup merge of rust-lang#154398 - sandersaares:higher-ranked-auto-trait-test-phantomdata-rawptr, r=jackh726
Add test for async Send with PhantomData<*mut ()> + unsafe impl Send + dyn Trait Add a regression test for rust-lang#154397, covering the case where: - A type uses `PhantomData<*mut ()>` to opt out of `Sync` - `Send` is restored via `unsafe impl<T: Send + 'static> Send` - The type is captured across an `.await` in an async block - The type parameter is a trait object (`Box<dyn Trait>`) This is an instance of rust-lang#110338. The test includes both revisions: - `assumptions`: compiles with `-Zhigher-ranked-assumptions` (check-pass) - `no_assumptions`: documents the current failure as a known-bug Also includes a `PhantomData<Cell<()>>` comparison showing the workaround compiles in all cases.
2 parents 17f03b3 + d560d3a commit 0df87b3

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: higher-ranked lifetime error
2+
--> $DIR/higher-ranked-auto-trait-18.rs:69:5
3+
|
4+
LL | / require_send(async {
5+
LL | | let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData };
6+
LL | | let _ = r.await;
7+
LL | | });
8+
| |______^
9+
|
10+
= note: could not prove `{async block@$DIR/higher-ranked-auto-trait-18.rs:69:18: 69:23}: Send`
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Repro for a bug where `PhantomData<*mut ()>` + `unsafe impl Send` fails to prove
2+
// `Send` for an async block when the type parameter is a trait object (`dyn Trait`).
3+
//
4+
// The static assertion `assert_send::<Receiver<Box<dyn MyTrait>>>()` succeeds,
5+
// but the same type captured across an `.await` in an async block does not.
6+
// This is because MIR erases the `'static` lifetime from `dyn MyTrait + 'static`,
7+
// and the auto-trait analysis cannot recover the `T: 'static` bound without
8+
// higher-ranked assumptions.
9+
//
10+
// Using `PhantomData<Cell<()>>` instead of `PhantomData<*mut ()>` avoids the
11+
// issue because `Cell<()>` is natively `Send`, so no `unsafe impl` (with its
12+
// `T: 'static` bound) is needed.
13+
//
14+
// See <https://github.com/rust-lang/rust/issues/110338>.
15+
//@ edition: 2021
16+
//@ revisions: assumptions no_assumptions
17+
//@[assumptions] compile-flags: -Zhigher-ranked-assumptions
18+
//@[assumptions] check-pass
19+
//@[no_assumptions] known-bug: #110338
20+
21+
use std::cell::Cell;
22+
use std::future::Future;
23+
use std::marker::PhantomData;
24+
use std::pin::Pin;
25+
use std::task::{Context, Poll};
26+
27+
// --- PhantomData<*mut ()> version: needs `unsafe impl Send` ---
28+
29+
struct Receiver<T: Send + 'static> {
30+
_value: Option<T>,
31+
_not_sync: PhantomData<*mut ()>,
32+
}
33+
34+
unsafe impl<T: Send + 'static> Send for Receiver<T> {}
35+
36+
impl<T: Send + 'static> Future for Receiver<T> {
37+
type Output = T;
38+
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
39+
Poll::Pending
40+
}
41+
}
42+
43+
// --- PhantomData<Cell<()>> version: auto-derived Send works ---
44+
45+
struct ReceiverCell<T: Send + 'static> {
46+
_value: Option<T>,
47+
_not_sync: PhantomData<Cell<()>>,
48+
}
49+
50+
impl<T: Send + 'static> Future for ReceiverCell<T> {
51+
type Output = T;
52+
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
53+
Poll::Pending
54+
}
55+
}
56+
57+
trait MyTrait: Send {}
58+
59+
fn require_send<F: Future + Send>(_f: F) {}
60+
61+
fn main() {
62+
// PhantomData<*mut ()> + concrete type: always works.
63+
require_send(async {
64+
let r = Receiver::<u32> { _value: None, _not_sync: PhantomData };
65+
let _ = r.await;
66+
});
67+
68+
// PhantomData<*mut ()> + dyn Trait: fails without higher-ranked assumptions.
69+
require_send(async {
70+
let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData };
71+
let _ = r.await;
72+
});
73+
74+
// PhantomData<Cell<()>> + dyn Trait: always works (auto-derived Send).
75+
require_send(async {
76+
let r = ReceiverCell::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData };
77+
let _ = r.await;
78+
});
79+
}

0 commit comments

Comments
 (0)