Closed
Description
I tried this code:
struct Ref<'a, T>(&'a T, *const () /* !Send */);
impl<'a, T> Ref<'a, T> {
fn borrow(r: &'a T) -> Result<Self, ()> {
Ok(Self(r, 0 as _))
}
}
// Not `async fn` because `async fn` always captures lifetimes of arguments
fn accept_ref<'a, T>(
_: Ref<'a, T>,
) -> impl core::future::Future<Output = ()> + Send + Sync + 'static {
async {}
}
fn test<T: Send + Sync>(arg: T) {
let fut = async move {
match Ref::borrow(&arg) {
Ok(r) => {
// `r` is moved into `accept_ref` before `await`.
let fut = accept_ref(r);
Ok(fut.await)
},
// - compiler thinks that `r` is dropped here, even though it's already moved
Err(()) => Err(arg),
}
};
fn assert_send<T: Send>(_: T) {}
assert_send(fut);
}
I expected to see this happen: the code compiles.
Instead, this happened: the following compile error:
error: future cannot be sent between threads safely
--> src/lib.rs:32:5
|
30 | fn assert_send<T: Send>(_: T) {}
| ---- required by this bound in `assert_send`
31 |
32 | assert_send(fut);
| ^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `*const ()`
note: future is not `Send` as this value is used across an await
--> src/lib.rs:22:20
|
19 | Ok(r) => {
| - has type `Ref<'_, T>` which is not `Send`
...
22 | Ok(fut.await)
| ^^^^^^^^^ await occurs here, with `r` maybe used later
23 | },
| - `r` is later dropped here
Meta
rustc --version --verbose
:
rustc 1.55.0-nightly (240ff4c4a 2021-07-09)
binary: rustc
commit-hash: 240ff4c4a0d0936c9eeb783fa9ff5c0507a6ffb4
commit-date: 2021-07-09
host: x86_64-unknown-linux-gnu
release: 1.55.0-nightly
LLVM version: 12.0.1