Rust: Invalid "variable does not need to be mutable" warning in 2018 edition with partially initialized structs

Created on 23 Sep 2018  Â·  5Comments  Â·  Source: rust-lang/rust

fn main() {
    let mut s: (i32, i32);
    s.0 = 3;
    s.1 = 4;
    println!("{} {}", s.0, s.1);
}

Causes the following warning:

warning: variable does not need to be mutable
 --> src/main.rs:2:9
  |
2 |     let mut s: (i32, i32);
  |         ----^
  |         |
  |         help: remove this `mut`
  |
  = note: #[warn(unused_mut)] on by default

Removing mut causes an error:

error[E0594]: cannot assign to `s.0`, as `s` is not declared as mutable
 --> src/main.rs:3:5
  |
2 |     let s: (i32, i32);
  |         - help: consider changing this to be mutable: `mut s`
3 |     s.0 = 3;
  |     ^^^^^^^ cannot assign

error[E0594]: cannot assign to `s.1`, as `s` is not declared as mutable
 --> src/main.rs:4:5
  |
2 |     let s: (i32, i32);
  |         - help: consider changing this to be mutable: `mut s`
3 |     s.0 = 3;
4 |     s.1 = 4;
  |     ^^^^^^^ cannot assign

error: aborting due to 2 previous errors

Tested on nightly on the playground. This code is stupid, but I don't think it should report "unused mut" warnings.

A-NLL NLL-diagnostics

Most helpful comment

@nikomatsakis I just like abusing compiler edge cases hoping to find bugs, this isn't from an actual program.

All 5 comments

I think the error (that partial initialization requires mut) is wrong, or at least surprising.
cc @nikomatsakis @pnkfelix

So, we decided to echo existing borrowck behavior here, which does require a mut for.. no particularly good reason (this is https://github.com/rust-lang/rust/issues/21232, a long-standing issue). I did this as a performance optimization in https://github.com/rust-lang/rust/pull/53258 with the intention that we would expand the handling of immutable variables at some later point.

The simplest thing would be to update the "mut checker" to understand this limitation, I suppose. The more complex thing would be to try and fix #21232 — this feels like something we might consider, as NLL is reaching a decent point.

In terms of how to suppress the false warning, here are a few tips:

The BorrowCheckContext has a field used_muts indicating the variables and things where a mut declaration was *required::

https://github.com/rust-lang/rust/blob/c9865b1c37f8cb8a257591e6ea0b32a5df1f3d41/src/librustc_mir/borrow_check/mod.rs#L436-L438

So we probably need to add something to that set when we see a.b = c. That is a MIR assignment, so it winds up invoking mutate_place:

https://github.com/rust-lang/rust/blob/c9865b1c37f8cb8a257591e6ea0b32a5df1f3d41/src/librustc_mir/borrow_check/mod.rs#L493-L499

Here we special case out assignments to immutable local variables (not this case):

https://github.com/rust-lang/rust/blob/c9865b1c37f8cb8a257591e6ea0b32a5df1f3d41/src/librustc_mir/borrow_check/mod.rs#L1094-L1108

and then fall through to access_place:

https://github.com/rust-lang/rust/blob/c9865b1c37f8cb8a257591e6ea0b32a5df1f3d41/src/librustc_mir/borrow_check/mod.rs#L1110-L1117

Something in there must be failing to update used_muts...

@xfix out of curiosity, how did you notice this bug? Are you relying on the current behavior of being able to assign to (but not read from) a field of an uninitialized variable?

@nikomatsakis I just like abusing compiler edge cases hoping to find bugs, this isn't from an actual program.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dnsl48 picture dnsl48  Â·  3Comments

dtolnay picture dtolnay  Â·  3Comments

SharplEr picture SharplEr  Â·  3Comments

behnam picture behnam  Â·  3Comments

mcarton picture mcarton  Â·  3Comments