diff options
| author | Ralf Jung <post@ralfj.de> | 2024-03-17 10:29:02 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2024-03-23 18:45:05 +0100 |
| commit | 61775304200826b412f18fc87218161fb8a0dc5c (patch) | |
| tree | 43a2a658f42b2e50f03f8f09d1f970ebeef564a3 /library/core/src | |
| parent | 987ef4c9221e792614a015a39b78f7d6a156c2f2 (diff) | |
| download | rust-61775304200826b412f18fc87218161fb8a0dc5c.tar.gz rust-61775304200826b412f18fc87218161fb8a0dc5c.zip | |
refactor check_{lang,library}_ub: use a single intrinsic, put policy into library
Diffstat (limited to 'library/core/src')
| -rw-r--r-- | library/core/src/intrinsics.rs | 44 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/ub_checks.rs | 35 |
3 files changed, 46 insertions, 34 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index af83a8d8fa4..76e387d54d8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -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. -/// -/// 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")] +/// 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, 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) } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8f292bf1551..0c95ecafc7c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 2c5b4699806..ff6b2d30539 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -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>()`. /// |
