Closed
Description
I tried this code:
#[must_use]
pub fn important() -> i32 {
42
}
pub fn foo() {
#[expect(unused_must_use)]
important();
}
I expected #[expect]
to catch unused_must_use
lint and suppress it, as it should. Instead, compiler issues a diagnostic both about unused #[must_use]
value and unfulfilled lint expectation:
warning: unused return value of `important` that must be used
--> src/lib.rs:8:5
|
8 | important();
| ^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
8 | let _ = important();
| +++++++
warning: this lint expectation is unfulfilled
--> src/lib.rs:7:14
|
7 | #[expect(unused_must_use)]
| ^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
It does work as expected though if #[expect]
is applied to function.
Meta
I used the latest stable (Rust 1.81), but it is reproducible both on latest beta (2024-09-04 c7c49f4) and latest nightly (2024-09-05 9c01301).
@rustbot labels: +F-lint_reasons, +A-diagnostics
Activity
[-]`#[expect(unused_must_use]` does not work when applied directly to statement[/-][+]`#[expect(unused_must_use)]` does not work when applied directly to statement[/+]gurry commentedon Sep 10, 2024
@rustbot claim
gurry commentedon Sep 11, 2024
This issue is not limited to just
expect
. Others attrs likeallow
ordeny
don't work either. For instance, the following variant of the reproducer withexpect
replaced withallow
emits the warning even though it shouldn't:Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5847d1b5165f0da09b093559c6d20f6e
This broken behaviour goes as far back as at least 2021 (couldn't build and test earlier rustc)
Underlying reason
We emit the lint on the
Stmt
HIR node corresponding toimportant();
. However, theExpect
orAllow
levels, which are supposed to override the defaultWarn
level of the lint, are associated with or bound to theExpr
node underlying theStmt
as shown in the figure below:The end result is that the lint's
Warn
level is never knocked down toExpect
orAllow
since when searching for levels we start from the node on which the lint is triggered and go up the chain of parents. So in this case we look for the level onStmt
and then on theBlock
and so on. We never look for it on theExpr
where the levels actually exist.Possible fix
As it happens
AttributeMap
in the lowered HIR does have theexpect
/allow
attrs for both theStmt
node and its childExpr
node. However when adding the levels in theLintLevelBuilder
we do not add anything for theStmt
node as shown here (note the comment):rust/compiler/rustc_lint/src/levels.rs
Lines 258 to 263 in 6c65d4f
If were to add the level for
Stmt
as well the issue will go away.However, if we do that we will still have one problem in the case of
expect
which is that we will end up with two expectations and the one on theExpr
will not be fullfilled and hence we will still see a warning about unfulfilled expectation. To prevent that I think we should take the following approach: when an attr likeallow
orexpect
etc. are present for more than one HIR node in theAttributeMap
and if one node is the (direct or indirect) parent of the other node, then add the level only for parent node. This will take care of any lints on the child (since we always walk up the HIR hierachy as mentioned earlier) as well as the parent and it will not cause any warnings about missed expectations.I am new to this area so if someone can review this idea or suggest alternatives that will be great. @cjgillot since you seemed to have worked in this area recently, can you please weigh in?
cjgillot commentedon Sep 13, 2024
Your investigation is accurate, and the fix is simple: visit the statement node when building lint levels.
Do you mind making such a pr ?
I don't think we need any special adjustment for
expect
cases, duplicated attributes are already taken into account, but a test won't hurt.gurry commentedon Sep 13, 2024
Thanks @cjgillot .
Yes, I'll put together a PR. My only concern is if all we do is add the level at
Stmt
, although it will work perfectly forallow
,deny
etc., in the case ofexpect
we will end up with an unfulfilled expectation on theExpr
node which will appear to the user as a warning.But anyway let me have a go and see what happens.
Stmt
nodes #130293gurry commentedon Sep 13, 2024
Opened draft PR #130293 that adds the lint on
Stmt
. It does suffer from the extra warning problem.Rollup merge of rust-lang#130293 - gurry:130142-lint-level-issue, r=c…
3 remaining items