Skip to content

Commit 57fa783

Browse files
committed
Rollup merge of rust-lang#33383 - cramertj:E0509, r=Manishearth
Add detailed error explanation for E0509 Part of rust-lang#32777
2 parents 9f5f997 + 5071728 commit 57fa783

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
@@ -653,6 +653,101 @@ You can find more information about borrowing in the rust-book:
653653
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
654654
"##,
655655

656+
E0509: r##"
657+
This error occurs when an attempt is made to move out of a value whose type
658+
implements the `Drop` trait.
659+
660+
Example of erroneous code:
661+
662+
```compile_fail
663+
struct FancyNum {
664+
num: usize
665+
}
666+
667+
struct DropStruct {
668+
fancy: FancyNum
669+
}
670+
671+
impl Drop for DropStruct {
672+
fn drop(&mut self) {
673+
// Destruct DropStruct, possibly using FancyNum
674+
}
675+
}
676+
677+
fn main() {
678+
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
679+
let fancy_field = drop_struct.fancy; // Error E0509
680+
println!("Fancy: {}", fancy_field.num);
681+
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
682+
}
683+
```
684+
685+
Here, we tried to move a field out of a struct of type `DropStruct` which
686+
implements the `Drop` trait. However, a struct cannot be dropped if one or
687+
more of its fields have been moved.
688+
689+
Structs implementing the `Drop` trait have an implicit destructor that gets
690+
called when they go out of scope. This destructor may use the fields of the
691+
struct, so moving out of the struct could make it impossible to run the
692+
destructor. Therefore, we must think of all values whose type implements the
693+
`Drop` trait as single units whose fields cannot be moved.
694+
695+
This error can be fixed by creating a reference to the fields of a struct,
696+
enum, or tuple using the `ref` keyword:
697+
698+
```
699+
struct FancyNum {
700+
num: usize
701+
}
702+
703+
struct DropStruct {
704+
fancy: FancyNum
705+
}
706+
707+
impl Drop for DropStruct {
708+
fn drop(&mut self) {
709+
// Destruct DropStruct, possibly using FancyNum
710+
}
711+
}
712+
713+
fn main() {
714+
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
715+
let ref fancy_field = drop_struct.fancy; // No more errors!
716+
println!("Fancy: {}", fancy_field.num);
717+
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
718+
}
719+
```
720+
721+
Note that this technique can also be used in the arms of a match expression:
722+
723+
```
724+
struct FancyNum {
725+
num: usize
726+
}
727+
728+
enum DropEnum {
729+
Fancy(FancyNum)
730+
}
731+
732+
impl Drop for DropEnum {
733+
fn drop(&mut self) {
734+
// Destruct DropEnum, possibly using FancyNum
735+
}
736+
}
737+
738+
fn main() {
739+
// Creates and enum of type `DropEnum`, which implements `Drop`
740+
let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
741+
match drop_enum {
742+
// Creates a reference to the inside of `DropEnum::Fancy`
743+
DropEnum::Fancy(ref fancy_field) => // No error!
744+
println!("It was fancy-- {}!", fancy_field.num),
745+
}
746+
// implicit call to `drop_enum.drop()` as drop_enum goes out of scope
747+
}
748+
```
749+
"##,
750+
656751
}
657752

658753
register_diagnostics! {
@@ -664,6 +759,5 @@ register_diagnostics! {
664759
E0504, // cannot move `..` into closure because it is borrowed
665760
E0505, // cannot move out of `..` because it is borrowed
666761
E0508, // cannot move out of type `..`, a non-copy fixed-size array
667-
E0509, // cannot move out of type `..`, which defines the `Drop` trait
668762
E0524, // two closures require unique access to `..` at the same time
669763
}

0 commit comments

Comments
 (0)