&mut T is copied in MIR?

  let mut local = 0;
  let mut x = &mut local;
  f(x);
  *x = 101;

From the source codes, I know that f(x) will reborrow x. Thus, x is active later. However, when we transfer the above code into MIR. It seams that x is copied.

    let mut _0: ();
    let mut _1: i32;
    let mut _2: &mut i32;
    let  _3: ();
    debug local => _1;
    debug x => _2;
    bb0: {
        _1 = 0_i32;
        _2 = &mut _1;
        _3 = f(_2) -> [return: bb1, unwind continue];
    }
    bb1: {
        (*_2) = 101_i32;
        _1 = 10_i32;
        return;
    }

By the terminator of bb0, _2 is copied. Is it optimized?

Since &mut T does not implement Copy, is it ok to copy &mut T in MIR? Or, do I misunderstand the semantic of Copy in MIR(not trait)?

The reborrow semantics effectively happen as part of the Call terminator.

(I don't have the answer if you did, but) did you mean:

    bb0: {
        _1 = const 0_i32;
        _2 = &mut _1;
        _3 = f(copy _2) -> [return: bb1, unwind continue];
    }

(There is no copy in your OP MIR.)

You are right. The MIR from Rust Playground is right. I print the MIR on my computer. The copy is hidden.

I get it. But, why does MIR write copy _2?

There are multiple phases of MIR, and which one you're in matters. Before NLL runs, this is illegal. After NLL runs, this is entirely fine. ptr::read::<&mut T>(p) will give you a copy of a &mut in optimized MIR, for example.

3 Likes

The MIR is retrieved from rustc_internal API. I think that the NLL has ran.