You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[regression - rust2018]: unused_mut lint false positives on nightly #55344
changed the title [-]unused_mut lint broken on nightly+Rust2018[/-][+][regression] Rust-2018: unused_mut lint false positives on nightly[/+]on Oct 25, 2018
changed the title [-][regression] Rust-2018: unused_mut lint false positives on nightly[/-][+][regression - rust2018]: unused_mut lint false positives on nightly[/+]on Oct 25, 2018
#54943 is about well-formedness, which I don't think is part of the code that tags whether a mut was necessary or not (which is what is triggering the unused_mut warning that is then triggering the deny(warnings) you have in there.
This is an interesting scenario in terms of what one can do to mitigate this...
@pnkfelix i've been thinking a bit about the well-formedness of unreachable code because of this. AFAICT with NLL currently unreachable code needs to be syntactically correct, to typeck and to unsafeck, but it does not need to dropck (double drops are currently allowed) or borrowck (this example).
In Rust2015 unreachable code also needs to dropck and borrowck.
The first question that should be answered is whether these changes in the well-formedness requirements of unreachable code are by design or an accident (cc @nikomatsakis ). If this is by design, then I'd suppose they have gone through an RFC and we can close this, or leave this open with the intent of maybe adding a better warning about this.
If they are by accident, then the first thing to do is to decide what should be the correct behavior here (e.g. stick to what Rust2015 does or change that to something else?).
This is considered an acceptable regression, per our usual policy on lints (see e.g. the motivation for RFC 1993. However, we may want to avoid linting about unused-mut on unreachable variables like this, just to be less annoying.
#[allow(unreachable_code)]pubfnsum_nan(){return;let v = 0;assert_eq!(v,0);
std::mem::drop(v);
std::mem::drop(v);assert_eq!(v,1);}
where no errors are emitted even though the unreachable code has a double drop, or this code:
#[allow(unreachable_code, unused_mut)]pubfnsum_nan(){return;letmut v = 0;assert_eq!(v,0);let x = &mut v;assert_eq!(*x,0);*x = 1;let y = &mut v;assert_eq!(*y,1);assert_eq!(*x,1);}
where two mutable references can be created and compile fine in unreachable code.
The first question that should be answered is whether these changes in the well-formedness requirements of unreachable code are by design or an accident (cc @nikomatsakis ). If this is by design, then I'd suppose they have gone through an RFC and we can close this, or leave this open with the intent of maybe adding a better warning about this.
I think at least some of the changes you are describing here are definitely by design.
The NLL RFC stated that lifetimes were going to be based on the control-flow graph. This included details like "the lifetime 'a must only outlive those portions of 'b that are reachable from P."
Giiven that this was always going to be a control-flow sensitive analysis, it seems entirely understandable that the new borrow-check analysis is going to only consider code that is actually reachable in the control flow.
So, my initial reaction is that the examples you describe are not all that surprising to me.
Having said that ... that same RFC did document a number of changes that were being included in order to deal with infinite loops.
(A stray thought: Would it be bonkers to use similar false unwind edges after return statements...?)
Update: it almost certainly wouldn't be trivial to add such a change; after all, part of the point of adding the false unwind edge after loops was to make it look like destructors would run. But return statements already have that effect... I guess we could make the false-edges conditional (which is similar to what we do in the false-edges we add to match arms...)
triage: I have tagged this as NLL-diagnostics (rather than NLL-complete).
My reasoning: Even though this is an example where one might argue that NLL is causing the compiler to regress (and fail to compile previously compiled code, which would usually yield an NLL-complete issue), that failure to compile is a consequence of the use of #![deny(warnings)], and our standard policy is that the compiler is free to add new warnings; cap-lints is meant to take care of downstream crates that have not been updated to account for any such warnings, as @nikomatsakis stated above.
Interestingly, the following example provided by @matthewjasper has the same behavior (of triggering the lint in question) on both the 2015 and 2018 editions (play)
#![deny(warnings)]#[allow(unreachable_code)]pubfnsum_nan(){letmut v;
v = 0;assert_eq!(v,0);return;
v = 1;assert_eq!(v,1);}fnmain(){}
(I mention this mostly because I am not sure exactly what mental model one is meant to apply to reason about when the lint here will and won't fire...)
Activity
[-]unused_mut lint broken on nightly+Rust2018[/-][+][regression] Rust-2018: unused_mut lint false positives on nightly[/+][-][regression] Rust-2018: unused_mut lint false positives on nightly[/-][+][regression - rust2018]: unused_mut lint false positives on nightly[/+]matthewjasper commentedon Oct 27, 2018
Well, the code compiles (in Rust2018) without
mut, so the lint's not exactly wrong, even if the behaviour is surprising.gnzlbg commentedon Oct 27, 2018
@matthewjasper this is caused by the NLL feature, so maybe this is a consequence of #54943 ?
pnkfelix commentedon Oct 29, 2018
#54943 is about well-formedness, which I don't think is part of the code that tags whether a
mutwas necessary or not (which is what is triggering theunused_mutwarning that is then triggering thedeny(warnings)you have in there.This is an interesting scenario in terms of what one can do to mitigate this...
gnzlbg commentedon Oct 30, 2018
@pnkfelix i've been thinking a bit about the well-formedness of unreachable code because of this. AFAICT with NLL currently unreachable code needs to be syntactically correct, to
typeckand tounsafeck, but it does not need todropck(double drops are currently allowed) orborrowck(this example).In Rust2015 unreachable code also needs to
dropckandborrowck.gnzlbg commentedon Oct 30, 2018
The first question that should be answered is whether these changes in the well-formedness requirements of unreachable code are by design or an accident (cc @nikomatsakis ). If this is by design, then I'd suppose they have gone through an RFC and we can close this, or leave this open with the intent of maybe adding a better warning about this.
If they are by accident, then the first thing to do is to decide what should be the correct behavior here (e.g. stick to what Rust2015 does or change that to something else?).
nikomatsakis commentedon Oct 30, 2018
This is considered an acceptable regression, per our usual policy on lints (see e.g. the motivation for RFC 1993. However, we may want to avoid linting about unused-mut on unreachable variables like this, just to be less annoying.
pnkfelix commentedon Oct 30, 2018
(in particular the fact that the binding is itself unreachable makes this lint seem especially weird, at least to me...)
1 remaining item
gnzlbg commentedon Oct 30, 2018
Another variant of this bug is:
where no errors are emitted even though the unreachable code has a double drop, or this code:
where two mutable references can be created and compile fine in unreachable code.
pnkfelix commentedon Oct 30, 2018
@gnzlbg wrote:
I think at least some of the changes you are describing here are definitely by design.
The NLL RFC stated that lifetimes were going to be based on the control-flow graph. This included details like "the lifetime
'amust only outlive those portions of'bthat are reachable from P."Giiven that this was always going to be a control-flow sensitive analysis, it seems entirely understandable that the new borrow-check analysis is going to only consider code that is actually reachable in the control flow.
So, my initial reaction is that the examples you describe are not all that surprising to me.
Having said that ... that same RFC did document a number of changes that were being included in order to deal with infinite loops.
returnstatements...?)returnstatements already have that effect... I guess we could make the false-edges conditional (which is similar to what we do in the false-edges we add tomatcharms...)pnkfelix commentedon Nov 6, 2018
triage: I have tagged this as NLL-diagnostics (rather than NLL-complete).
My reasoning: Even though this is an example where one might argue that NLL is causing the compiler to regress (and fail to compile previously compiled code, which would usually yield an NLL-complete issue), that failure to compile is a consequence of the use of
#![deny(warnings)], and our standard policy is that the compiler is free to add new warnings; cap-lints is meant to take care of downstream crates that have not been updated to account for any such warnings, as @nikomatsakis stated above.pnkfelix commentedon Nov 6, 2018
Triage: I don't think any hypothetical "fix" (if we make one) would be beta-backported. So the only question is what priority to assign.
With regards to prioritization... I'm torn between P-high or P-medium on this one. I think I'll wait to discuss it at the NLL team meeting tonight.
pnkfelix commentedon Nov 6, 2018
Interestingly, the following example provided by @matthewjasper has the same behavior (of triggering the lint in question) on both the 2015 and 2018 editions (play)
(I mention this mostly because I am not sure exactly what mental model one is meant to apply to reason about when the lint here will and won't fire...)
pnkfelix commentedon Nov 6, 2018
making executive decision to tag this as P-medium
Rollup merge of rust-lang#55758 - davidtwco:issue-55344, r=pnkfelix
Rollup merge of rust-lang#55758 - davidtwco:issue-55344, r=pnkfelix
gnzlbg commentedon Nov 9, 2018
Thank you all!