Skip to content
Merged
217 changes: 151 additions & 66 deletions src/attributes/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,120 +345,198 @@ The [RFC][1270-deprecation.md] contains motivations and more details.

[1270-deprecation.md]: https://github.com/rust-lang/rfcs/blob/master/text/1270-deprecation.md

<!-- template:attributes -->
r[attributes.diagnostics.must_use]
## The `must_use` attribute

r[attributes.diagnostics.must_use.intro]
The *`must_use` attribute* is used to issue a diagnostic warning when a value
is not "used".
The *`must_use` [attribute]* marks a value that should be used.

r[attributes.diagnostics.must_use.syntax]
The `must_use` attribute uses the [MetaWord] and [MetaNameValueStr] syntaxes.

> [!EXAMPLE]
> ```rust
> #[must_use]
> fn use_me1() -> u8 { 0 }
>
> #[must_use = "explanation of why it should be used"]
> fn use_me2() -> u8 { 0 }
> ```

r[attributes.diagnostics.must_use.allowed-positions]
The `must_use` attribute can be applied to user-defined composite types
([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions],
and [traits].
The `must_use` attribute may be applied to a:

- [Struct]
- [Enumeration]
- [Union]
- [Function]
- [Trait]

> [!NOTE]
> `rustc` ignores use in other positions but lints against it. This may become an error in the future.

r[attributes.diagnostics.must_use.duplicates]
The `must_use` attribute may be used only once on an item.

> [!NOTE]
> `rustc` lints against any use following the first. This may become an error in the future.

r[attributes.diagnostics.must_use.message]
The `must_use` attribute may include a message by using the
[MetaNameValueStr] syntax such as `#[must_use = "example message"]`. The
message will be given alongside the warning.
The `must_use` attribute may include a message by using the [MetaNameValueStr] syntax, e.g., `#[must_use = "example message"]`. The message may be emitted as part of the lint.

r[attributes.diagnostics.must_use.type]
When used on user-defined composite types, if the [expression] of an
[expression statement] has that type, then the `unused_must_use` lint is
violated.
When the attribute is applied to a [struct], [enumeration], or [union], if the [expression] of an [expression statement] has that type, the use triggers the `unused_must_use` lint.

```rust
```rust,compile_fail
#![deny(unused_must_use)]
#[must_use]
struct MustUse {
// some fields
}
struct MustUse();
MustUse(); // ERROR: Unused value that must be used.
```

# impl MustUse {
# fn new() -> MustUse { MustUse {} }
# }
#
// Violates the `unused_must_use` lint.
MustUse::new();
r[attributes.diagnostics.must_use.type.uninhabited]
As an exception to [attributes.diagnostics.must_use.type], the lint does not fire for `Result<(), E>` when `E` is [uninhabited] or for `ControlFlow<B, ()>` when `B` is [uninhabited]. A `#[non_exhaustive]` type from an external crate is not considered uninhabited for this purpose, because it may gain constructors in the future.

```rust
#![deny(unused_must_use)]
# use core::ops::ControlFlow;
enum Empty {}
fn f1() -> Result<(), Empty> { Ok(()) }
f1(); // OK: `Empty` is uninhabited.
fn f2() -> ControlFlow<Empty, ()> { ControlFlow::Continue(()) }
f2(); // OK: `Empty` is uninhabited.
```

r[attributes.diagnostics.must_use.fn]
When used on a function, if the [expression] of an [expression statement] is a
[call expression] to that function, then the `unused_must_use` lint is
violated.
If the [expression] of an [expression statement] is a [call expression] or [method call expression] whose function operand is a function to which the attribute is applied, the use triggers the `unused_must_use` lint.

```rust
```rust,compile_fail
#![deny(unused_must_use)]
#[must_use]
fn five() -> i32 { 5i32 }

// Violates the unused_must_use lint.
five();
fn f() {}
f(); // ERROR: Unused return value that must be used.
```

r[attributes.diagnostics.must_use.trait]
When used on a [trait declaration], a [call expression] of an [expression
statement] to a function that returns an [impl trait] or a [dyn trait] of that trait violates
the `unused_must_use` lint.
If the [expression] of an [expression statement] is a [call expression] or [method call expression] whose function operand is a function that returns an [impl trait] or a [dyn trait] type where one or more traits in the bound are marked with the attribute, the use triggers the `unused_must_use` lint.

```rust
```rust,compile_fail
#![deny(unused_must_use)]
#[must_use]
trait Critical {}
impl Critical for i32 {}

fn get_critical() -> impl Critical {
4i32
}

// Violates the `unused_must_use` lint.
get_critical();
trait Tr {}
impl Tr for () {}
fn f() -> impl Tr {}
f(); // ERROR: Unused implementor that must be used.
```

r[attributes.diagnostics.must_use.trait-function]
When used on a function in a trait declaration, then the behavior also applies
when the call expression is a function from an implementation of the trait.
When the attribute is applied to a function in a trait declaration, the rules described in [attributes.diagnostics.must_use.fn] also apply when the function operand of the [call expression] or [method call expression] is an implementation of that function.

```rust
trait Trait {
```rust,compile_fail
#![deny(unused_must_use)]
trait Tr {
#[must_use]
fn use_me(&self) -> i32;
fn use_me(&self);
}

impl Trait for i32 {
fn use_me(&self) -> i32 { 0i32 }
impl Tr for () {
fn use_me(&self) {}
}

// Violates the `unused_must_use` lint.
5i32.use_me();
().use_me(); // ERROR: Unused return value that must be used.
```

```rust,compile_fail
# #![deny(unused_must_use)]
# trait Tr {
# #[must_use]
# fn use_me(&self);
# }
#
# impl Tr for () {
# fn use_me(&self) {}
# }
#
<() as Tr>::use_me(&());
// ^^^^^^^^^^^ ERROR: Unused return value that must be used.
```

r[attributes.diagnostics.must_use.block-expr]
When checking the [expression] of an [expression statement] for [attributes.diagnostics.must_use.type], [attributes.diagnostics.must_use.fn], [attributes.diagnostics.must_use.trait], and [attributes.diagnostics.must_use.trait-function], the lint looks through [block expressions][block expression] (including [`unsafe` blocks] and [labeled block expressions]) to the trailing expression of each. This applies recursively for nested block expressions.

```rust,compile_fail
#![deny(unused_must_use)]
#[must_use]
fn f() {}

{ f() }; // ERROR: The lint looks through block expressions.
unsafe { f() }; // ERROR: The lint looks through `unsafe` blocks.
{ { f() } }; // ERROR: The lint looks through nested blocks.
```

r[attributes.diagnostics.must_use.trait-impl-function]
When used on a function in a trait implementation, the attribute does nothing.

```rust
#![deny(unused_must_use)]
trait Tr {
fn f(&self);
}

impl Tr for () {
#[must_use] // This has no effect.
fn f(&self) {}
}

().f(); // OK.
```

> [!NOTE]
> Trivial no-op expressions containing the value will not violate the lint. Examples include wrapping the value in a type that does not implement [`Drop`] and then not using that type and being the final expression of a [block expression] that is not used.
> `rustc` lints against use on functions in trait implementations. This may become an error in the future.

r[attributes.diagnostics.must_use.wrapping-suppression]
> [!NOTE]
> Wrapping the result of a `#[must_use]` function in certain expressions can suppress the [fn-based check][attributes.diagnostics.must_use.fn], because the [expression] of the [expression statement] is not a [call expression] or [method call expression] to a `#[must_use]` function. The [type-based check][attributes.diagnostics.must_use.type] still applies if the type of the overall expression is `#[must_use]`.
>
> ```rust
> #![deny(unused_must_use)]
> #[must_use]
> fn five() -> i32 { 5i32 }
> fn f() {}
>
> // None of these violate the unused_must_use lint.
> (five(),);
> Some(five());
> { five() };
> if true { five() } else { 0i32 };
> match true {
> _ => five()
> // The fn-based check does not fire for any of these, because the
> // expression of the expression statement is not a call to a
> // `#[must_use]` function.
> (f(),); // Expression is a tuple, not a call.
> Some(f()); // Callee `Some` is not `#[must_use]`.
> if true { f() } else {}; // Expression is an `if`, not a call.
> match true { // Expression is a `match`, not a call.
> _ => f()
> };
> ```
>
> ```rust,compile_fail
> #![deny(unused_must_use)]
> #[must_use]
> struct MustUse;
> fn g() -> MustUse { MustUse }
>
> // Despite the `if` expression not being a call, the type-based check
> // fires because the type of the expression is `MustUse`, which has
> // the `#[must_use]` attribute.
> if true { g() } else { MustUse }; // ERROR: Must be used.
> ```

r[attributes.diagnostics.must_use.underscore-idiom]
> [!NOTE]
> It is idiomatic to use a [let statement] with a pattern of `_` when a must-used value is purposely discarded.
> Using a [let statement] or [destructuring assignment] with a pattern of `_` when a must-used value is purposely discarded is idiomatic.
>
> ```rust
> #![deny(unused_must_use)]
> #[must_use]
> fn five() -> i32 { 5i32 }
>
> // Does not violate the unused_must_use lint.
> let _ = five();
> fn f() {}
> let _ = f(); // OK.
> _ = f(); // OK.
> ```

r[attributes.diagnostic.namespace]
Expand Down Expand Up @@ -664,19 +742,24 @@ The first error message includes a somewhat confusing error message about the re

[Clippy]: https://github.com/rust-lang/rust-clippy
[`Drop`]: ../special-types-and-traits.md#drop
[`unsafe` blocks]: ../expressions/block-expr.md#unsafe-blocks
[attribute]: ../attributes.md
[attributes]: ../attributes.md
[block expression]: ../expressions/block-expr.md
[call expression]: ../expressions/call-expr.md
[destructuring assignment]: expr.assign.destructure
[method call expression]: ../expressions/method-call-expr.md
[dyn trait]: ../types/trait-object.md
[enum variant]: ../items/enumerations.md
[enum]: ../items/enumerations.md
[enumeration]: ../items/enumerations.md
[expression statement]: ../statements.md#expression-statements
[expression]: ../expressions.md
[external block item]: ../items/external-blocks.md
[functions]: ../items/functions.md
[impl trait]: ../types/impl-trait.md
[implementation]: ../items/implementations.md
[item]: ../items.md
[labeled block expressions]: ../expressions/block-expr.md#labeled-block-expressions
[let statement]: ../statements.md#let-statements
[macro definition]: ../macros-by-example.md
[module]: ../items/modules.md
Expand All @@ -686,8 +769,10 @@ The first error message includes a somewhat confusing error message about the re
[rustdoc]: ../../rustdoc/lints.html
[struct field]: ../items/structs.md
[struct]: ../items/structs.md
[external block]: ../items/external-blocks.md
[trait declaration]: ../items/traits.md
[trait item]: ../items/traits.md
[trait-impl]: ../items/implementations.md#trait-implementations
[traits]: ../items/traits.md
[uninhabited]: glossary.uninhabited
[union]: ../items/unions.md
Loading