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

#[expect(unused_imports)] does not work correctly on grouped imports #127884

Closed
vxpm opened this issue Jul 17, 2024 · 8 comments · Fixed by #130050
Closed

#[expect(unused_imports)] does not work correctly on grouped imports #127884

vxpm opened this issue Jul 17, 2024 · 8 comments · Fixed by #130050
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. F-lint_reasons `#![feature(lint_reasons)]` L-unused_imports Lint: unused_imports T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@vxpm
Copy link
Contributor

vxpm commented Jul 17, 2024

the following snippet:

#[expect(unused_imports)]
use std::{io, fs};

results in the following compiler output:

warning: this lint expectation is unfulfilled
 --> src/main.rs:2:10
  |
2 | #[expect(unused_imports)]
  |          ^^^^^^^^^^^^^^
  |
  = note: ​`#[warn(unfulfilled_lint_expectations)]​` on by default

but removing the #[expect] results in:

warning: unused imports: ​`fs​` and ​`io​`
 --> src/main.rs:2:11
  |
2 | use std::{io, fs};
  |           ^^  ^^
  |
  = note: ​`#[warn(unused_imports)]​` on by default

so it is, indeed, supressing the lint - which means the first warning is wrong. it is important to note that the same does not happen on imports of a single item.

rustc version:

rustc 1.81.0-nightly (24d2ac0b5 2024-07-15)
binary: rustc
commit-hash: 24d2ac0b56fcbde13d827745f66e73efb1e17156
commit-date: 2024-07-15
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly
LLVM version: 18.1.7
@vxpm vxpm added the C-bug Category: This is a bug. label Jul 17, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 17, 2024
@jieyouxu jieyouxu added A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. L-unused_imports Lint: unused_imports labels Jul 18, 2024
@tgross35
Copy link
Contributor

cc @xFrednet who has been handling expect

@xFrednet xFrednet added the F-lint_reasons `#![feature(lint_reasons)]` label Jul 18, 2024
@xFrednet
Copy link
Member

Thank you for the ping. So my educated guess is that this issue comes from how rustc handles group imports. The import from the issue is internally desugared into three separate imports, like this (Playground "Show HIR"):

#[expect(unused_imports)]
use ::{};
#[expect(unused_imports)]
use std::io;
#[expect(unused_imports)]
use std::fs;

From the text output of HIR it looks like the attributes are duplicated. This in turn creates additional expectations which are not fulfilled.

The question is now, hot to figure out, that these items and attributes all originate from the same item.

@cjgillot do you maybe have an idea on this one?

@tgross35 tgross35 removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 18, 2024
@cjgillot
Copy link
Contributor

That's not the only place where we duplicate attributes. I had to partially work around it in #127313, but that's not a good solution in general.

Right now, the diagnostic infra stores the stable LintExpectationId, we update unstable -> stable before emitting diagnostics, and we try to match the stable id.

What if we did the other way?

I mean:

  • In the DiagCtxtInner, store keep fulfilled_expectations: Vec<LintExpectationId> but stop stashing diagnostics to convert unstable->stable version, just emit them. Emitting an unstable id should only happen from pre-lowering code, which is not incremental, so we won't try to decode such a diagnostic to re-emit it.
  • In lint_expectations(()), stop computing the unstable -> stable mapping.
  • In check_expectations(()), make a FxHashSet<(AttrId, u16)> from the global fulfilled expectations, and use it to check what lint_expectations(()) returns.

Step 3 should be ok for incr comp, as check_expectations is eval_always.

Does that make sense to you?

@xFrednet
Copy link
Member

I'm not sure, I fully understand you. Does this rephrasing sound reasonably close?

  1. The pre-lowering code, that can emit unstable LintExpectationIDs is always executed. Instead of transforming these ID's we just don't store between compilations as they will be emitted again during the next run.
  2. lint_expectations() returns all lint expectations defined by the user.
  3. check_expectations() will take the stable IDs and map them to their unstable versions. These unstable ID's are then used to fulfill the expectations from lint_expectations(). And this should fix this issue since the AST hasn't duplicated any attributes yet.

@cjgillot
Copy link
Contributor

Yes.

@xFrednet
Copy link
Member

