Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Tracked by #69663
WaffleLapkin opened this issue Jul 20, 2021 · 15 comments
Closed
Tracked by #69663

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

WaffleLapkin opened this issue Jul 20, 2021 · 15 comments
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug.

Comments

@WaffleLapkin
Copy link
Member

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
@WaffleLapkin WaffleLapkin added the C-bug Category: This is a bug. label Jul 20, 2021
@WaffleLapkin
Copy link
Member Author

@rustbot modify labels +A-async-await

@tmandry
Copy link
Member

tmandry commented Jul 23, 2021

Looks like an instance of #69663, potentially same as #57017.

@rustbot label: +AsyncAwait-Triaged

@rustbot rustbot added the AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. label Jul 23, 2021
@jyn514
Copy link
Member

jyn514 commented May 20, 2022

Here is a reduced example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8e17d9e4b6c20ad7f3291c92aa648969

use std::rc::Rc;

async fn non_trivial_drop() {
    let x = Rc::new(vec![0]);
    drop(x);
    async {}.await;
}


fn assert_send<T: Send>(_: T) {}

fn main() {
    assert_send(non_trivial_drop());
}

@eholk
Copy link
Contributor

eholk commented May 20, 2022

Does your example work with -Zdrop-tracking? This is exactly what drop tracking is meant to handle.

@jyn514
Copy link
Member

jyn514 commented May 20, 2022

@eholk yes, drop-tracking fixes it :) is there a tracking issue for that I can watch? looks like #69663

@jyn514
Copy link
Member

jyn514 commented May 20, 2022

hmm, #69663 doesn't mention -Zdrop-tracking though - I would love to help get that onto stable :) let me know if there's anything I can do.

@eholk
Copy link
Contributor

eholk commented May 20, 2022

#69663 is the umbrella bug for all overly aggressive generator captures, but there are several distinct causes for them. The case you listed looks most like #57478, which is what I've been linked most of the drop tracking work to.

There are a couple of pending PRs fixing bugs in it, such as #96923 and #97029. Once #96923 merges, I think that fixes all the major bugs I know about so the next step will be to do a crater run to make sure we don't have any other bugs lurking around.

@eholk
Copy link
Contributor

eholk commented May 20, 2022

Actually, @jyn514, one issue I haven't been able to look at yet is src/test/ui/async-await/issue-70935-complex-spans.rs. With -Zdrop-tracking the error message is significantly worse. It still works, but I'd hate to regress the user experience like this. Is that something you'd be interested in looking at?

@jyn514
Copy link
Member

jyn514 commented May 20, 2022

Sure! let me take a look :)

@jyn514

This comment was marked as resolved.

@jyn514

This comment was marked as resolved.

@eholk
Copy link
Contributor

eholk commented May 23, 2022

@eholk yes, drop-tracking fixes it :) is there a tracking issue for that I can watch?

There is now: #97331

@StyMaar
Copy link

StyMaar commented Mar 28, 2024

This issue seems to be solved now, the playground link compiles fine and everything listed in the tracking issue is marked as done (even though the tracking issue itself isn't)

@jmagnuson
Copy link

I had run into a similar issue, and bisected the fix to the 1.74.0 release which from the changelog and #97334, suggests that #107421 has ultimately resolved this.

@WaffleLapkin
Copy link
Member Author

Given the above comments I'll go ahead and close this. @eholk I am assuming the drop tracking has enough tests and we don't need to do anything here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

7 participants