1
Fork 0

Lint #[must_use] attributes applied to methods in trait impls

The `#[must_use]` attribute has no effect when applied to methods in
trait implementations. This case was not linted before.
This commit is contained in:
Samuel Tardieu 2025-02-12 10:35:32 +01:00
parent 3e66ba73d5
commit e639e886b2
3 changed files with 56 additions and 34 deletions

View file

@ -1431,37 +1431,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
/// Warns against some misuses of `#[must_use]` /// Warns against some misuses of `#[must_use]`
fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if !matches!( if matches!(
target, target,
Target::Fn Target::Fn
| Target::Enum | Target::Enum
| Target::Struct | Target::Struct
| Target::Union | Target::Union
| Target::Method(_) | Target::Method(MethodKind::Trait { body: false } | MethodKind::Inherent)
| Target::ForeignFn | Target::ForeignFn
// `impl Trait` in return position can trip // `impl Trait` in return position can trip
// `unused_must_use` if `Trait` is marked as // `unused_must_use` if `Trait` is marked as
// `#[must_use]` // `#[must_use]`
| Target::Trait | Target::Trait
) { ) {
let article = match target { return;
Target::ExternCrate
| Target::Enum
| Target::Impl
| Target::Expression
| Target::Arm
| Target::AssocConst
| Target::AssocTy => "an",
_ => "a",
};
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::MustUseNoEffect { article, target },
);
} }
// `#[must_use]` can be applied to a trait method definition with a default body
if let Target::Method(MethodKind::Trait { body: true }) = target
&& let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id
&& let containing_item = self.tcx.hir().expect_item(parent_def_id)
&& let hir::ItemKind::Trait(..) = containing_item.kind
{
return;
}
let article = match target {
Target::ExternCrate
| Target::Enum
| Target::Impl
| Target::Expression
| Target::Arm
| Target::AssocConst
| Target::AssocTy => "an",
_ => "a",
};
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::MustUseNoEffect { article, target },
);
} }
/// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait. /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.

View file

@ -79,6 +79,11 @@ trait Use {
#[must_use] //~ ERROR `#[must_use]` has no effect #[must_use] //~ ERROR `#[must_use]` has no effect
impl Use for () { impl Use for () {
type AssocTy = (); type AssocTy = ();
#[must_use] //~ ERROR `#[must_use]` has no effect
fn get_four(&self) -> usize {
4
}
} }
#[must_use] //~ ERROR `#[must_use]` has no effect #[must_use] //~ ERROR `#[must_use]` has no effect

View file

@ -76,43 +76,43 @@ LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a trait alias error: `#[must_use]` has no effect when applied to a trait alias
--> $DIR/unused_attributes-must_use.rs:84:1 --> $DIR/unused_attributes-must_use.rs:89:1
| |
LL | #[must_use] LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a macro def error: `#[must_use]` has no effect when applied to a macro def
--> $DIR/unused_attributes-must_use.rs:87:1 --> $DIR/unused_attributes-must_use.rs:92:1
| |
LL | #[must_use] LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a statement error: `#[must_use]` has no effect when applied to a statement
--> $DIR/unused_attributes-must_use.rs:95:5 --> $DIR/unused_attributes-must_use.rs:100:5
| |
LL | #[must_use] LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a closure error: `#[must_use]` has no effect when applied to a closure
--> $DIR/unused_attributes-must_use.rs:99:13 --> $DIR/unused_attributes-must_use.rs:104:13
| |
LL | let x = #[must_use] LL | let x = #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to an match arm error: `#[must_use]` has no effect when applied to an match arm
--> $DIR/unused_attributes-must_use.rs:121:9 --> $DIR/unused_attributes-must_use.rs:126:9
| |
LL | #[must_use] LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a struct field error: `#[must_use]` has no effect when applied to a struct field
--> $DIR/unused_attributes-must_use.rs:129:28 --> $DIR/unused_attributes-must_use.rs:134:28
| |
LL | let s = PatternField { #[must_use] foo: 123 }; LL | let s = PatternField { #[must_use] foo: 123 };
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a pattern field error: `#[must_use]` has no effect when applied to a pattern field
--> $DIR/unused_attributes-must_use.rs:130:24 --> $DIR/unused_attributes-must_use.rs:135:24
| |
LL | let PatternField { #[must_use] foo } = s; LL | let PatternField { #[must_use] foo } = s;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -129,6 +129,12 @@ error: `#[must_use]` has no effect when applied to an associated type
LL | #[must_use] LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a provided trait method
--> $DIR/unused_attributes-must_use.rs:83:5
|
LL | #[must_use]
| ^^^^^^^^^^^
error: `#[must_use]` has no effect when applied to a foreign static item error: `#[must_use]` has no effect when applied to a foreign static item
--> $DIR/unused_attributes-must_use.rs:50:5 --> $DIR/unused_attributes-must_use.rs:50:5
| |
@ -136,7 +142,7 @@ LL | #[must_use]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: unused `X` that must be used error: unused `X` that must be used
--> $DIR/unused_attributes-must_use.rs:103:5 --> $DIR/unused_attributes-must_use.rs:108:5
| |
LL | X; LL | X;
| ^ | ^
@ -152,7 +158,7 @@ LL | let _ = X;
| +++++++ | +++++++
error: unused `Y` that must be used error: unused `Y` that must be used
--> $DIR/unused_attributes-must_use.rs:104:5 --> $DIR/unused_attributes-must_use.rs:109:5
| |
LL | Y::Z; LL | Y::Z;
| ^^^^ | ^^^^
@ -163,7 +169,7 @@ LL | let _ = Y::Z;
| +++++++ | +++++++
error: unused `U` that must be used error: unused `U` that must be used
--> $DIR/unused_attributes-must_use.rs:105:5 --> $DIR/unused_attributes-must_use.rs:110:5
| |
LL | U { unit: () }; LL | U { unit: () };
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -174,7 +180,7 @@ LL | let _ = U { unit: () };
| +++++++ | +++++++
error: unused return value of `U::method` that must be used error: unused return value of `U::method` that must be used
--> $DIR/unused_attributes-must_use.rs:106:5 --> $DIR/unused_attributes-must_use.rs:111:5
| |
LL | U::method(); LL | U::method();
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -185,7 +191,7 @@ LL | let _ = U::method();
| +++++++ | +++++++
error: unused return value of `foo` that must be used error: unused return value of `foo` that must be used
--> $DIR/unused_attributes-must_use.rs:107:5 --> $DIR/unused_attributes-must_use.rs:112:5
| |
LL | foo(); LL | foo();
| ^^^^^ | ^^^^^
@ -196,7 +202,7 @@ LL | let _ = foo();
| +++++++ | +++++++
error: unused return value of `foreign_foo` that must be used error: unused return value of `foreign_foo` that must be used
--> $DIR/unused_attributes-must_use.rs:110:9 --> $DIR/unused_attributes-must_use.rs:115:9
| |
LL | foreign_foo(); LL | foreign_foo();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -207,7 +213,7 @@ LL | let _ = foreign_foo();
| +++++++ | +++++++
error: unused return value of `Use::get_four` that must be used error: unused return value of `Use::get_four` that must be used
--> $DIR/unused_attributes-must_use.rs:118:5 --> $DIR/unused_attributes-must_use.rs:123:5
| |
LL | ().get_four(); LL | ().get_four();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -217,5 +223,5 @@ help: use `let _ = ...` to ignore the resulting value
LL | let _ = ().get_four(); LL | let _ = ().get_four();
| +++++++ | +++++++
error: aborting due to 28 previous errors error: aborting due to 29 previous errors