xFrednet commented Jul 20, 2024

On what level does lint_expectations() operate? Is it on the AST or HIR?

Because, if it's on the HIR, we still need to find a way to map from duplicated attributes back to their original single ones. Don't we?

@cjgillot
Copy link
Contributor

lint_expectations() can operate on either, depending on what is easier to code. You could also have the early lint pass feed it.

check_expectations() can always look at the attribute in HIR to do this mapping. Given id: LintExpectationId, something like:

match id {
    Unstable { attr_id, lint_index: Some(lint_index) } => (attr_id, lint_index),
    Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
        // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
        let attr_id = tcx.hir().attrs(hir_id)[attr_index].id;
        (attr_id, lint_index)
    }
    _ => bug!(),
}

When we duplicate the attributes, we don't change the AttrId, so relying on it is ok.

@xFrednet
Copy link
Member

xFrednet commented Jul 20, 2024

Interesting, yep, then this should work :D

Is this something that can/should be done with #127313?

If we want to make it a followup PR, we should probably ping the reviewer or reroll 🤔

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 6, 2024
Enumerate lint expectations using AttrId

This PR implements the idea I outlined in rust-lang#127884 (comment)

We can uniquely identify a lint expectation `#[expect(lint0, lint1...)]` using the `AttrId` and the index of the lint inside the attribute. This PR uses this property in `check_expectations`.

In addition, this PR stops stashing expected diagnostics to wait for the unstable -> stable `LintExpectationId` mapping: if the lint is emitted with an unstable attribute, it must have been emitted by an `eval_always` query (like inside the resolver), so won't be loaded from cache. Decoding an `AttrId` from the on-disk cache ICEs, so we have no risk of accidentally checking an expectation.

Fixes rust-lang#127884

cc `@xFrednet`
bors added a commit to rust-lang-ci/rust that referenced this issue Sep 10, 2024
Enumerate lint expectations using AttrId

This PR implements the idea I outlined in rust-lang#127884 (comment)

We can uniquely identify a lint expectation `#[expect(lint0, lint1...)]` using the `AttrId` and the index of the lint inside the attribute. This PR uses this property in `check_expectations`.

In addition, this PR stops stashing expected diagnostics to wait for the unstable -> stable `LintExpectationId` mapping: if the lint is emitted with an unstable attribute, it must have been emitted by an `eval_always` query (like inside the resolver), so won't be loaded from cache. Decoding an `AttrId` from the on-disk cache ICEs, so we have no risk of accidentally checking an expectation.

Fixes rust-lang#127884

cc `@xFrednet`
@bors bors closed this as completed in 4c5fc2c Sep 11, 2024
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 12, 2024
Enumerate lint expectations using AttrId

This PR implements the idea I outlined in rust-lang/rust#127884 (comment)

We can uniquely identify a lint expectation `#[expect(lint0, lint1...)]` using the `AttrId` and the index of the lint inside the attribute. This PR uses this property in `check_expectations`.

In addition, this PR stops stashing expected diagnostics to wait for the unstable -> stable `LintExpectationId` mapping: if the lint is emitted with an unstable attribute, it must have been emitted by an `eval_always` query (like inside the resolver), so won't be loaded from cache. Decoding an `AttrId` from the on-disk cache ICEs, so we have no risk of accidentally checking an expectation.

Fixes rust-lang/rust#127884

cc `@xFrednet`
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Sep 25, 2024
Enumerate lint expectations using AttrId

This PR implements the idea I outlined in rust-lang/rust#127884 (comment)

We can uniquely identify a lint expectation `#[expect(lint0, lint1...)]` using the `AttrId` and the index of the lint inside the attribute. This PR uses this property in `check_expectations`.

In addition, this PR stops stashing expected diagnostics to wait for the unstable -> stable `LintExpectationId` mapping: if the lint is emitted with an unstable attribute, it must have been emitted by an `eval_always` query (like inside the resolver), so won't be loaded from cache. Decoding an `AttrId` from the on-disk cache ICEs, so we have no risk of accidentally checking an expectation.

Fixes rust-lang/rust#127884

cc `@xFrednet`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. F-lint_reasons `#![feature(lint_reasons)]` L-unused_imports Lint: unused_imports T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants