-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
I tried this code:
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Receiver<T: Send + 'static> {
_value: Option<T>,
_not_sync: PhantomData<*mut ()>,
}
unsafe impl<T: Send + 'static> Send for Receiver<T> {}
impl<T: Send + 'static> Future for Receiver<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Pending
}
}
trait MyTrait: Send {}
fn require_send<F: Future + Send>(_f: F) {}
fn main() {
// Static assertion works:
fn assert_send<T: Send>() {}
assert_send::<Receiver<Box<dyn MyTrait>>>();
// Async block with concrete type works:
require_send(async {
let r = Receiver::<u32> { _value: None, _not_sync: PhantomData };
let _ = r.await;
});
// Async block with dyn Trait FAILS:
require_send(async {
let r = Receiver::<Box<dyn MyTrait>> { _value: None, _not_sync: PhantomData };
let _ = r.await;
});
}I expected this to compile, because Receiver<Box<dyn MyTrait>>: Send is established by the unsafe impl (and the static assertion confirms it).
Instead, I got:
error: higher-ranked lifetime error
= note: could not prove `{async block@...}: Send`
Pattern
This is the common pattern of using PhantomData<*mut ()> to opt out of Sync while restoring Send via unsafe impl. It works for static assertions and for concrete type parameters, but fails when T is a trait object (Box<dyn Trait>) and the type is captured across an .await.
A workaround is to use PhantomData<Cell<()>> instead of PhantomData<*mut ()>, since Cell<()> is natively Send + !Sync and avoids the need for unsafe impl Send.
Versions
Relationship to #110338
This is an instance of #110338. The code compiles successfully with -Zhigher-ranked-assumptions on nightly.
@rustbot label +A-async-await +A-auto-traits +A-coroutines +fixed-by-higher-ranked-assumptions