Skip to content

[regression - rust2018]: unused_mut lint false positives on nightly #55344

Closed

Description

@gnzlbg

I believe this is a regression in rust2018 nightly (it wasn't triggering in earlier rust2018 builds).


Playground

#![deny(warnings)]  

#[allow(unreachable_code)]
pub fn sum_nan() {
    // return;

    let mut v = 0;
    assert_eq!(v, 0);
    v = 1;
    assert_eq!(v, 1);
}

fn main() {}

works correctly, but uncommenting the return; (play) errors with:

error: variable does not need to be mutable
 --> src/main.rs:7:9
  |
7 |     let mut v = 0;
  |         ----^
  |         |
  |         help: remove this `mut`

This only happens with Rust2018 on nightly (Rust2015 works fine).

Activity

  1. changed the title [-]unused_mut lint broken on nightly+Rust2018[/-] [+][regression] Rust-2018: unused_mut lint false positives on nightly[/+] on Oct 25, 2018
  2. 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
  3. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    C-bugCategory: This is a bug.
    on Oct 25, 2018
  4. matthewjasper commented on Oct 27, 2018

    @matthewjasper
    Contributor

    Well, the code compiles (in Rust2018) without mut, so the lint's not exactly wrong, even if the behaviour is surprising.

  5. gnzlbg commented on Oct 27, 2018

    @gnzlbg
    ContributorAuthor

    @matthewjasper this is caused by the NLL feature, so maybe this is a consequence of #54943 ?

  6. pnkfelix commented on Oct 29, 2018

    @pnkfelix
    Contributor

    #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...

  7. gnzlbg commented on Oct 30, 2018

    @gnzlbg
    ContributorAuthor

    @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.

  8. gnzlbg commented on Oct 30, 2018

    @gnzlbg
    ContributorAuthor

    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?).

  9. self-assigned this
    on Oct 30, 2018
  10. nikomatsakis commented on Oct 30, 2018

    @nikomatsakis
    Contributor

    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.

  11. pnkfelix commented on Oct 30, 2018

    @pnkfelix
    Contributor

    (in particular the fact that the binding is itself unreachable makes this lint seem especially weird, at least to me...)

  12. 1 remaining item

  13. gnzlbg commented on Oct 30, 2018

    @gnzlbg
    ContributorAuthor

    Another variant of this bug is:

    #[allow(unreachable_code)]
    pub fn sum_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)]
    pub fn sum_nan() {
        return;
    
        let mut 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.

  14. pnkfelix commented on Oct 30, 2018

    @pnkfelix
    Contributor

    @gnzlbg wrote:

    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...)
  15. pnkfelix commented on Nov 6, 2018

    @pnkfelix
    Contributor

    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.

  16. pnkfelix commented on Nov 6, 2018

    @pnkfelix
    Contributor

    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.

  17. self-assigned this
    on Nov 6, 2018
  18. pnkfelix commented on Nov 6, 2018

    @pnkfelix
    Contributor

    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)]
    pub fn sum_nan() {
        let mut v;
        v = 0;
        assert_eq!(v, 0);
        return;
        v = 1;
        assert_eq!(v, 1);
    }
    
    fn main() {}

    (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...)

  19. pnkfelix commented on Nov 6, 2018

    @pnkfelix
    Contributor

    making executive decision to tag this as P-medium

  20. added a commit that references this issue on Nov 8, 2018
    543d645
  21. added a commit that references this issue on Nov 9, 2018
    7944075
  22. gnzlbg commented on Nov 9, 2018

    @gnzlbg
    ContributorAuthor

    Thank you all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

A-NLLArea: Non-lexical lifetimes (NLL)A-edition-2018Area: The 2018 editionA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-bugCategory: This is a bug.NLL-diagnosticsWorking towards the "diagnostic parity" goalP-mediumMedium priorityT-langRelevant to the language team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions