Skip to content

Commit 3263ad8

Browse files
committed
refactor check_{lang,library}_ub: use a single intrinsic, put policy into library
1 parent c629e7a commit 3263ad8

File tree

3 files changed

+46
-34
lines changed

3 files changed

+46
-34
lines changed

core/src/intrinsics.rs

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,38 +2661,22 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
26612661
unsafe { ptr::swap_nonoverlapping(x, y, 1) };
26622662
}
26632663

2664-
/// Returns whether we should check for library UB. This evaluate to the value of `cfg!(debug_assertions)`
2665-
/// during monomorphization.
2666-
///
2667-
/// This intrinsic is evaluated after monomorphization, and therefore branching on this value can
2668-
/// be used to implement debug assertions that are included in the precompiled standard library,
2669-
/// but can be optimized out by builds that monomorphize the standard library code with debug
2670-
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
2671-
///
2672-
/// We have separate intrinsics for library UB and language UB because checkers like the const-eval
2673-
/// interpreter and Miri already implement checks for language UB. Since such checkers do not know
2674-
/// about library preconditions, checks guarded by this intrinsic let them find more UB.
2675-
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
2664+
/// Returns whether we should perform some UB-checking at runtime. This evaluate to the value of
2665+
/// `cfg!(debug_assertions)` during monomorphization.
2666+
///
2667+
/// This intrinsic is evaluated after monomorphization, which is relevant when mixing crates
2668+
/// compiled with and without debug_assertions. The common case here is a user program built with
2669+
/// debug_assertions linked against the distributed sysroot which is built without debug_assertions.
2670+
/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with
2671+
/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that
2672+
/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the
2673+
/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is
2674+
/// primarily used by [`ub_checks::assert_unsafe_precondition`].
2675+
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
26762676
#[unstable(feature = "core_intrinsics", issue = "none")]
26772677
#[inline(always)]
2678-
#[rustc_intrinsic]
2679-
pub(crate) const fn check_library_ub() -> bool {
2680-
cfg!(debug_assertions)
2681-
}
2682-
2683-
/// Returns whether we should check for language UB. This evaluate to the value of `cfg!(debug_assertions)`
2684-
/// during monomorphization.
2685-
///
2686-
/// Since checks implemented at the source level must come strictly before the operation that
2687-
/// executes UB, if we enabled language UB checks in const-eval/Miri we would miss out on the
2688-
/// interpreter's improved diagnostics for the cases that our source-level checks catch.
2689-
///
2690-
/// See `check_library_ub` for more information.
2691-
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
2692-
#[unstable(feature = "core_intrinsics", issue = "none")]
2693-
#[inline(always)]
2694-
#[rustc_intrinsic]
2695-
pub(crate) const fn check_language_ub() -> bool {
2678+
#[cfg_attr(not(bootstrap), rustc_intrinsic)] // just make it a regular fn in bootstrap
2679+
pub(crate) const fn ub_checks() -> bool {
26962680
cfg!(debug_assertions)
26972681
}
26982682

core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@
171171
#![feature(const_type_id)]
172172
#![feature(const_type_name)]
173173
#![feature(const_typed_swap)]
174+
#![feature(const_ub_checks)]
174175
#![feature(const_unicode_case_lookup)]
175176
#![feature(const_unsafecell_get_mut)]
176177
#![feature(const_waker)]

core/src/ub_checks.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Provides the [`assert_unsafe_precondition`] macro as well as some utility functions that cover
22
//! common preconditions.
33
4-
use crate::intrinsics::const_eval_select;
4+
use crate::intrinsics::{self, const_eval_select};
55

66
/// Check that the preconditions of an unsafe function are followed. The check is enabled at
77
/// 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;
4545
/// order to call it. Since the precompiled standard library is built with full debuginfo and these
4646
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
4747
/// debuginfo to have a measurable compile-time impact on debug builds.
48-
#[allow_internal_unstable(ub_checks)] // permit this to be called in stably-const fn
48+
#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
4949
macro_rules! assert_unsafe_precondition {
5050
($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
5151
{
@@ -60,7 +60,7 @@ macro_rules! assert_unsafe_precondition {
6060
#[rustc_no_mir_inline]
6161
#[inline]
6262
#[rustc_nounwind]
63-
#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
63+
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
6464
const fn precondition_check($($name:$ty),*) {
6565
if !$e {
6666
::core::panicking::panic_nounwind(
@@ -69,14 +69,41 @@ macro_rules! assert_unsafe_precondition {
6969
}
7070
}
7171

72-
if ::core::intrinsics::$kind() {
72+
if ::core::ub_checks::$kind() {
7373
precondition_check($($arg,)*);
7474
}
7575
}
7676
};
7777
}
7878
pub(crate) use assert_unsafe_precondition;
7979

80+
/// Checking library UB is always enabled when UB-checking is done
81+
/// (and we use a reexport so that there is no unnecessary wrapper function).
82+
pub(crate) use intrinsics::ub_checks as check_library_ub;
83+
84+
/// Determines whether we should check for language UB.
85+
///
86+
/// The intention is to not do that when running in the interpreter, as that one has its own
87+
/// language UB checks which generally produce better errors.
88+
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
89+
#[inline]
90+
pub(crate) const fn check_language_ub() -> bool {
91+
#[inline]
92+
fn runtime() -> bool {
93+
// Disable UB checks in Miri.
94+
!cfg!(miri)
95+
}
96+
97+
#[inline]
98+
const fn comptime() -> bool {
99+
// Always disable UB checks.
100+
false
101+
}
102+
103+
// Only used for UB checks so we may const_eval_select.
104+
intrinsics::ub_checks() && const_eval_select((), comptime, runtime)
105+
}
106+
80107
/// Checks whether `ptr` is properly aligned with respect to
81108
/// `align_of::<T>()`.
82109
///

0 commit comments

Comments
 (0)