Skip to content

Move closure copies :Copy variables silently #63220

Closed
@kpp

Description

@kpp

The Good

Given the following code:

fn main() {
    let mut x = 0;
    dbg!(x);
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=19261742184207a4075885cae58680e1

I got a reasonable warning:

warning: variable does not need to be mutable
 --> src/main.rs:2:9
  |
2 |     let mut x = 0;
  |         ----^
  |         |
  |         help: remove this `mut`

The Bad

Suggest we have the following code:

fn main() {
    let mut x = 0;
    let mut f = move || x = 42;
    f();
    dbg!(x);
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42c989cf63f57e5bad0f572bb705b69f

Neither rustc nor clippy gives me any warning. x = 42 affects a local copy of x, not the outer one, that's why dbg prints x=0. This can result in a buggy code.

The Ugly

async move closures are affected too. Replacing FnMut's with async move closures light-headedly will add unexpected bugs. Example from https://docs.rs/futures-preview/0.3.0-alpha.17/futures/stream/trait.StreamExt.html#method.for_each:

-let fut = stream::repeat(1).take(3).for_each(|item| {
+let fut = stream::repeat(1).take(3).for_each(async move |item| {
      x += item;
-     ready(())
 });
// futures 0.3
#![feature(async_await, async_closure)]
use futures::future;
use futures::stream::{self, StreamExt};

let mut x = 0;

{
    let fut = stream::repeat(1).take(3).for_each(async move |item| {
        x += item;
    });
    fut.await;
}

assert_eq!(x, 3); // BOOM! x = 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions