Skip to content

Commit 7446bf9

Browse files
authored
Merge pull request #1892 from ehuss/must_use
Update `must_use` to use the attribute template
2 parents 65bf656 + a30f26e commit 7446bf9

File tree

1 file changed

+151
-66
lines changed

1 file changed

+151
-66
lines changed

src/attributes/diagnostics.md

Lines changed: 151 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -345,120 +345,198 @@ The [RFC][1270-deprecation.md] contains motivations and more details.
345345

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

348+
<!-- template:attributes -->
348349
r[attributes.diagnostics.must_use]
349350
## The `must_use` attribute
350351

351352
r[attributes.diagnostics.must_use.intro]
352-
The *`must_use` attribute* is used to issue a diagnostic warning when a value
353-
is not "used".
353+
The *`must_use` [attribute]* marks a value that should be used.
354+
355+
r[attributes.diagnostics.must_use.syntax]
356+
The `must_use` attribute uses the [MetaWord] and [MetaNameValueStr] syntaxes.
357+
358+
> [!EXAMPLE]
359+
> ```rust
360+
> #[must_use]
361+
> fn use_me1() -> u8 { 0 }
362+
>
363+
> #[must_use = "explanation of why it should be used"]
364+
> fn use_me2() -> u8 { 0 }
365+
> ```
354366
355367
r[attributes.diagnostics.must_use.allowed-positions]
356-
The `must_use` attribute can be applied to user-defined composite types
357-
([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions],
358-
and [traits].
368+
The `must_use` attribute may be applied to a:
369+
370+
- [Struct]
371+
- [Enumeration]
372+
- [Union]
373+
- [Function]
374+
- [Trait]
375+
376+
> [!NOTE]
377+
> `rustc` ignores use in other positions but lints against it. This may become an error in the future.
378+
379+
r[attributes.diagnostics.must_use.duplicates]
380+
The `must_use` attribute may be used only once on an item.
381+
382+
> [!NOTE]
383+
> `rustc` lints against any use following the first. This may become an error in the future.
359384
360385
r[attributes.diagnostics.must_use.message]
361-
The `must_use` attribute may include a message by using the
362-
[MetaNameValueStr] syntax such as `#[must_use = "example message"]`. The
363-
message will be given alongside the warning.
386+
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.
364387
365388
r[attributes.diagnostics.must_use.type]
366-
When used on user-defined composite types, if the [expression] of an
367-
[expression statement] has that type, then the `unused_must_use` lint is
368-
violated.
389+
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.
369390
370-
```rust
391+
```rust,compile_fail
392+
#![deny(unused_must_use)]
371393
#[must_use]
372-
struct MustUse {
373-
// some fields
374-
}
394+
struct MustUse();
395+
MustUse(); // ERROR: Unused value that must be used.
396+
```
375397
376-
# impl MustUse {
377-
# fn new() -> MustUse { MustUse {} }
378-
# }
379-
#
380-
// Violates the `unused_must_use` lint.
381-
MustUse::new();
398+
r[attributes.diagnostics.must_use.type.uninhabited]
399+
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.
400+
401+
```rust
402+
#![deny(unused_must_use)]
403+
# use core::ops::ControlFlow;
404+
enum Empty {}
405+
fn f1() -> Result<(), Empty> { Ok(()) }
406+
f1(); // OK: `Empty` is uninhabited.
407+
fn f2() -> ControlFlow<Empty, ()> { ControlFlow::Continue(()) }
408+
f2(); // OK: `Empty` is uninhabited.
382409
```
383410

384411
r[attributes.diagnostics.must_use.fn]
385-
When used on a function, if the [expression] of an [expression statement] is a
386-
[call expression] to that function, then the `unused_must_use` lint is
387-
violated.
412+
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.
388413

389-
```rust
414+
```rust,compile_fail
415+
#![deny(unused_must_use)]
390416
#[must_use]
391-
fn five() -> i32 { 5i32 }
392-
393-
// Violates the unused_must_use lint.
394-
five();
417+
fn f() {}
418+
f(); // ERROR: Unused return value that must be used.
395419
```
396420

397421
r[attributes.diagnostics.must_use.trait]
398-
When used on a [trait declaration], a [call expression] of an [expression
399-
statement] to a function that returns an [impl trait] or a [dyn trait] of that trait violates
400-
the `unused_must_use` lint.
422+
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.
401423

402-
```rust
424+
```rust,compile_fail
425+
#![deny(unused_must_use)]
403426
#[must_use]
404-
trait Critical {}
405-
impl Critical for i32 {}
406-
407-
fn get_critical() -> impl Critical {
408-
4i32
409-
}
410-
411-
// Violates the `unused_must_use` lint.
412-
get_critical();
427+
trait Tr {}
428+
impl Tr for () {}
429+
fn f() -> impl Tr {}
430+
f(); // ERROR: Unused implementor that must be used.
413431
```
414432

415433
r[attributes.diagnostics.must_use.trait-function]
416-
When used on a function in a trait declaration, then the behavior also applies
417-
when the call expression is a function from an implementation of the trait.
434+
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.
418435

419-
```rust
420-
trait Trait {
436+
```rust,compile_fail
437+
#![deny(unused_must_use)]
438+
trait Tr {
421439
#[must_use]
422-
fn use_me(&self) -> i32;
440+
fn use_me(&self);
423441
}
424442
425-
impl Trait for i32 {
426-
fn use_me(&self) -> i32 { 0i32 }
443+
impl Tr for () {
444+
fn use_me(&self) {}
427445
}
428446
429-
// Violates the `unused_must_use` lint.
430-
5i32.use_me();
447+
().use_me(); // ERROR: Unused return value that must be used.
448+
```
449+
450+
```rust,compile_fail
451+
# #![deny(unused_must_use)]
452+
# trait Tr {
453+
# #[must_use]
454+
# fn use_me(&self);
455+
# }
456+
#
457+
# impl Tr for () {
458+
# fn use_me(&self) {}
459+
# }
460+
#
461+
<() as Tr>::use_me(&());
462+
// ^^^^^^^^^^^ ERROR: Unused return value that must be used.
463+
```
464+
465+
r[attributes.diagnostics.must_use.block-expr]
466+
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.
467+
468+
```rust,compile_fail
469+
#![deny(unused_must_use)]
470+
#[must_use]
471+
fn f() {}
472+
473+
{ f() }; // ERROR: The lint looks through block expressions.
474+
unsafe { f() }; // ERROR: The lint looks through `unsafe` blocks.
475+
{ { f() } }; // ERROR: The lint looks through nested blocks.
431476
```
432477

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

481+
```rust
482+
#![deny(unused_must_use)]
483+
trait Tr {
484+
fn f(&self);
485+
}
486+
487+
impl Tr for () {
488+
#[must_use] // This has no effect.
489+
fn f(&self) {}
490+
}
491+
492+
().f(); // OK.
493+
```
494+
436495
> [!NOTE]
437-
> 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.
496+
> `rustc` lints against use on functions in trait implementations. This may become an error in the future.
497+
498+
r[attributes.diagnostics.must_use.wrapping-suppression]
499+
> [!NOTE]
500+
> 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]`.
438501
>
439502
> ```rust
503+
> #![deny(unused_must_use)]
440504
> #[must_use]
441-
> fn five() -> i32 { 5i32 }
505+
> fn f() {}
442506
>
443-
> // None of these violate the unused_must_use lint.
444-
> (five(),);
445-
> Some(five());
446-
> { five() };
447-
> if true { five() } else { 0i32 };
448-
> match true {
449-
> _ => five()
507+
> // The fn-based check does not fire for any of these, because the
508+
> // expression of the expression statement is not a call to a
509+
> // `#[must_use]` function.
510+
> (f(),); // Expression is a tuple, not a call.
511+
> Some(f()); // Callee `Some` is not `#[must_use]`.
512+
> if true { f() } else {}; // Expression is an `if`, not a call.
513+
> match true { // Expression is a `match`, not a call.
514+
> _ => f()
450515
> };
451516
> ```
517+
>
518+
> ```rust,compile_fail
519+
> #![deny(unused_must_use)]
520+
> #[must_use]
521+
> struct MustUse;
522+
> fn g() -> MustUse { MustUse }
523+
>
524+
> // Despite the `if` expression not being a call, the type-based check
525+
> // fires because the type of the expression is `MustUse`, which has
526+
> // the `#[must_use]` attribute.
527+
> if true { g() } else { MustUse }; // ERROR: Must be used.
528+
> ```
452529
530+
r[attributes.diagnostics.must_use.underscore-idiom]
453531
> [!NOTE]
454-
> It is idiomatic to use a [let statement] with a pattern of `_` when a must-used value is purposely discarded.
532+
> Using a [let statement] or [destructuring assignment] with a pattern of `_` when a must-used value is purposely discarded is idiomatic.
455533
>
456534
> ```rust
535+
> #![deny(unused_must_use)]
457536
> #[must_use]
458-
> fn five() -> i32 { 5i32 }
459-
>
460-
> // Does not violate the unused_must_use lint.
461-
> let _ = five();
537+
> fn f() {}
538+
> let _ = f(); // OK.
539+
> _ = f(); // OK.
462540
> ```
463541
464542
r[attributes.diagnostic.namespace]
@@ -664,19 +742,24 @@ The first error message includes a somewhat confusing error message about the re
664742

665743
[Clippy]: https://github.com/rust-lang/rust-clippy
666744
[`Drop`]: ../special-types-and-traits.md#drop
745+
[`unsafe` blocks]: ../expressions/block-expr.md#unsafe-blocks
746+
[attribute]: ../attributes.md
667747
[attributes]: ../attributes.md
668748
[block expression]: ../expressions/block-expr.md
669749
[call expression]: ../expressions/call-expr.md
750+
[destructuring assignment]: expr.assign.destructure
751+
[method call expression]: ../expressions/method-call-expr.md
670752
[dyn trait]: ../types/trait-object.md
671753
[enum variant]: ../items/enumerations.md
672-
[enum]: ../items/enumerations.md
754+
[enumeration]: ../items/enumerations.md
673755
[expression statement]: ../statements.md#expression-statements
674756
[expression]: ../expressions.md
675757
[external block item]: ../items/external-blocks.md
676758
[functions]: ../items/functions.md
677759
[impl trait]: ../types/impl-trait.md
678760
[implementation]: ../items/implementations.md
679761
[item]: ../items.md
762+
[labeled block expressions]: ../expressions/block-expr.md#labeled-block-expressions
680763
[let statement]: ../statements.md#let-statements
681764
[macro definition]: ../macros-by-example.md
682765
[module]: ../items/modules.md
@@ -686,8 +769,10 @@ The first error message includes a somewhat confusing error message about the re
686769
[rustdoc]: ../../rustdoc/lints.html
687770
[struct field]: ../items/structs.md
688771
[struct]: ../items/structs.md
772+
[external block]: ../items/external-blocks.md
689773
[trait declaration]: ../items/traits.md
690774
[trait item]: ../items/traits.md
691775
[trait-impl]: ../items/implementations.md#trait-implementations
692776
[traits]: ../items/traits.md
777+
[uninhabited]: glossary.uninhabited
693778
[union]: ../items/unions.md

0 commit comments

Comments
 (0)