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

Additional let bindings needed to avoid Sync #94843

Closed
crepererum opened this issue Mar 11, 2022 · 1 comment
Closed

Additional let bindings needed to avoid Sync #94843

crepererum opened this issue Mar 11, 2022 · 1 comment
Labels
A-async-await Area: Async & Await A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@crepererum
Copy link
Contributor

I tried this code:

use std::future::Future;

fn spawn<T>(_: T)
where
    T: Future + Send + 'static,
    T::Output: Send + 'static,
{
}

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

async fn g<T>(x: T)
where
    T: Clone + Send + 'static,
{
    spawn(async move {
        f(x.clone()).await;
    });
}

fn main() {}

(playground)

I expected to see this happen:
It should compile.

Instead, this happened:

Compiling playground v0.0.1 (/playground)
error: future cannot be sent between threads safely
  [--> src/main.rs:16:5
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
16 |     spawn(async move {
   |     ^^^^^ future created by async block is not `Send`
   |
note: future is not `Send` as this value is used across an await
  [--> src/main.rs:17:21
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
17 |         f(x.clone()).await;
   |           -         ^^^^^^ await occurs here, with `x` maybe used later
   |           |
   |           has type `&T` which is not `Send`
note: `x` is later dropped here
  [--> src/main.rs:17:27
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
17 |         f(x.clone()).await;
   |                           ^
help: consider moving this into a `let` binding to create a shorter lived borrow
  [--> src/main.rs:17:11
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
17 |         f(x.clone()).await;
   |           ^^^^^^^^^
note: required by a bound in `spawn`
  [--> src/main.rs:5:17
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)   |
3  | fn spawn<T>(_: T)
   |    ----- required by a bound in this
4  | where
5  |     T: Future + Send + 'static,
   |                 ^^^^ required by this bound in `spawn`
help: consider further restricting this bound
   |
14 |     T: Clone + Send + 'static + std::marker::Sync,
   |                               +++++++++++++++++++

error: could not compile `playground` due to previous error

Note that following the suggestion using an additional let binding fixes the issue:

async fn g<T>(x: T)
where
    T: Clone + Send + 'static,
{
    spawn(async move {
        let x = x.clone();
        f(x).await;
    });
}

What is kinda weird (from my PoV) is the explanation: adding an additional let binding doesn't really shorted the borrowing of x, we're still just calling .clone() and then call f.

You might wonder why someone would clone x here, but let's assume we need x after calling f and I didn't want to make the example more complicated.

The spawn function above was chosen because it is similar to tokio::spawn, for which this issue was observed originally.

I think this might be another instance of #69663 but I'm not sure.

Meta

rustc --version --verbose:

rustc 1.59.0 (9d1b2106e 2022-02-23)
binary: rustc
commit-hash: 9d1b2106e23b1abd32fce1f17267604a5102f57a
commit-date: 2022-02-23
host: x86_64-unknown-linux-gnu
release: 1.59.0
LLVM version: 13.0.0

Bug is also reproducible on nightly.

@crepererum crepererum added the C-bug Category: This is a bug. label Mar 11, 2022
@ChrisDenton ChrisDenton added the needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. label Jul 16, 2023
@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-async-await Area: Async & Await A-borrow-checker Area: The borrow checker and removed needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. labels Jan 24, 2024
@fmease
Copy link
Member

fmease commented Jan 24, 2024

This now successfully compiles. Closing as fixed.

@fmease fmease closed this as completed Jan 24, 2024
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 A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants