pub fn must_use<T>(value: T) -> T
hint_must_use
#94745)Expand description
An identity function that causes an unused_must_use
warning to be
triggered if the given value is not used (returned, stored in a variable,
etc) by the caller.
This is primarily intended for use in macro-generated code, in which a
#[must_use]
attribute either on a type or a function would not
be convenient.
§Example
#![feature(hint_must_use)]
use core::fmt;
pub struct Error(/* ... */);
#[macro_export]
macro_rules! make_error {
($($args:expr),*) => {
core::hint::must_use({
let error = $crate::make_error(core::format_args!($($args),*));
error
})
};
}
// Implementation detail of make_error! macro.
#[doc(hidden)]
pub fn make_error(args: fmt::Arguments<'_>) -> Error {
Error(/* ... */)
}
fn demo() -> Option<Error> {
if true {
// Oops, meant to write `return Some(make_error!("..."));`
Some(make_error!("..."));
}
None
}
RunIn the above example, we’d like an unused_must_use
lint to apply to the
value created by make_error!
. However, neither #[must_use]
on a struct
nor #[must_use]
on a function is appropriate here, so the macro expands
using core::hint::must_use
instead.
-
We wouldn’t want
#[must_use]
on thestruct Error
because that would make the following unproblematic code trigger a warning:
Runfn f(arg: &str) -> Result<(), Error> #[test] fn t() { // Assert that `f` returns error if passed an empty string. // A value of type `Error` is unused here but that's not a problem. f("").unwrap_err(); }
-
Using
#[must_use]
onfn make_error
can’t help because the return value is used, as the right-hand side of alet
statement. Thelet
statement looks useless but is in fact necessary for ensuring that temporaries within theformat_args
expansion are not kept alive past the creation of theError
, as keeping them alive past that point can cause autotrait issues in async code:
Runasync fn f() { // Using `let` inside the make_error expansion causes temporaries like // `unsync()` to drop at the semicolon of that `let` statement, which // is prior to the await point. They would otherwise stay around until // the semicolon on *this* statement, which is after the await point, // and the enclosing Future would not implement Send. log(make_error!("look: {:p}", unsync())).await; } async fn log(error: Error) {/* ... */} // Returns something without a Sync impl. fn unsync() -> *const () { 0 as *const () }