Skip to content

Disjoint capture in async blocks requires mut for Copy field modifications #146547

@DangerousVegetable

Description

@DangerousVegetable

I tried this code:

use std::future::Future; use std::pin::Pin; use std::thread::sleep; use std::time::Duration; async fn run_multiple_times<Fut>( mut f: impl FnMut() -> Pin<Box<dyn Future<Output = Fut> + Send>>, ) { for _ in 0..5 { f().await; sleep(Duration::from_secs(1)); } } struct Test { pub num: usize, pub name: String, } impl Test { fn inc(&mut self) { self.num += 1 } } #[tokio::main] async fn main() { let mut state = Test {num: 0, name: "test".to_string()}; run_multiple_times(move || { Box::pin(async move { println!("State: {}", state.num); state.num = state.num + 1; // This line doesn't capture state, yet requires it to be mut ??? // These two lines, as expected, do not compile: // state.inc() // error: cannot move out of `state` // state.name = "test".to_string(); // error: String doesn't implement Copy trait }) }).await; println!("State: {}", state.num); }

I expected to see a compilation error due to state being moved twice. Instead, this code compiled without any warnings and printed "State: 0" 6 times. This issue also exists on the nightly version.

The way I understand this is that the compiler decides to move state.num instead of the whole state (which is already confusing) and, since usize implements Copy trait, it simply copies its value. The problem is that the compiler also requires state to be declared as mut which is definitely not how it should be.

Am I missing something or is it an actual bug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions