Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unnecessary parentheses warning is printed twice #88256

Closed
jDomantas opened this issue Aug 23, 2021 · 7 comments · Fixed by #88493
Closed

Unnecessary parentheses warning is printed twice #88256

jDomantas opened this issue Aug 23, 2021 · 7 comments · Fixed by #88493
Labels
C-bug Category: This is a bug.

Comments

@jDomantas
Copy link
Contributor

This code:

pub fn repro() {
    if let Some(_a) = foo() {
        let _b = (foo());
    }
}

fn foo() -> Option<i32> { None }

Gives unnecessary parentheses warning twice:

warning: unnecessary parentheses around assigned value
 --> interpreter\src\lib.rs:3:18
  |
3 |         let _b = (foo());
  |                  ^^^^^^^ help: remove these parentheses
  |
  = note: `#[warn(unused_parens)]` on by default

warning: unnecessary parentheses around assigned value
 --> interpreter\src\lib.rs:3:18
  |
3 |         let _b = (foo());
  |                  ^^^^^^^ help: remove these parentheses

warning: 2 warnings emitted

Reproduced with stable 1.54.0 and nightly 2021-08-22 af14075 on playground.

Playground link

@jDomantas jDomantas added the C-bug Category: This is a bug. label Aug 23, 2021
@ehuss
Copy link
Contributor

ehuss commented Aug 24, 2021

Bisected the regression to #82854.

@estebank Do you happen to know why the deduplicator here is not deduplicating these? I ran into another strange duplicate diagnostic in another situation, too.

@chenyukang
Copy link
Member

@ehuss I have some investigation on this.
This is caused by two different hash values calculated in here.

The two diagnostics are the same, except that the first diagnostic has children, and the latter one doesn't have children.
I'm trying to make a fix on it.

@chenyukang
Copy link
Member

My draft commit fixed this issue, how do you think about it, @ehuss .
Need to add a test case for it.

@ehuss
Copy link
Contributor

ehuss commented Aug 29, 2021

I'm not an expert on the compiler, so I'm not the right person to ask. However, I would say changing the hash might not be a good idea, since I think it would be bad to lose the children, or have it be non-deterministic which diagnostic gets emitted. It's also dangerous to have the Hash implementation out of sync with PartialEq since some code may be assuming those are in sync.

For this particular issue, I would investigate more why there are multiple lints getting triggered with different sets of children, and see if it is possible to avoid emitting multiple lints. Or if multiple are emitted to make sure they are the same.

@chenyukang
Copy link
Member

chenyukang commented Aug 30, 2021

I have more debugging on this.

There are two execute paths finally flow to analyze the expr,

fn visit_expr(&mut self, e: &'a ast::Expr) {
        self.with_lint_attrs(e.id, &e.attrs, |cx| {
            run_early_pass!(cx, check_expr, e);       // C1: create fir the diagnostic 
            ast_visit::walk_expr(cx, e);                     // C2: create the second diagnostic
        })
    }

The C1 will finally call to check_expr
The C2 will finally call to check_stmt

Seems it's common in Rustc lint, since I see some code is trying to remove duplicates.

Then, why there is only the first diagnostic that contains children? The child is a note for diagnostic:

warning: unnecessary parentheses around assigned value
  --> ./src/main.rs:35:18
   |
35 |         let _b = (foo_b());
   |                  ^^^^^^^^^ help: remove these parentheses
   |
   = note: `#[warn(unused_parens)]` on by default                // This is the children part.

This is because when lint try to add a diagnostic, diag_once is called to add note for it, but this line of code get the fresh as false for the second diagnostic, so it won't add a note:

 let id_span_message = (msg_id, span_maybe, message.to_owned());
 let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message);

@chenyukang
Copy link
Member

chenyukang commented Aug 30, 2021

@chenyukang
Copy link
Member

How do you think @estebank , do you think custom Hash is the right way for this? I'm a beginner in hacking Rust compiler, maybe you have any more idea.

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 6, 2021
@bors bors closed this as completed in ca27f03 Sep 6, 2021
flip1995 pushed a commit to flip1995/rust that referenced this issue Sep 8, 2021
flip1995 pushed a commit to flip1995/rust that referenced this issue Sep 8, 2021
calebcartwright pushed a commit to calebcartwright/rust that referenced this issue Oct 20, 2021
calebcartwright pushed a commit to calebcartwright/rust that referenced this issue Oct 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants