Allow annotating functions with #[must_use = false] to suppress any warning generated due to its return type being marked as #[must_use].
Motivation
The primary motivation is that there are some situations where a function is technically fallible, but it is almost always correct to not check its result.
example:
/// Try to open a file before it is required.
///
/// This result can be safely ignored,
/// as the file will be automatically opened again
/// when it is actually needed.
Another example is closing files and similar operations, where the only possible error recovery is to just ignoring the error.
Guide-level explanation
The #[must_use] attribute can also take a boolean value instead of a string value.
When a function is annotated with #[must_use = false], its result can be ignored without triggering the unused_must_use lint, even if its return type is marked as must_use.
#[must_use = true] is equivelent to #[must_use].
When used on a type, #[must_use = false] is equivelent to not having any #[must_use] attribute.
Reference-level explanation
The must_use attribute is used to control when the unused_must_use lint is emitted.
It has three forms:
- the plain
#[must_use]form, equivalent to#[must_use = true]. - the boolean form,
#[must_use = BOOLEAN], whereBOOLEANis eithertrueorfalse. - the string form,
#[must_use = "MESSAGE"], whereMESSAGEis a help message to emmitted alongside theunused_must_uselint.
For the purposes of calculating whether to emit unused_must_use for an expression, every function and type item is in one of the following must_use states:
- a positive state, corresponding to any
must_useattribute besidesmust_use = false. - a neutral state, corresponding to no
must_useattribute - a negative state, corresponding to
must_use = false.
For each expression statement, the following process is used to calculate a positive (emit the lint) or negative (do not emit the lint) result:
- if the expression of the expression statement is a function call, check the
must_usestate of that function, otherwise skip to step 3 - if the function has a neutral state, continue to step 3, otherwise the result is positive/negative according the the state
- if the type of the expression has a positive
must_usestate, the result is positive, otherwise, the result is negative.
Drawbacks
Yet another "opt-in/opt-out" dance, similar to #[non_exhaustive].
The usecase is fairly niche.
Implementation complexity.
Passing the result of a #[must_use = false] function through an identity function will cause the lint to trigger.
Rationale and alternatives
An = style attribute is used since this is already used for must_use, and it intuativly evokes the idea of "overwriting" a variable.
#[must_use = true] is provided for symmetry.
Prior art
- Pre-RFC on IRLO
- Scala's
@CanIgnoreResultannotation
Unresolved questions
- Is this the best way we can handle this, or is there a more elegant/general solution that doesn't involve marking every single function?
Future possibilities
- A future edition making
#[must_use]the default for functions that return something other than(). - Allow annotating a module/crate with
#[must_use]to make all its functions and methods default tomust_use.