Skip to content

Moved value is considered as held across an await in async fn #87309

Closed
@WaffleLapkin

Description

@WaffleLapkin

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);
}

[playground]

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions