refactor check_{lang,library}_ub: use a single intrinsic, put policy into library
This commit is contained in:
@@ -2661,38 +2661,22 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
|
||||
unsafe { ptr::swap_nonoverlapping(x, y, 1) };
|
||||
}
|
||||
|
||||
/// Returns whether we should check for library UB. This evaluate to the value of `cfg!(debug_assertions)`
|
||||
/// during monomorphization.
|
||||
/// Returns whether we should perform some UB-checking at runtime. This evaluate to the value of
|
||||
/// `cfg!(debug_assertions)` during monomorphization.
|
||||
///
|
||||
/// This intrinsic is evaluated after monomorphization, and therefore branching on this value can
|
||||
/// be used to implement debug assertions that are included in the precompiled standard library,
|
||||
/// but can be optimized out by builds that monomorphize the standard library code with debug
|
||||
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
|
||||
///
|
||||
/// We have separate intrinsics for library UB and language UB because checkers like the const-eval
|
||||
/// interpreter and Miri already implement checks for language UB. Since such checkers do not know
|
||||
/// about library preconditions, checks guarded by this intrinsic let them find more UB.
|
||||
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
|
||||
/// This intrinsic is evaluated after monomorphization, which is relevant when mixing crates
|
||||
/// compiled with and without debug_assertions. The common case here is a user program built with
|
||||
/// debug_assertions linked against the distributed sysroot which is built without debug_assertions.
|
||||
/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with
|
||||
/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that
|
||||
/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the
|
||||
/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is
|
||||
/// primarily used by [`ub_checks::assert_unsafe_precondition`].
|
||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[inline(always)]
|
||||
#[rustc_intrinsic]
|
||||
pub(crate) const fn check_library_ub() -> bool {
|
||||
cfg!(debug_assertions)
|
||||
}
|
||||
|
||||
/// Returns whether we should check for language UB. This evaluate to the value of `cfg!(debug_assertions)`
|
||||
/// during monomorphization.
|
||||
///
|
||||
/// Since checks implemented at the source level must come strictly before the operation that
|
||||
/// executes UB, if we enabled language UB checks in const-eval/Miri we would miss out on the
|
||||
/// interpreter's improved diagnostics for the cases that our source-level checks catch.
|
||||
///
|
||||
/// See `check_library_ub` for more information.
|
||||
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[inline(always)]
|
||||
#[rustc_intrinsic]
|
||||
pub(crate) const fn check_language_ub() -> bool {
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)] // just make it a regular fn in bootstrap
|
||||
pub(crate) const fn ub_checks() -> bool {
|
||||
cfg!(debug_assertions)
|
||||
}
|
||||
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
#![feature(const_type_id)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_typed_swap)]
|
||||
#![feature(const_ub_checks)]
|
||||
#![feature(const_unicode_case_lookup)]
|
||||
#![feature(const_unsafecell_get_mut)]
|
||||
#![feature(const_waker)]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Provides the [`assert_unsafe_precondition`] macro as well as some utility functions that cover
|
||||
//! common preconditions.
|
||||
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::intrinsics::{self, const_eval_select};
|
||||
|
||||
/// Check 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
|
||||
@@ -45,7 +45,7 @@ use crate::intrinsics::const_eval_select;
|
||||
/// 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.
|
||||
#[allow_internal_unstable(ub_checks)] // permit this to be called in stably-const fn
|
||||
#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
|
||||
macro_rules! assert_unsafe_precondition {
|
||||
($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
|
||||
{
|
||||
@@ -60,7 +60,7 @@ macro_rules! assert_unsafe_precondition {
|
||||
#[rustc_no_mir_inline]
|
||||
#[inline]
|
||||
#[rustc_nounwind]
|
||||
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||
const fn precondition_check($($name:$ty),*) {
|
||||
if !$e {
|
||||
::core::panicking::panic_nounwind(
|
||||
@@ -69,7 +69,7 @@ macro_rules! assert_unsafe_precondition {
|
||||
}
|
||||
}
|
||||
|
||||
if ::core::intrinsics::$kind() {
|
||||
if ::core::ub_checks::$kind() {
|
||||
precondition_check($($arg,)*);
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,33 @@ macro_rules! assert_unsafe_precondition {
|
||||
}
|
||||
pub(crate) use assert_unsafe_precondition;
|
||||
|
||||
/// Checking library UB is always enabled when UB-checking is done
|
||||
/// (and we use a reexport so that there is no unnecessary wrapper function).
|
||||
pub(crate) use intrinsics::ub_checks as check_library_ub;
|
||||
|
||||
/// Determines whether we should check for language UB.
|
||||
///
|
||||
/// The intention is to not do that when running in the interpreter, as that one has its own
|
||||
/// language UB checks which generally produce better errors.
|
||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||
#[inline]
|
||||
pub(crate) const fn check_language_ub() -> bool {
|
||||
#[inline]
|
||||
fn runtime() -> bool {
|
||||
// Disable UB checks in Miri.
|
||||
!cfg!(miri)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn comptime() -> bool {
|
||||
// Always disable UB checks.
|
||||
false
|
||||
}
|
||||
|
||||
// Only used for UB checks so we may const_eval_select.
|
||||
intrinsics::ub_checks() && const_eval_select((), comptime, runtime)
|
||||
}
|
||||
|
||||
/// Checks whether `ptr` is properly aligned with respect to
|
||||
/// `align_of::<T>()`.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user