Function no_std_compat::hint::unreachable_unchecked
1.27.0 (const: 1.57.0) · source · pub const unsafe fn unreachable_unchecked() -> !
Expand description
Informs the compiler that the site which is calling this function is not reachable, possibly enabling further optimizations.
§Safety
Reaching this function is Undefined Behavior.
As the compiler assumes that all forms of Undefined Behavior can never
happen, it will eliminate all branches in the surrounding code that it can
determine will invariably lead to a call to unreachable_unchecked()
.
If the assumptions embedded in using this function turn out to be wrong -
that is, if the site which is calling unreachable_unchecked()
is actually
reachable at runtime - the compiler may have generated nonsensical machine
instructions for this situation, including in seemingly unrelated code,
causing difficult-to-debug problems.
Use this function sparingly. Consider using the unreachable!
macro,
which may prevent some optimizations but will safely panic in case it is
actually reached at runtime. Benchmark your code to find out if using
unreachable_unchecked()
comes with a performance benefit.
§Examples
unreachable_unchecked()
can be used in situations where the compiler
can’t prove invariants that were previously established. Such situations
have a higher chance of occurring if those invariants are upheld by
external code that the compiler can’t analyze.
fn prepare_inputs(divisors: &mut Vec<u32>) {
// Note to future-self when making changes: The invariant established
// here is NOT checked in `do_computation()`; if this changes, you HAVE
// to change `do_computation()`.
divisors.retain(|divisor| *divisor != 0)
}
/// # Safety
/// All elements of `divisor` must be non-zero.
unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
divisors.iter().fold(i, |acc, divisor| {
// Convince the compiler that a division by zero can't happen here
// and a check is not needed below.
if *divisor == 0 {
// Safety: `divisor` can't be zero because of `prepare_inputs`,
// but the compiler does not know about this. We *promise*
// that we always call `prepare_inputs`.
std::hint::unreachable_unchecked()
}
// The compiler would normally introduce a check here that prevents
// a division by zero. However, if `divisor` was zero, the branch
// above would reach what we explicitly marked as unreachable.
// The compiler concludes that `divisor` can't be zero at this point
// and removes the - now proven useless - check.
acc / divisor
})
}
let mut divisors = vec![2, 0, 4];
prepare_inputs(&mut divisors);
let result = unsafe {
// Safety: prepare_inputs() guarantees that divisors is non-zero
do_computation(100, &divisors)
};
assert_eq!(result, 12);
While using unreachable_unchecked()
is perfectly sound in the following
example, as the compiler is able to prove that a division by zero is not
possible, benchmarking reveals that unreachable_unchecked()
provides
no benefit over using unreachable!
, while the latter does not introduce
the possibility of Undefined Behavior.
fn div_1(a: u32, b: u32) -> u32 {
use std::hint::unreachable_unchecked;
// `b.saturating_add(1)` is always positive (not zero),
// hence `checked_div` will never return `None`.
// Therefore, the else branch is unreachable.
a.checked_div(b.saturating_add(1))
.unwrap_or_else(|| unsafe { unreachable_unchecked() })
}
assert_eq!(div_1(7, 0), 7);
assert_eq!(div_1(9, 1), 4);
assert_eq!(div_1(11, u32::MAX), 0);