Ranjit Jhala
Ranjit Jhala

Reputation: 1242

Mutating a struct's fields after a move

I was puzzled by the following behavior: could someone explain what is going on?

Consider the code:

struct Point {
    cx : u32,
}
fn main() {
    let mut p1 = Point { cx: 100 };
    let     p2 = p1; 
    p1.cx      = 5000;
    // println!("p1.x = {}", p1.cx); // disallowed as p1.cx is "moved" ... ok
    println!("p2.x = {}", p2.cx); // ==> prints 100 (!)
}

Specifically, I was puzzled that:

  1. The update to p1.cx is allowed even though the move has occurred,
  2. The value returned by p2.x is not in fact the updated 5000, but the old 100.

I was expecting the new value as there is no copy-trait (hence the move), so was expecting there is just a single cell whose updated value (5000) should be printed.

However, I must be missing something. Any tips? Thanks in advance!

Upvotes: 3

Views: 434

Answers (1)

mcarton
mcarton

Reputation: 30021

This is now forbidden.

It used to be allowed. However this was an error in the old borrow checker, and it has been made a warning then an error with the introduction of the new borrow checker (NLL).

For example, with rustc 1.39.0 and the 2015 edition you get the following warning:

warning[E0382]: assign to part of moved value: `p1`
 --> a.rs:8:5
  |
6 |     let mut p1 = Point { cx: 100 };
  |         ------ move occurs because `p1` has type `Point`, which does not implement the `Copy` trait
7 |     let p2 = p1;
  |              -- value moved here
8 |     p1.cx = 5000;
  |     ^^^^^^^^^^^^ value partially assigned here after move
  |
  = warning: this error has been downgraded to a warning for backwards compatibility with previous releases
  = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
  = note: for more information, try `rustc --explain E0729`

rustc 1.40.0 turned it into an error:

error[E0382]: assign to part of moved value: `p1`
 --> src/main.rs:7:5
  |
5 |     let mut p1 = Point { cx: 100 };
  |         ------ move occurs because `p1` has type `Point`, which does not implement the `Copy` trait
6 |     let p2 = p1;
  |              -- value moved here
7 |     p1.cx = 5000;
  |     ^^^^^^^^^^^^ value partially assigned here after move

error: aborting due to previous error

Note also that this was an error with the 2018 edition for a longer time (possibly since the creation of the edition).

See also:

Upvotes: 7

Related Questions