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

async/await regression regarding borrows across yields #65436

Open
valff opened this issue Oct 15, 2019 · 4 comments

Comments

@valff
Copy link
Contributor

@valff valff commented Oct 15, 2019

The following code was working in nightly-2019-09-05, but no longer works in nightly-2019-10-15. The workaround is not quite intuitive.

struct Foo(*const u8);

unsafe impl Send for Foo {}

async fn bar(_: Foo) {}

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

fn main() {
    assert_send(async {
        // This works in nightly-2019-09-05, but no longer works in nightly-2019-10-15:
        bar(Foo(std::ptr::null())).await;
        // This way it does work in nightly-2019-10-15:
        //let foo = Foo(std::ptr::null());
        //bar(foo).await;
    })
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: `*const u8` cannot be sent between threads safely
  --> src/main.rs:10:5
   |
7  | fn assert_send<T: Send>(_: T) {}
   |    -----------    ---- required by this bound in `assert_send`
...
10 |     assert_send(async {
   |     ^^^^^^^^^^^ `*const u8` cannot be sent between threads safely
   |
   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*const u8`
   = note: required because it appears within the type `{fn(Foo) -> impl std::future::Future {bar}, fn(*const u8) -> Foo {Foo}, fn() -> *const u8 {std::ptr::null::<u8>}, *const u8, Foo, impl std::future::Future, impl std::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:10:23: 16:6 {fn(Foo) -> impl std::future::Future {bar}, fn(*const u8) -> Foo {Foo}, fn() -> *const u8 {std::ptr::null::<u8>}, *const u8, Foo, impl std::future::Future, impl std::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:10:23: 16:6 {fn(Foo) -> impl std::future::Future {bar}, fn(*const u8) -> Foo {Foo}, fn() -> *const u8 {std::ptr::null::<u8>}, *const u8, Foo, impl std::future::Future, impl std::future::Future, ()}]>`
   = note: required because it appears within the type `impl std::future::Future`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

@callym

This comment has been minimized.

Copy link

@callym callym commented Oct 21, 2019

I'm also running into this error using Tide and a DB Pool from Diesel

I've managed to get a slightly simpler/different version of the above code - I'd expect this to work because I'd expect the Foo.v() to be finished before the .async starts (I guess it's similar to how pre-NLL we'd expect function calls in arguments to work but sometimes they wouldn't because existing borrows?)

#![feature(optin_builtin_traits)]

struct Foo;

impl Foo {
  fn v(&self) -> () {}
}

impl !Send for Foo {}

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

async fn take<T>(_: T) {}

fn main() {
  // This compiles fine
  assert_send(async {
    let v = Foo.v();

    take(v).await;
  });

  // This used to work but now doesn't
  assert_send(async {
    take(Foo.v()).await;
  });
}

I've managed to track it down to happening somewhere between these - but I'm not sure how to go about figuring this out any further (I've never built the compiler, let alone actually debugged it)

rustc 1.39.0-nightly (0b36e9dea 2019-09-09) - This successfully builds

rustc 1.39.0-nightly (34e82a7b7 2019-09-10) - This fails

https://github.com/rust-lang/rust/compare/0b36e9dea..34e82a7b7

@sfackler

This comment has been minimized.

Copy link
Member

@sfackler sfackler commented Oct 21, 2019

This was an intentional change to match the drop order in synchronous code: #64512

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

@nikomatsakis nikomatsakis commented Oct 22, 2019

This was an intentional change but these errors also look like they are caused by "overapproximation" of the set of captured values. We are working to improve that; separately, we are also working on improving the diagnostics here.

@davidtwco

This comment has been minimized.

Copy link
Member

@davidtwco davidtwco commented Oct 24, 2019

Assigning to myself as this is a case I'd hope to tackle in #65345. It isn't currently handled by that PR, as the current diagnostic improvements only work when the error originates from an async fn, not async { }.

@rustbot claim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.