You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The admonition for `must_use` claimed that wrapping a value in a block
expression, as in `{ f() };`, suppresses the `unused_must_use` lint.
Testing against rustc shows this isn't true -- the lint explicitly
looks through block expressions (including `unsafe` and labeled
blocks) to their trailing expression before checking. Let's fix that.
Copy file name to clipboardExpand all lines: src/attributes/diagnostics.md
+35-7Lines changed: 35 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -449,6 +449,19 @@ impl Tr for () {
449
449
// ^^^^^^^^^^^ ERROR: Unused return value that must be used.
450
450
```
451
451
452
+
r[attributes.diagnostics.must_use.block-expr]
453
+
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.
454
+
455
+
```rust,compile_fail
456
+
#![deny(unused_must_use)]
457
+
#[must_use]
458
+
fn f() {}
459
+
460
+
{ f() }; // ERROR: The lint looks through block expressions.
461
+
unsafe { f() }; // ERROR: The lint looks through `unsafe` blocks.
462
+
{ { f() } }; // ERROR: The lint looks through nested blocks.
When used on a function in a trait implementation, the attribute does nothing.
454
467
@@ -470,22 +483,35 @@ impl Tr for () {
470
483
> `rustc` lints against use on functions in trait implementations. This may become an error in the future.
471
484
472
485
> [!NOTE]
473
-
> Wrapping the value, even trivially, will suppress the lint.
486
+
> 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]`.
474
487
>
475
488
> ```rust
476
489
> #![deny(unused_must_use)]
477
490
> #[must_use]
478
491
> fnf() {}
479
492
>
480
-
> // None of these trigger the `unused_must_use` lint.
481
-
> (f(),);
482
-
> Some(f());
483
-
> { f() };
484
-
> iftrue { f() } else {};
485
-
> matchtrue {
493
+
> // The fn-based check does not fire for any of these, because the
494
+
> // expression of the expression statement is not a call to a
495
+
> // `#[must_use]` function.
496
+
> (f(),); // Expression is a tuple, not a call.
497
+
> Some(f()); // Callee `Some` is not `#[must_use]`.
498
+
> iftrue { f() } else {}; // Expression is an `if`, not a call.
499
+
> matchtrue { // Expression is a `match`, not a call.
486
500
> _=>f()
487
501
> };
488
502
> ```
503
+
>
504
+
> ```rust,compile_fail
505
+
> #![deny(unused_must_use)]
506
+
> #[must_use]
507
+
> structMustUse;
508
+
> fng() ->MustUse { MustUse }
509
+
>
510
+
> // Despite the `if` expression not being a call, the type-based check
511
+
> // fires because the type of the expression is `MustUse`, which has
512
+
> // the `#[must_use]` attribute.
513
+
> iftrue { g() } else { MustUse }; // ERROR: Must be used.
0 commit comments