assert_unsafe_precondition in core - Rust
Description: Checks that the preconditions of an unsafe function are followed.

## assert_unsafe_precondition

# Macro assert_unsafe_precondition

Source

    macro_rules! assert_unsafe_precondition {
        ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => { ... };
    }

🔬This is a nightly-only experimental API. (`ub_checks`)
Expand description

Checks that the preconditions of an unsafe function are followed.

The check is enabled at runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri checks implemented with this macro for language UB are always ignored.

This macro should be called as `assert_unsafe_precondition!(check_{library,language}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)` where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all those arguments are passed to a function with the body `check_expr`. Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation of a documented library precondition that does not immediately lead to language UB.

If `check_library_ub` is used but the check is actually guarding language UB, the check will slow down const-eval/Miri and we’ll get the panic message instead of the interpreter’s nice diagnostic, but our ability to detect UB is unchanged. But if `check_language_ub` is used when the check is actually for library UB, the check is omitted in const-eval/Miri and thus UB might occur undetected. Even if we eventually execute language UB which relies on the library UB, the backtrace Miri reports may be far removed from original cause.

These checks are behind a condition which is evaluated at codegen time, not expansion time like `debug_assert`. This means that a standard library built with optimizations and debug assertions disabled will have these checks optimized out of its monomorphizations, but if a caller of the standard library has debug assertions enabled and monomorphizes an expansion of this macro, that monomorphization will contain the check.

Since these checks cannot be optimized out in MIR, some care must be taken in both call and implementation to mitigate their compile-time overhead. Calls to this macro always expand to this structure:

ⓘ

    if ::core::intrinsics::check_language_ub() {
        precondition_check(args)
    }

where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is compiled only once and generates a minimal amount of IR because the check cannot be inlined in MIR, but can be inlined and fully optimized by a codegen backend.

Callers should avoid introducing any other `let` bindings or any code outside this macro in order to call it. Since the precompiled standard library is built with full debuginfo and these variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough debuginfo to have a measurable compile-time impact on debug builds.