Skip to content

Commit 884e05e

Browse files
Rollup merge of rust-lang#33386 - cramertj:E0504, r=steveklabnik
Add detailed error explanation for E0504 Part of rust-lang#32777
2 parents 0abdb1e + 3371b8a commit 884e05e

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

src/librustc_borrowck/diagnostics.rs

+103-1
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,109 @@ fn foo(a: &mut i32) {
386386
let bar = || {
387387
inside_closure(a)
388388
};
389+
```
390+
"##,
391+
392+
E0504: r##"
393+
This error occurs when an attempt is made to move a borrowed variable into a
394+
closure.
395+
396+
Example of erroneous code:
397+
398+
```compile_fail
399+
struct FancyNum {
400+
num: u8
401+
}
402+
403+
fn main() {
404+
let fancy_num = FancyNum { num: 5 };
405+
let fancy_ref = &fancy_num;
406+
407+
let x = move || {
408+
println!("child function: {}", fancy_num.num);
409+
// error: cannot move `fancy_num` into closure because it is borrowed
410+
};
411+
412+
x();
413+
println!("main function: {}", fancy_ref.num);
414+
}
415+
```
416+
417+
Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
418+
the closure `x`. There is no way to move a value into a closure while it is
419+
borrowed, as that would invalidate the borrow.
420+
421+
If the closure can't outlive the value being moved, try using a reference
422+
rather than moving:
423+
424+
```
425+
struct FancyNum {
426+
num: u8
427+
}
428+
429+
fn main() {
430+
let fancy_num = FancyNum { num: 5 };
431+
let fancy_ref = &fancy_num;
432+
433+
let x = move || {
434+
// fancy_ref is usable here because it doesn't move `fancy_num`
435+
println!("child function: {}", fancy_ref.num);
436+
};
437+
438+
x();
439+
440+
println!("main function: {}", fancy_num.num);
441+
}
442+
```
443+
444+
If the value has to be borrowed and then moved, try limiting the lifetime of
445+
the borrow using a scoped block:
446+
447+
```
448+
struct FancyNum {
449+
num: u8
450+
}
451+
452+
fn main() {
453+
let fancy_num = FancyNum { num: 5 };
454+
455+
{
456+
let fancy_ref = &fancy_num;
457+
println!("main function: {}", fancy_ref.num);
458+
// `fancy_ref` goes out of scope here
459+
}
460+
461+
let x = move || {
462+
// `fancy_num` can be moved now (no more references exist)
463+
println!("child function: {}", fancy_num.num);
464+
};
465+
466+
x();
467+
}
468+
```
469+
470+
If the lifetime of a reference isn't enough, such as in the case of threading,
471+
consider using an `Arc` to create a reference-counted value:
472+
473+
```
474+
use std::sync::Arc;
475+
use std::thread;
476+
477+
struct FancyNum {
478+
num: u8
479+
}
480+
481+
fn main() {
482+
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
483+
let fancy_ref2 = fancy_ref1.clone();
484+
485+
let x = thread::spawn(move || {
486+
// `fancy_ref1` can be moved and has a `'static` lifetime
487+
println!("child thread: {}", fancy_ref1.num);
488+
});
489+
490+
x.join().expect("child thread should finish");
491+
println!("main thread: {}", fancy_ref2.num);
389492
}
390493
```
391494
"##,
@@ -514,7 +617,6 @@ register_diagnostics! {
514617
E0500, // closure requires unique access to `..` but .. is already borrowed
515618
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
516619
E0503, // cannot use `..` because it was mutably borrowed
517-
E0504, // cannot move `..` into closure because it is borrowed
518620
E0505, // cannot move out of `..` because it is borrowed
519621
E0506, // cannot assign to `..` because it is borrowed
520622
E0508, // cannot move out of type `..`, a non-copy fixed-size array

0 commit comments

Comments
 (0)