must_use in std::hint - Rust (original) (raw)
pub const fn must_use<T>(value: T) -> T
🔬This is a nightly-only experimental API. (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 = <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>r</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo>:</mo><mo>:</mo><mi>m</mi><mi>a</mi><mi>k</mi><msub><mi>e</mi><mi>e</mi></msub><mi>r</mi><mi>r</mi><mi>o</mi><mi>r</mi><mo stretchy="false">(</mo><mi>c</mi><mi>o</mi><mi>r</mi><mi>e</mi><mo>:</mo><mo>:</mo><mi>f</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><msub><mi>t</mi><mi>a</mi></msub><mi>r</mi><mi>g</mi><mi>s</mi><mo stretchy="false">!</mo><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">crate::make_error(core::format_args!(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">cr</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">mak</span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">e</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">rror</span><span class="mopen">(</span><span class="mord mathnormal">core</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal" style="margin-right:0.02778em;">or</span><span class="mord mathnormal">ma</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">s</span><span class="mclose">!</span><span class="mopen">(</span></span></span></span>($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
}
In 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:
fn 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:
async 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 ()
}