]> git.lizzy.rs Git - rust.git/blob - library/core/src/hint.rs
Rollup merge of #96768 - m-ou-se:futex-fuchsia, r=tmandry
[rust.git] / library / core / src / hint.rs
1 #![stable(feature = "core_hint", since = "1.27.0")]
2
3 //! Hints to compiler that affects how code should be emitted or optimized.
4 //! Hints may be compile time or runtime.
5
6 use crate::intrinsics;
7
8 /// Informs the compiler that the site which is calling this function is not
9 /// reachable, possibly enabling further optimizations.
10 ///
11 /// # Safety
12 ///
13 /// Reaching this function is *Undefined Behavior*.
14 ///
15 /// As the compiler assumes that all forms of Undefined Behavior can never
16 /// happen, it will eliminate all branches in the surrounding code that it can
17 /// determine will invariably lead to a call to `unreachable_unchecked()`.
18 ///
19 /// If the assumptions embedded in using this function turn out to be wrong -
20 /// that is, if the site which is calling `unreachable_unchecked()` is actually
21 /// reachable at runtime - the compiler may have generated nonsensical machine
22 /// instructions for this situation, including in seemingly unrelated code,
23 /// causing difficult-to-debug problems.
24 ///
25 /// Use this function sparingly. Consider using the [`unreachable!`] macro,
26 /// which may prevent some optimizations but will safely panic in case it is
27 /// actually reached at runtime. Benchmark your code to find out if using
28 /// `unreachable_unchecked()` comes with a performance benefit.
29 ///
30 /// # Examples
31 ///
32 /// `unreachable_unchecked()` can be used in situations where the compiler
33 /// can't prove invariants that were previously established. Such situations
34 /// have a higher chance of occuring if those invariants are upheld by
35 /// external code that the compiler can't analyze.
36 /// ```
37 /// fn prepare_inputs(divisors: &mut Vec<u32>) {
38 ///     // Note to future-self when making changes: The invariant established
39 ///     // here is NOT checked in `do_computation()`; if this changes, you HAVE
40 ///     // to change `do_computation()`.
41 ///     divisors.retain(|divisor| *divisor != 0)
42 /// }
43 ///
44 /// /// # Safety
45 /// /// All elements of `divisor` must be non-zero.
46 /// unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
47 ///     divisors.iter().fold(i, |acc, divisor| {
48 ///         // Convince the compiler that a division by zero can't happen here
49 ///         // and a check is not needed below.
50 ///         if *divisor == 0 {
51 ///             // Safety: `divisor` can't be zero because of `prepare_inputs`,
52 ///             // but the compiler does not know about this. We *promise*
53 ///             // that we always call `prepare_inputs`.
54 ///             std::hint::unreachable_unchecked()
55 ///         }
56 ///         // The compiler would normally introduce a check here that prevents
57 ///         // a division by zero. However, if `divisor` was zero, the branch
58 ///         // above would reach what we explicitly marked as unreachable.
59 ///         // The compiler concludes that `divisor` can't be zero at this point
60 ///         // and removes the - now proven useless - check.
61 ///         acc / divisor
62 ///     })
63 /// }
64 ///
65 /// let mut divisors = vec![2, 0, 4];
66 /// prepare_inputs(&mut divisors);
67 /// let result = unsafe {
68 ///     // Safety: prepare_inputs() guarantees that divisors is non-zero
69 ///     do_computation(100, &divisors)
70 /// };
71 /// assert_eq!(result, 12);
72 ///
73 /// ```
74 ///
75 /// While using `unreachable_unchecked()` is perfectly sound in the following
76 /// example, the compiler is able to prove that a division by zero is not
77 /// possible. Benchmarking reveals that `unreachable_unchecked()` provides
78 /// no benefit over using [`unreachable!`], while the latter does not introduce
79 /// the possibility of Undefined Behavior.
80 ///
81 /// ```
82 /// fn div_1(a: u32, b: u32) -> u32 {
83 ///     use std::hint::unreachable_unchecked;
84 ///
85 ///     // `b.saturating_add(1)` is always positive (not zero),
86 ///     // hence `checked_div` will never return `None`.
87 ///     // Therefore, the else branch is unreachable.
88 ///     a.checked_div(b.saturating_add(1))
89 ///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
90 /// }
91 ///
92 /// assert_eq!(div_1(7, 0), 7);
93 /// assert_eq!(div_1(9, 1), 4);
94 /// assert_eq!(div_1(11, u32::MAX), 0);
95 /// ```
96 #[inline]
97 #[stable(feature = "unreachable", since = "1.27.0")]
98 #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
99 pub const unsafe fn unreachable_unchecked() -> ! {
100     // SAFETY: the safety contract for `intrinsics::unreachable` must
101     // be upheld by the caller.
102     unsafe { intrinsics::unreachable() }
103 }
104
105 /// Emits a machine instruction to signal the processor that it is running in
106 /// a busy-wait spin-loop ("spin lock").
107 ///
108 /// Upon receiving the spin-loop signal the processor can optimize its behavior by,
109 /// for example, saving power or switching hyper-threads.
110 ///
111 /// This function is different from [`thread::yield_now`] which directly
112 /// yields to the system's scheduler, whereas `spin_loop` does not interact
113 /// with the operating system.
114 ///
115 /// A common use case for `spin_loop` is implementing bounded optimistic
116 /// spinning in a CAS loop in synchronization primitives. To avoid problems
117 /// like priority inversion, it is strongly recommended that the spin loop is
118 /// terminated after a finite amount of iterations and an appropriate blocking
119 /// syscall is made.
120 ///
121 /// **Note**: On platforms that do not support receiving spin-loop hints this
122 /// function does not do anything at all.
123 ///
124 /// # Examples
125 ///
126 /// ```
127 /// use std::sync::atomic::{AtomicBool, Ordering};
128 /// use std::sync::Arc;
129 /// use std::{hint, thread};
130 ///
131 /// // A shared atomic value that threads will use to coordinate
132 /// let live = Arc::new(AtomicBool::new(false));
133 ///
134 /// // In a background thread we'll eventually set the value
135 /// let bg_work = {
136 ///     let live = live.clone();
137 ///     thread::spawn(move || {
138 ///         // Do some work, then make the value live
139 ///         do_some_work();
140 ///         live.store(true, Ordering::Release);
141 ///     })
142 /// };
143 ///
144 /// // Back on our current thread, we wait for the value to be set
145 /// while !live.load(Ordering::Acquire) {
146 ///     // The spin loop is a hint to the CPU that we're waiting, but probably
147 ///     // not for very long
148 ///     hint::spin_loop();
149 /// }
150 ///
151 /// // The value is now set
152 /// # fn do_some_work() {}
153 /// do_some_work();
154 /// bg_work.join()?;
155 /// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
156 /// ```
157 ///
158 /// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
159 #[inline]
160 #[stable(feature = "renamed_spin_loop", since = "1.49.0")]
161 pub fn spin_loop() {
162     #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
163     {
164         #[cfg(target_arch = "x86")]
165         {
166             // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
167             unsafe { crate::arch::x86::_mm_pause() };
168         }
169
170         #[cfg(target_arch = "x86_64")]
171         {
172             // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
173             unsafe { crate::arch::x86_64::_mm_pause() };
174         }
175     }
176
177     // RISC-V platform spin loop hint implementation
178     {
179         // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different
180         // modules in `core::arch`.
181         // In this case, here we call `pause` function in each core arch module.
182         #[cfg(target_arch = "riscv32")]
183         {
184             crate::arch::riscv32::pause();
185         }
186         #[cfg(target_arch = "riscv64")]
187         {
188             crate::arch::riscv64::pause();
189         }
190     }
191
192     #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
193     {
194         #[cfg(target_arch = "aarch64")]
195         {
196             // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
197             unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
198         }
199         #[cfg(target_arch = "arm")]
200         {
201             // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
202             // with support for the v6 feature.
203             unsafe { crate::arch::arm::__yield() };
204         }
205     }
206 }
207
208 /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
209 /// `black_box` could do.
210 ///
211 /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
212 /// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
213 /// behavior in the calling code. This property makes `black_box` useful for writing code in which
214 /// certain optimizations are not desired, such as benchmarks.
215 ///
216 /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
217 /// extent to which it can block optimisations may vary depending upon the platform and code-gen
218 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
219 ///
220 /// [`std::convert::identity`]: crate::convert::identity
221 #[inline]
222 #[unstable(feature = "bench_black_box", issue = "64102")]
223 #[rustc_const_unstable(feature = "const_black_box", issue = "none")]
224 pub const fn black_box<T>(dummy: T) -> T {
225     crate::intrinsics::black_box(dummy)
226 }
227
228 /// An identity function that causes an `unused_must_use` warning to be
229 /// triggered if the given value is not used (returned, stored in a variable,
230 /// etc) by the caller.
231 ///
232 /// This is primarily intended for use in macro-generated code, in which a
233 /// [`#[must_use]` attribute][must_use] either on a type or a function would not
234 /// be convenient.
235 ///
236 /// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
237 ///
238 /// # Example
239 ///
240 /// ```
241 /// #![feature(hint_must_use)]
242 ///
243 /// use core::fmt;
244 ///
245 /// pub struct Error(/* ... */);
246 ///
247 /// #[macro_export]
248 /// macro_rules! make_error {
249 ///     ($($args:expr),*) => {
250 ///         core::hint::must_use({
251 ///             let error = $crate::make_error(core::format_args!($($args),*));
252 ///             error
253 ///         })
254 ///     };
255 /// }
256 ///
257 /// // Implementation detail of make_error! macro.
258 /// #[doc(hidden)]
259 /// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
260 ///     Error(/* ... */)
261 /// }
262 ///
263 /// fn demo() -> Option<Error> {
264 ///     if true {
265 ///         // Oops, meant to write `return Some(make_error!("..."));`
266 ///         Some(make_error!("..."));
267 ///     }
268 ///     None
269 /// }
270 /// #
271 /// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
272 /// # fn main() {}
273 /// ```
274 ///
275 /// In the above example, we'd like an `unused_must_use` lint to apply to the
276 /// value created by `make_error!`. However, neither `#[must_use]` on a struct
277 /// nor `#[must_use]` on a function is appropriate here, so the macro expands
278 /// using `core::hint::must_use` instead.
279 ///
280 /// - We wouldn't want `#[must_use]` on the `struct Error` because that would
281 ///   make the following unproblematic code trigger a warning:
282 ///
283 ///   ```
284 ///   # struct Error;
285 ///   #
286 ///   fn f(arg: &str) -> Result<(), Error>
287 ///   # { Ok(()) }
288 ///
289 ///   #[test]
290 ///   fn t() {
291 ///       // Assert that `f` returns error if passed an empty string.
292 ///       // A value of type `Error` is unused here but that's not a problem.
293 ///       f("").unwrap_err();
294 ///   }
295 ///   ```
296 ///
297 /// - Using `#[must_use]` on `fn make_error` can't help because the return value
298 ///   *is* used, as the right-hand side of a `let` statement. The `let`
299 ///   statement looks useless but is in fact necessary for ensuring that
300 ///   temporaries within the `format_args` expansion are not kept alive past the
301 ///   creation of the `Error`, as keeping them alive past that point can cause
302 ///   autotrait issues in async code:
303 ///
304 ///   ```
305 ///   # #![feature(hint_must_use)]
306 ///   #
307 ///   # struct Error;
308 ///   #
309 ///   # macro_rules! make_error {
310 ///   #     ($($args:expr),*) => {
311 ///   #         core::hint::must_use({
312 ///   #             // If `let` isn't used, then `f()` produces a non-Send future.
313 ///   #             let error = make_error(core::format_args!($($args),*));
314 ///   #             error
315 ///   #         })
316 ///   #     };
317 ///   # }
318 ///   #
319 ///   # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
320 ///   #     Error
321 ///   # }
322 ///   #
323 ///   async fn f() {
324 ///       // Using `let` inside the make_error expansion causes temporaries like
325 ///       // `unsync()` to drop at the semicolon of that `let` statement, which
326 ///       // is prior to the await point. They would otherwise stay around until
327 ///       // the semicolon on *this* statement, which is after the await point,
328 ///       // and the enclosing Future would not implement Send.
329 ///       log(make_error!("look: {:p}", unsync())).await;
330 ///   }
331 ///
332 ///   async fn log(error: Error) {/* ... */}
333 ///
334 ///   // Returns something without a Sync impl.
335 ///   fn unsync() -> *const () {
336 ///       0 as *const ()
337 ///   }
338 ///   #
339 ///   # fn test() {
340 ///   #     fn assert_send(_: impl Send) {}
341 ///   #     assert_send(f());
342 ///   # }
343 ///   ```
344 #[unstable(feature = "hint_must_use", issue = "94745")]
345 #[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
346 #[must_use] // <-- :)
347 pub const fn must_use<T>(value: T) -> T {
348     value
349 }