rust-lang / rust-lang/rust

rustc should allow moving a value and its borrowed data into a `move` closure.

Open
#128,164 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-feature-request T-lang T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Given the following code (playground):

struct Borrows<'a>(&'a String);

impl<'a> Borrows<'a> {
    fn do_something(&self) {
        println!("data contents: {}", self.0);
    }
}

fn main() {
    let data = String::from("hi-ho kermit thee frog heer");
    let borrower = Borrows(&data);
    
    let _ = move || {
        println!("data size: {}", data.len());
        borrower.do_something();
    };
}

The following error is produced on stable (1.79.0) and nightly (1.81.0-nightly):

error[E0505]: cannot move out of `data` because it is borrowed
  --> src/main.rs:13:13
   |
10 |     let data = String::from("hi-ho kermit thee frog heer");
   |         ---- binding `data` declared here
11 |     let borrower = Borrows(&data);
   |                            ----- borrow of `data` occurs here
12 |     
13 |     let _ = move || {
   |             ^^^^^^^ move out of `data` occurs here
14 |         println!("data size: {}", data.len());
   |                                   ---- move occurs due to use in closure
15 |         borrower.do_something();
   |         -------- borrow later captured here by closure
   |
help: consider cloning the value if the performance cost is acceptable
   |
11 -     let borrower = Borrows(&data);
11 +     let borrower = Borrows(data.clone());
   |

This would normally make sense, except for the fact that both borrower and data are moved into the closure, and the println! statement inside the closure does not consume data.

So in theory, rustc could allow this code. It seems like it would be similar to other ways in which rustc pushes around lexical scopes in order to allow more code to be valid.

Alternatives

Alternatively, rustc could suggest that the move is not necessary:

help: consider capturing by reference instead of by value
   |
13 -     let _ = move || {
13 +     let _ = || {
   |

Or it could suggest rebinding as a reference to be moved into the closure:

help: consider capturing `data` by reference instead of by value
   |
   +     let data = &data;
13 |     let _ = move || {
   |

@rustbot label +T-compiler

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example in the linked Rust Playground and inspect rustc's E0505 diagnostic for the closure capture. Determine whether the compiler should permit the move or recommend one of the alternatives, then add coverage for the chosen behavior and verify the diagnostic or compilation result.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.