Skip to content

Commit ff54e34

Browse files
authored
Rollup merge of #94723 - dtolnay:mustuse, r=Mark-Simulacrum
Add core::hint::must_use The example code in this documentation is minimized from a real-world situation in the `anyhow` crate where this function would have been valuable. Having this provided by the standard library is especially useful for proc macros, even more than for macro_rules. That's because proc macro crates aren't allowed to export anything other than macros, so they couldn't make their own `must_use` function for their macro-generated code to call. <br> ## Rendered documentation > 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][must_use] either on a type or a function would not be convenient. > > [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute > > ### Example > > ```rust > #![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 > } > ``` > > 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 the `struct Error` because that would make the following unproblematic code trigger a warning: > > ```rust > 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]` on `fn make_error` can't help because the return value *is* used, as the right-hand side of a `let` statement. The `let` statement looks useless but is in fact necessary for ensuring that temporaries within the `format_args` expansion are not kept alive past the creation of the `Error`, as keeping them alive past that point can cause autotrait issues in async code: > > ```rust > 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 () > } > ```
2 parents ee8109d + b2473e9 commit ff54e34

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

library/core/src/hint.rs

+123
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,126 @@ pub fn spin_loop() {
173173
pub const fn black_box<T>(dummy: T) -> T {
174174
crate::intrinsics::black_box(dummy)
175175
}
176+
177+
/// An identity function that causes an `unused_must_use` warning to be
178+
/// triggered if the given value is not used (returned, stored in a variable,
179+
/// etc) by the caller.
180+
///
181+
/// This is primarily intended for use in macro-generated code, in which a
182+
/// [`#[must_use]` attribute][must_use] either on a type or a function would not
183+
/// be convenient.
184+
///
185+
/// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
186+
///
187+
/// # Example
188+
///
189+
/// ```
190+
/// #![feature(hint_must_use)]
191+
///
192+
/// use core::fmt;
193+
///
194+
/// pub struct Error(/* ... */);
195+
///
196+
/// #[macro_export]
197+
/// macro_rules! make_error {
198+
/// ($($args:expr),*) => {
199+
/// core::hint::must_use({
200+
/// let error = $crate::make_error(core::format_args!($($args),*));
201+
/// error
202+
/// })
203+
/// };
204+
/// }
205+
///
206+
/// // Implementation detail of make_error! macro.
207+
/// #[doc(hidden)]
208+
/// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
209+
/// Error(/* ... */)
210+
/// }
211+
///
212+
/// fn demo() -> Option<Error> {
213+
/// if true {
214+
/// // Oops, meant to write `return Some(make_error!("..."));`
215+
/// Some(make_error!("..."));
216+
/// }
217+
/// None
218+
/// }
219+
/// #
220+
/// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
221+
/// # fn main() {}
222+
/// ```
223+
///
224+
/// In the above example, we'd like an `unused_must_use` lint to apply to the
225+
/// value created by `make_error!`. However, neither `#[must_use]` on a struct
226+
/// nor `#[must_use]` on a function is appropriate here, so the macro expands
227+
/// using `core::hint::must_use` instead.
228+
///
229+
/// - We wouldn't want `#[must_use]` on the `struct Error` because that would
230+
/// make the following unproblematic code trigger a warning:
231+
///
232+
/// ```
233+
/// # struct Error;
234+
/// #
235+
/// fn f(arg: &str) -> Result<(), Error>
236+
/// # { Ok(()) }
237+
///
238+
/// #[test]
239+
/// fn t() {
240+
/// // Assert that `f` returns error if passed an empty string.
241+
/// // A value of type `Error` is unused here but that's not a problem.
242+
/// f("").unwrap_err();
243+
/// }
244+
/// ```
245+
///
246+
/// - Using `#[must_use]` on `fn make_error` can't help because the return value
247+
/// *is* used, as the right-hand side of a `let` statement. The `let`
248+
/// statement looks useless but is in fact necessary for ensuring that
249+
/// temporaries within the `format_args` expansion are not kept alive past the
250+
/// creation of the `Error`, as keeping them alive past that point can cause
251+
/// autotrait issues in async code:
252+
///
253+
/// ```
254+
/// # #![feature(hint_must_use)]
255+
/// #
256+
/// # struct Error;
257+
/// #
258+
/// # macro_rules! make_error {
259+
/// # ($($args:expr),*) => {
260+
/// # core::hint::must_use({
261+
/// # // If `let` isn't used, then `f()` produces a non-Send future.
262+
/// # let error = make_error(core::format_args!($($args),*));
263+
/// # error
264+
/// # })
265+
/// # };
266+
/// # }
267+
/// #
268+
/// # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
269+
/// # Error
270+
/// # }
271+
/// #
272+
/// async fn f() {
273+
/// // Using `let` inside the make_error expansion causes temporaries like
274+
/// // `unsync()` to drop at the semicolon of that `let` statement, which
275+
/// // is prior to the await point. They would otherwise stay around until
276+
/// // the semicolon on *this* statement, which is after the await point,
277+
/// // and the enclosing Future would not implement Send.
278+
/// log(make_error!("look: {:p}", unsync())).await;
279+
/// }
280+
///
281+
/// async fn log(error: Error) {/* ... */}
282+
///
283+
/// // Returns something without a Sync impl.
284+
/// fn unsync() -> *const () {
285+
/// 0 as *const ()
286+
/// }
287+
/// #
288+
/// # fn test() {
289+
/// # fn assert_send(_: impl Send) {}
290+
/// # assert_send(f());
291+
/// # }
292+
/// ```
293+
#[unstable(feature = "hint_must_use", issue = "94745")]
294+
#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
295+
#[must_use] // <-- :)
296+
pub const fn must_use<T>(value: T) -> T {
297+
value
298+
}

0 commit comments

Comments
 (0)