Skip to content

Commit b2473e9

Browse files
committed
Add core::hint::must_use
1 parent 89adcc6 commit b2473e9

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)