]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #33386 - cramertj:E0504, r=steveklabnik
authorSteve Klabnik <steve@steveklabnik.com>
Wed, 11 May 2016 13:27:43 +0000 (09:27 -0400)
committerSteve Klabnik <steve@steveklabnik.com>
Wed, 11 May 2016 13:27:43 +0000 (09:27 -0400)
Add detailed error explanation for E0504

Part of #32777

1  2 
src/librustc_borrowck/diagnostics.rs

index 8d9b88e899be26974252f228d82dc0eac5be83d2,1802ab43161fbc4ca4086bfcf936442533a1e733..0687faa112f5e9efbaf28f46e1dffac2389dfe87
@@@ -454,6 -454,110 +454,110 @@@ fn foo(a: &mut i32) 
  ```
  "##,
  
+ E0504: r##"
+ This error occurs when an attempt is made to move a borrowed variable into a
+ closure.
+ Example of erroneous code:
+ ```compile_fail
+ struct FancyNum {
+     num: u8
+ }
+ fn main() {
+     let fancy_num = FancyNum { num: 5 };
+     let fancy_ref = &fancy_num;
+     let x = move || {
+         println!("child function: {}", fancy_num.num);
+         // error: cannot move `fancy_num` into closure because it is borrowed
+     };
+     x();
+     println!("main function: {}", fancy_ref.num);
+ }
+ ```
+ Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
+ the closure `x`. There is no way to move a value into a closure while it is
+ borrowed, as that would invalidate the borrow.
+ If the closure can't outlive the value being moved, try using a reference
+ rather than moving:
+ ```
+ struct FancyNum {
+     num: u8
+ }
+ fn main() {
+     let fancy_num = FancyNum { num: 5 };
+     let fancy_ref = &fancy_num;
+     let x = move || {
+         // fancy_ref is usable here because it doesn't move `fancy_num`
+         println!("child function: {}", fancy_ref.num);
+     };
+     x();
+     println!("main function: {}", fancy_num.num);
+ }
+ ```
+ If the value has to be borrowed and then moved, try limiting the lifetime of
+ the borrow using a scoped block:
+ ```
+ struct FancyNum {
+     num: u8
+ }
+ fn main() {
+     let fancy_num = FancyNum { num: 5 };
+     {
+         let fancy_ref = &fancy_num;
+         println!("main function: {}", fancy_ref.num);
+         // `fancy_ref` goes out of scope here
+     }
+     let x = move || {
+         // `fancy_num` can be moved now (no more references exist)
+         println!("child function: {}", fancy_num.num);
+     };
+     x();
+ }
+ ```
+ If the lifetime of a reference isn't enough, such as in the case of threading,
+ consider using an `Arc` to create a reference-counted value:
+ ```
+ use std::sync::Arc;
+ use std::thread;
+ struct FancyNum {
+     num: u8
+ }
+ fn main() {
+     let fancy_ref1 = Arc::new(FancyNum { num: 5 });
+     let fancy_ref2 = fancy_ref1.clone();
+     let x = thread::spawn(move || {
+         // `fancy_ref1` can be moved and has a `'static` lifetime
+         println!("child thread: {}", fancy_ref1.num);
+     });
+     x.join().expect("child thread should finish");
+     println!("main thread: {}", fancy_ref2.num);
+ }
+ ```
+ "##,
  E0506: r##"
  This error occurs when an attempt is made to assign to a borrowed value.
  
@@@ -653,101 -757,6 +757,101 @@@ You can find more information about bor
  http://doc.rust-lang.org/stable/book/references-and-borrowing.html
  "##,
  
 +E0509: r##"
 +This error occurs when an attempt is made to move out of a value whose type
 +implements the `Drop` trait.
 +
 +Example of erroneous code:
 +
 +```compile_fail
 +struct FancyNum {
 +    num: usize
 +}
 +
 +struct DropStruct {
 +    fancy: FancyNum
 +}
 +
 +impl Drop for DropStruct {
 +    fn drop(&mut self) {
 +        // Destruct DropStruct, possibly using FancyNum
 +    }
 +}
 +
 +fn main() {
 +    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
 +    let fancy_field = drop_struct.fancy; // Error E0509
 +    println!("Fancy: {}", fancy_field.num);
 +    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
 +}
 +```
 +
 +Here, we tried to move a field out of a struct of type `DropStruct` which
 +implements the `Drop` trait. However, a struct cannot be dropped if one or
 +more of its fields have been moved.
 +
 +Structs implementing the `Drop` trait have an implicit destructor that gets
 +called when they go out of scope. This destructor may use the fields of the
 +struct, so moving out of the struct could make it impossible to run the
 +destructor. Therefore, we must think of all values whose type implements the
 +`Drop` trait as single units whose fields cannot be moved.
 +
 +This error can be fixed by creating a reference to the fields of a struct,
 +enum, or tuple using the `ref` keyword:
 +
 +```
 +struct FancyNum {
 +    num: usize
 +}
 +
 +struct DropStruct {
 +    fancy: FancyNum
 +}
 +
 +impl Drop for DropStruct {
 +    fn drop(&mut self) {
 +        // Destruct DropStruct, possibly using FancyNum
 +    }
 +}
 +
 +fn main() {
 +    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
 +    let ref fancy_field = drop_struct.fancy; // No more errors!
 +    println!("Fancy: {}", fancy_field.num);
 +    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
 +}
 +```
 +
 +Note that this technique can also be used in the arms of a match expression:
 +
 +```
 +struct FancyNum {
 +    num: usize
 +}
 +
 +enum DropEnum {
 +    Fancy(FancyNum)
 +}
 +
 +impl Drop for DropEnum {
 +    fn drop(&mut self) {
 +        // Destruct DropEnum, possibly using FancyNum
 +    }
 +}
 +
 +fn main() {
 +    // Creates and enum of type `DropEnum`, which implements `Drop`
 +    let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
 +    match drop_enum {
 +        // Creates a reference to the inside of `DropEnum::Fancy`
 +        DropEnum::Fancy(ref fancy_field) => // No error!
 +            println!("It was fancy-- {}!", fancy_field.num),
 +    }
 +    // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
 +}
 +```
 +"##,
 +
  }
  
  register_diagnostics! {
      E0500, // closure requires unique access to `..` but .. is already borrowed
      E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
      E0503, // cannot use `..` because it was mutably borrowed
-     E0504, // cannot move `..` into closure because it is borrowed
      E0505, // cannot move out of `..` because it is borrowed
      E0508, // cannot move out of type `..`, a non-copy fixed-size array
 -    E0509, // cannot move out of type `..`, which defines the `Drop` trait
      E0524, // two closures require unique access to `..` at the same time
  }