Skip to content

Commit 5071728

Browse files
committed
Add detailed error explanation for E0509
Edited the error explanation for E0509 to clarify dropping of moved fields Edited the error explanation for E0509 to clarify move out of Drop value language Fixed typeo in last commit to E0509 Switched to erroneous code wording
1 parent 3157691 commit 5071728

File tree

1 file changed

+95
-1
lines changed

1 file changed

+95
-1
lines changed

src/librustc_borrowck/diagnostics.rs

+95-1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,101 @@ You can find more information about borrowing in the rust-book:
429429
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
430430
"##,
431431

432+
E0509: r##"
433+
This error occurs when an attempt is made to move out of a value whose type
434+
implements the `Drop` trait.
435+
436+
Example of erroneous code:
437+
438+
```compile_fail
439+
struct FancyNum {
440+
num: usize
441+
}
442+
443+
struct DropStruct {
444+
fancy: FancyNum
445+
}
446+
447+
impl Drop for DropStruct {
448+
fn drop(&mut self) {
449+
// Destruct DropStruct, possibly using FancyNum
450+
}
451+
}
452+
453+
fn main() {
454+
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
455+
let fancy_field = drop_struct.fancy; // Error E0509
456+
println!("Fancy: {}", fancy_field.num);
457+
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
458+
}
459+
```
460+
461+
Here, we tried to move a field out of a struct of type `DropStruct` which
462+
implements the `Drop` trait. However, a struct cannot be dropped if one or
463+
more of its fields have been moved.
464+
465+
Structs implementing the `Drop` trait have an implicit destructor that gets
466+
called when they go out of scope. This destructor may use the fields of the
467+
struct, so moving out of the struct could make it impossible to run the
468+
destructor. Therefore, we must think of all values whose type implements the
469+
`Drop` trait as single units whose fields cannot be moved.
470+
471+
This error can be fixed by creating a reference to the fields of a struct,
472+
enum, or tuple using the `ref` keyword:
473+
474+
```
475+
struct FancyNum {
476+
num: usize
477+
}
478+
479+
struct DropStruct {
480+
fancy: FancyNum
481+
}
482+
483+
impl Drop for DropStruct {
484+
fn drop(&mut self) {
485+
// Destruct DropStruct, possibly using FancyNum
486+
}
487+
}
488+
489+
fn main() {
490+
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
491+
let ref fancy_field = drop_struct.fancy; // No more errors!
492+
println!("Fancy: {}", fancy_field.num);
493+
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
494+
}
495+
```
496+
497+
Note that this technique can also be used in the arms of a match expression:
498+
499+
```
500+
struct FancyNum {
501+
num: usize
502+
}
503+
504+
enum DropEnum {
505+
Fancy(FancyNum)
506+
}
507+
508+
impl Drop for DropEnum {
509+
fn drop(&mut self) {
510+
// Destruct DropEnum, possibly using FancyNum
511+
}
512+
}
513+
514+
fn main() {
515+
// Creates and enum of type `DropEnum`, which implements `Drop`
516+
let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
517+
match drop_enum {
518+
// Creates a reference to the inside of `DropEnum::Fancy`
519+
DropEnum::Fancy(ref fancy_field) => // No error!
520+
println!("It was fancy-- {}!", fancy_field.num),
521+
}
522+
// implicit call to `drop_enum.drop()` as drop_enum goes out of scope
523+
}
524+
```
525+
"##,
526+
432527
}
433528

434529
register_diagnostics! {
@@ -443,6 +538,5 @@ register_diagnostics! {
443538
E0505, // cannot move out of `..` because it is borrowed
444539
E0506, // cannot assign to `..` because it is borrowed
445540
E0508, // cannot move out of type `..`, a non-copy fixed-size array
446-
E0509, // cannot move out of type `..`, which defines the `Drop` trait
447541
E0524, // two closures require unique access to `..` at the same time
448542
}

0 commit comments

Comments
 (0)