Skip to content

Commit 38a5338

Browse files
committed
Add detailed error explanation for E0504
Removed unnecessary use of threads from E0504 Cleaned up line ending on E0504 Added more examples for E0504 Changed to erroneous code wording Switched Rc example to thread/Arc example Added comments describing why errors no longer occur
1 parent af0a433 commit 38a5338

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

src/librustc_borrowck/diagnostics.rs

+104-1
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,110 @@ fn foo(a: &mut i32) {
454454
```
455455
"##,
456456

457+
E0504: r##"
458+
This error occurs when an attempt is made to move a borrowed variable into a
459+
closure.
460+
461+
Example of erroneous code:
462+
463+
```compile_fail
464+
struct FancyNum {
465+
num: u8
466+
}
467+
468+
fn main() {
469+
let fancy_num = FancyNum { num: 5 };
470+
let fancy_ref = &fancy_num;
471+
472+
let x = move || {
473+
println!("child function: {}", fancy_num.num);
474+
// error: cannot move `fancy_num` into closure because it is borrowed
475+
};
476+
477+
x();
478+
println!("main function: {}", fancy_ref.num);
479+
}
480+
```
481+
482+
Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
483+
the closure `x`. There is no way to move a value into a closure while it is
484+
borrowed, as that would invalidate the borrow.
485+
486+
If the closure can't outlive the value being moved, try using a reference
487+
rather than moving:
488+
489+
```
490+
struct FancyNum {
491+
num: u8
492+
}
493+
494+
fn main() {
495+
let fancy_num = FancyNum { num: 5 };
496+
let fancy_ref = &fancy_num;
497+
498+
let x = move || {
499+
// fancy_ref is usable here because it doesn't move `fancy_num`
500+
println!("child function: {}", fancy_ref.num);
501+
};
502+
503+
x();
504+
505+
println!("main function: {}", fancy_num.num);
506+
}
507+
```
508+
509+
If the value has to be borrowed and then moved, try limiting the lifetime of
510+
the borrow using a scoped block:
511+
512+
```
513+
struct FancyNum {
514+
num: u8
515+
}
516+
517+
fn main() {
518+
let fancy_num = FancyNum { num: 5 };
519+
520+
{
521+
let fancy_ref = &fancy_num;
522+
println!("main function: {}", fancy_ref.num);
523+
// `fancy_ref` goes out of scope here
524+
}
525+
526+
let x = move || {
527+
// `fancy_num` can be moved now (no more references exist)
528+
println!("child function: {}", fancy_num.num);
529+
};
530+
531+
x();
532+
}
533+
```
534+
535+
If the lifetime of a reference isn't enough, such as in the case of threading,
536+
consider using an `Arc` to create a reference-counted value:
537+
538+
```
539+
use std::sync::Arc;
540+
use std::thread;
541+
542+
struct FancyNum {
543+
num: u8
544+
}
545+
546+
fn main() {
547+
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
548+
let fancy_ref2 = fancy_ref1.clone();
549+
550+
let x = thread::spawn(move || {
551+
// `fancy_ref1` can be moved and has a `'static` lifetime
552+
println!("child thread: {}", fancy_ref1.num);
553+
});
554+
555+
x.join().expect("child thread should finish");
556+
println!("main thread: {}", fancy_ref2.num);
557+
}
558+
```
559+
"##,
560+
457561
E0506: r##"
458562
This error occurs when an attempt is made to assign to a borrowed value.
459563
@@ -661,7 +765,6 @@ register_diagnostics! {
661765
E0500, // closure requires unique access to `..` but .. is already borrowed
662766
E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
663767
E0503, // cannot use `..` because it was mutably borrowed
664-
E0504, // cannot move `..` into closure because it is borrowed
665768
E0505, // cannot move out of `..` because it is borrowed
666769
E0508, // cannot move out of type `..`, a non-copy fixed-size array
667770
E0509, // cannot move out of type `..`, which defines the `Drop` trait

0 commit comments

Comments
 (0)