add const_eval_select macro to reduce redundancy
also move internal const_panic helpers to a better location
This commit is contained in:
parent
56c6a2f9b1
commit
613f53ef19
@ -1,7 +1,7 @@
|
|||||||
//! impl char {}
|
//! impl char {}
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::macros::const_panic;
|
use crate::panic::const_panic;
|
||||||
use crate::slice;
|
use crate::slice;
|
||||||
use crate::str::from_utf8_unchecked_mut;
|
use crate::str::from_utf8_unchecked_mut;
|
||||||
use crate::unicode::printable::is_printable;
|
use crate::unicode::printable::is_printable;
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
use crate::cmp::Ordering;
|
use crate::cmp::Ordering;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::ffi::c_char;
|
use crate::ffi::c_char;
|
||||||
|
use crate::intrinsics::const_eval_select;
|
||||||
use crate::iter::FusedIterator;
|
use crate::iter::FusedIterator;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
use crate::ptr::NonNull;
|
use crate::ptr::NonNull;
|
||||||
use crate::slice::memchr;
|
use crate::slice::memchr;
|
||||||
use crate::{fmt, intrinsics, ops, slice, str};
|
use crate::{fmt, ops, slice, str};
|
||||||
|
|
||||||
// FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link
|
// FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link
|
||||||
// depends on where the item is being documented. however, since this is libcore, we can't
|
// depends on where the item is being documented. however, since this is libcore, we can't
|
||||||
@ -411,20 +412,9 @@ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNul
|
|||||||
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
|
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
|
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
|
||||||
#[inline]
|
const_eval_select!(
|
||||||
fn rt_impl(bytes: &[u8]) -> &CStr {
|
@capture { bytes: &[u8] } -> &CStr:
|
||||||
// Chance at catching some UB at runtime with debug builds.
|
if const {
|
||||||
debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
|
|
||||||
|
|
||||||
// SAFETY: Casting to CStr is safe because its internal representation
|
|
||||||
// is a [u8] too (safe only inside std).
|
|
||||||
// Dereferencing the obtained pointer is safe because it comes from a
|
|
||||||
// reference. Making a reference is then safe because its lifetime
|
|
||||||
// is bound by the lifetime of the given `bytes`.
|
|
||||||
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn const_impl(bytes: &[u8]) -> &CStr {
|
|
||||||
// Saturating so that an empty slice panics in the assert with a good
|
// Saturating so that an empty slice panics in the assert with a good
|
||||||
// message, not here due to underflow.
|
// message, not here due to underflow.
|
||||||
let mut i = bytes.len().saturating_sub(1);
|
let mut i = bytes.len().saturating_sub(1);
|
||||||
@ -437,11 +427,20 @@ const fn const_impl(bytes: &[u8]) -> &CStr {
|
|||||||
assert!(byte != 0, "input contained interior nul");
|
assert!(byte != 0, "input contained interior nul");
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: See `rt_impl` cast.
|
// SAFETY: See runtime cast comment below.
|
||||||
|
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
||||||
|
} else {
|
||||||
|
// Chance at catching some UB at runtime with debug builds.
|
||||||
|
debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
|
||||||
|
|
||||||
|
// SAFETY: Casting to CStr is safe because its internal representation
|
||||||
|
// is a [u8] too (safe only inside std).
|
||||||
|
// Dereferencing the obtained pointer is safe because it comes from a
|
||||||
|
// reference. Making a reference is then safe because its lifetime
|
||||||
|
// is bound by the lifetime of the given `bytes`.
|
||||||
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
||||||
}
|
}
|
||||||
|
)
|
||||||
intrinsics::const_eval_select((bytes,), const_impl, rt_impl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner pointer to this C string.
|
/// Returns the inner pointer to this C string.
|
||||||
@ -735,7 +734,9 @@ fn as_ref(&self) -> &CStr {
|
|||||||
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))]
|
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const unsafe fn strlen(ptr: *const c_char) -> usize {
|
const unsafe fn strlen(ptr: *const c_char) -> usize {
|
||||||
const fn strlen_ct(s: *const c_char) -> usize {
|
const_eval_select!(
|
||||||
|
@capture { s: *const c_char = ptr } -> usize:
|
||||||
|
if const {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
||||||
// SAFETY: Outer caller has provided a pointer to a valid C string.
|
// SAFETY: Outer caller has provided a pointer to a valid C string.
|
||||||
@ -744,10 +745,7 @@ const fn strlen_ct(s: *const c_char) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
len
|
len
|
||||||
}
|
} else {
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn strlen_rt(s: *const c_char) -> usize {
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/// Provided by libc or compiler_builtins.
|
/// Provided by libc or compiler_builtins.
|
||||||
fn strlen(s: *const c_char) -> usize;
|
fn strlen(s: *const c_char) -> usize;
|
||||||
@ -756,8 +754,7 @@ fn strlen_rt(s: *const c_char) -> usize {
|
|||||||
// SAFETY: Outer caller has provided a pointer to a valid C string.
|
// SAFETY: Outer caller has provided a pointer to a valid C string.
|
||||||
unsafe { strlen(s) }
|
unsafe { strlen(s) }
|
||||||
}
|
}
|
||||||
|
)
|
||||||
intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over the bytes of a [`CStr`], without the nul terminator.
|
/// An iterator over the bytes of a [`CStr`], without the nul terminator.
|
||||||
|
@ -2788,6 +2788,68 @@ pub const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A macro to make it easier to invoke const_eval_select. Use as follows:
|
||||||
|
/// ```rust,ignore (just a macro example)
|
||||||
|
/// const_eval_select!(
|
||||||
|
/// @capture { arg1: i32 = some_expr, arg2: T = other_expr } -> U:
|
||||||
|
/// if const #[attributes_for_const_arm] {
|
||||||
|
/// // Compile-time code goes here.
|
||||||
|
/// } else #[attributes_for_runtime_arm] {
|
||||||
|
/// // Run-time code goes here.
|
||||||
|
/// }
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
/// The `@capture` block declares which surrounding variables / expressions can be
|
||||||
|
/// used inside the `if const`.
|
||||||
|
/// Note that the two arms of this `if` really each become their own function, which is why the
|
||||||
|
/// macro supports setting attributes for those functions. The runtime function is always
|
||||||
|
/// markes as `#[inline]`.
|
||||||
|
///
|
||||||
|
/// See [`const_eval_select()`] for the rules and requirements around that intrinsic.
|
||||||
|
pub(crate) macro const_eval_select {
|
||||||
|
(
|
||||||
|
@capture { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? :
|
||||||
|
if const
|
||||||
|
$(#[$compiletime_attr:meta])* $compiletime:block
|
||||||
|
else
|
||||||
|
$(#[$runtime_attr:meta])* $runtime:block
|
||||||
|
) => {{
|
||||||
|
#[inline] // avoid the overhead of an extra fn call
|
||||||
|
$(#[$runtime_attr])*
|
||||||
|
fn runtime($($arg: $ty),*) $( -> $ret )? {
|
||||||
|
$runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] // prevent codegen on this function
|
||||||
|
$(#[$compiletime_attr])*
|
||||||
|
const fn compiletime($($arg: $ty),*) $( -> $ret )? {
|
||||||
|
// Don't warn if one of the arguments is unused.
|
||||||
|
$(let _ = $arg;)*
|
||||||
|
|
||||||
|
$compiletime
|
||||||
|
}
|
||||||
|
|
||||||
|
const_eval_select(($($val,)*), compiletime, runtime)
|
||||||
|
}},
|
||||||
|
// We support leaving away the `val` expressions for *all* arguments
|
||||||
|
// (but not for *some* arguments, that's too tricky).
|
||||||
|
(
|
||||||
|
@capture { $($arg:ident : $ty:ty),* $(,)? } $( -> $ret:ty )? :
|
||||||
|
if const
|
||||||
|
$(#[$compiletime_attr:meta])* $compiletime:block
|
||||||
|
else
|
||||||
|
$(#[$runtime_attr:meta])* $runtime:block
|
||||||
|
) => {
|
||||||
|
$crate::intrinsics::const_eval_select!(
|
||||||
|
@capture { $($arg : $ty = $arg),* } $(-> $ret)? :
|
||||||
|
if const
|
||||||
|
$(#[$compiletime_attr])* $compiletime
|
||||||
|
else
|
||||||
|
$(#[$runtime_attr])* $runtime
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether the argument's value is statically known at
|
/// Returns whether the argument's value is statically known at
|
||||||
/// compile-time.
|
/// compile-time.
|
||||||
///
|
///
|
||||||
@ -2830,7 +2892,7 @@ pub const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
|||||||
/// # Stability concerns
|
/// # Stability concerns
|
||||||
///
|
///
|
||||||
/// While it is safe to call, this intrinsic may behave differently in
|
/// While it is safe to call, this intrinsic may behave differently in
|
||||||
/// a `const` context than otherwise. See the [`const_eval_select`]
|
/// a `const` context than otherwise. See the [`const_eval_select()`]
|
||||||
/// documentation for an explanation of the issues this can cause. Unlike
|
/// documentation for an explanation of the issues this can cause. Unlike
|
||||||
/// `const_eval_select`, this intrinsic isn't guaranteed to behave
|
/// `const_eval_select`, this intrinsic isn't guaranteed to behave
|
||||||
/// deterministically even in a `const` context.
|
/// deterministically even in a `const` context.
|
||||||
@ -3734,14 +3796,15 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
|
|||||||
fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
|
fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime(ptr: *const (), align: usize) {
|
const_eval_select!(
|
||||||
|
@capture { ptr: *const (), align: usize}:
|
||||||
|
if const {
|
||||||
|
// Do nothing.
|
||||||
|
} else {
|
||||||
// SAFETY: this call is always safe.
|
// SAFETY: this call is always safe.
|
||||||
unsafe {
|
unsafe {
|
||||||
miri_promise_symbolic_alignment(ptr, align);
|
miri_promise_symbolic_alignment(ptr, align);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn compiletime(_ptr: *const (), _align: usize) {}
|
|
||||||
|
|
||||||
const_eval_select((ptr, align), compiletime, runtime);
|
|
||||||
}
|
}
|
||||||
|
@ -12,54 +12,6 @@ macro_rules! panic {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper macro for panicking in a `const fn`.
|
|
||||||
/// Invoke as:
|
|
||||||
/// ```rust,ignore (just an example)
|
|
||||||
/// core::macros::const_panic!("boring message", "flavored message {a} {b:?}", a: u32 = foo.len(), b: Something = bar);
|
|
||||||
/// ```
|
|
||||||
/// where the first message will be printed in const-eval,
|
|
||||||
/// and the second message will be printed at runtime.
|
|
||||||
// All uses of this macro are FIXME(const-hack).
|
|
||||||
#[unstable(feature = "panic_internals", issue = "none")]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub macro const_panic {
|
|
||||||
($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty = $val:expr),* $(,)?) => {{
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
fn runtime($($arg: $ty),*) -> ! {
|
|
||||||
$crate::panic!($runtime_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
const fn compiletime($(_: $ty),*) -> ! {
|
|
||||||
$crate::panic!($const_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap call to `const_eval_select` in a function so that we can
|
|
||||||
// add the `rustc_allow_const_fn_unstable`. This is okay to do
|
|
||||||
// because both variants will panic, just with different messages.
|
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
|
||||||
#[inline(always)]
|
|
||||||
#[track_caller]
|
|
||||||
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "CURRENT_RUSTC_VERSION"))]
|
|
||||||
const fn do_panic($($arg: $ty),*) -> ! {
|
|
||||||
$crate::intrinsics::const_eval_select(($($arg),* ,), compiletime, runtime)
|
|
||||||
}
|
|
||||||
|
|
||||||
do_panic($($val),*)
|
|
||||||
}},
|
|
||||||
// We support leaving away the `val` expressions for *all* arguments
|
|
||||||
// (but not for *some* arguments, that's too tricky).
|
|
||||||
($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty),* $(,)?) => {
|
|
||||||
$crate::macros::const_panic!(
|
|
||||||
$const_msg,
|
|
||||||
$runtime_msg,
|
|
||||||
$($arg: $ty = $arg),*
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
||||||
///
|
///
|
||||||
/// Assertions are always checked in both debug and release builds, and cannot
|
/// Assertions are always checked in both debug and release builds, and cannot
|
||||||
@ -244,19 +196,6 @@ macro_rules! assert_ne {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A version of `assert` that prints a non-formatting message in const contexts.
|
|
||||||
///
|
|
||||||
/// See [`const_panic!`].
|
|
||||||
#[unstable(feature = "panic_internals", issue = "none")]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub macro const_assert {
|
|
||||||
($condition: expr, $const_msg:literal, $runtime_msg:literal, $($arg:tt)*) => {{
|
|
||||||
if !$crate::intrinsics::likely($condition) {
|
|
||||||
$crate::macros::const_panic!($const_msg, $runtime_msg, $($arg)*)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A macro for defining `#[cfg]` match-like statements.
|
/// A macro for defining `#[cfg]` match-like statements.
|
||||||
///
|
///
|
||||||
/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
|
/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
use crate::convert::FloatToInt;
|
use crate::convert::FloatToInt;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::intrinsics;
|
use crate::intrinsics;
|
||||||
use crate::macros::const_assert;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::num::FpCategory;
|
use crate::num::FpCategory;
|
||||||
|
use crate::panic::const_assert;
|
||||||
|
|
||||||
/// Basic mathematical constants.
|
/// Basic mathematical constants.
|
||||||
#[unstable(feature = "f128", issue = "116909")]
|
#[unstable(feature = "f128", issue = "116909")]
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
use crate::convert::FloatToInt;
|
use crate::convert::FloatToInt;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::intrinsics;
|
use crate::intrinsics;
|
||||||
use crate::macros::const_assert;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::num::FpCategory;
|
use crate::num::FpCategory;
|
||||||
|
use crate::panic::const_assert;
|
||||||
|
|
||||||
/// Basic mathematical constants.
|
/// Basic mathematical constants.
|
||||||
#[unstable(feature = "f16", issue = "116909")]
|
#[unstable(feature = "f16", issue = "116909")]
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
use crate::convert::FloatToInt;
|
use crate::convert::FloatToInt;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::intrinsics;
|
use crate::intrinsics;
|
||||||
use crate::macros::const_assert;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::num::FpCategory;
|
use crate::num::FpCategory;
|
||||||
|
use crate::panic::const_assert;
|
||||||
|
|
||||||
/// The radix or base of the internal representation of `f32`.
|
/// The radix or base of the internal representation of `f32`.
|
||||||
/// Use [`f32::RADIX`] instead.
|
/// Use [`f32::RADIX`] instead.
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
use crate::convert::FloatToInt;
|
use crate::convert::FloatToInt;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::intrinsics;
|
use crate::intrinsics;
|
||||||
use crate::macros::const_assert;
|
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::num::FpCategory;
|
use crate::num::FpCategory;
|
||||||
|
use crate::panic::const_assert;
|
||||||
|
|
||||||
/// The radix or base of the internal representation of `f64`.
|
/// The radix or base of the internal representation of `f64`.
|
||||||
/// Use [`f64::RADIX`] instead.
|
/// Use [`f64::RADIX`] instead.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
use crate::macros::const_panic;
|
use crate::panic::const_panic;
|
||||||
use crate::str::FromStr;
|
use crate::str::FromStr;
|
||||||
use crate::ub_checks::assert_unsafe_precondition;
|
use crate::ub_checks::assert_unsafe_precondition;
|
||||||
use crate::{ascii, intrinsics, mem};
|
use crate::{ascii, intrinsics, mem};
|
||||||
|
@ -189,3 +189,59 @@ fn as_str(&mut self) -> Option<&str> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro for panicking in a `const fn`.
|
||||||
|
/// Invoke as:
|
||||||
|
/// ```rust,ignore (just an example)
|
||||||
|
/// core::macros::const_panic!("boring message", "flavored message {a} {b:?}", a: u32 = foo.len(), b: Something = bar);
|
||||||
|
/// ```
|
||||||
|
/// where the first message will be printed in const-eval,
|
||||||
|
/// and the second message will be printed at runtime.
|
||||||
|
// All uses of this macro are FIXME(const-hack).
|
||||||
|
#[unstable(feature = "panic_internals", issue = "none")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub macro const_panic {
|
||||||
|
($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty = $val:expr),* $(,)?) => {{
|
||||||
|
// Wrap call to `const_eval_select` in a function so that we can
|
||||||
|
// add the `rustc_allow_const_fn_unstable`. This is okay to do
|
||||||
|
// because both variants will panic, just with different messages.
|
||||||
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
|
#[inline(always)]
|
||||||
|
#[track_caller]
|
||||||
|
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_panic", since = "CURRENT_RUSTC_VERSION"))]
|
||||||
|
const fn do_panic($($arg: $ty),*) -> ! {
|
||||||
|
$crate::intrinsics::const_eval_select!(
|
||||||
|
@capture { $($arg: $ty),* } -> !:
|
||||||
|
if const #[track_caller] {
|
||||||
|
$crate::panic!($const_msg)
|
||||||
|
} else #[track_caller] {
|
||||||
|
$crate::panic!($runtime_msg)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
do_panic($($val),*)
|
||||||
|
}},
|
||||||
|
// We support leaving away the `val` expressions for *all* arguments
|
||||||
|
// (but not for *some* arguments, that's too tricky).
|
||||||
|
($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty),* $(,)?) => {
|
||||||
|
$crate::panic::const_panic!(
|
||||||
|
$const_msg,
|
||||||
|
$runtime_msg,
|
||||||
|
$($arg: $ty = $arg),*
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A version of `assert` that prints a non-formatting message in const contexts.
|
||||||
|
///
|
||||||
|
/// See [`const_panic!`].
|
||||||
|
#[unstable(feature = "panic_internals", issue = "none")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub macro const_assert {
|
||||||
|
($condition: expr, $const_msg:literal, $runtime_msg:literal, $($arg:tt)*) => {{
|
||||||
|
if !$crate::intrinsics::likely($condition) {
|
||||||
|
$crate::panic::const_panic!($const_msg, $runtime_msg, $($arg)*)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
|
use crate::intrinsics::const_eval_select;
|
||||||
use crate::panic::{Location, PanicInfo};
|
use crate::panic::{Location, PanicInfo};
|
||||||
|
|
||||||
#[cfg(feature = "panic_immediate_abort")]
|
#[cfg(feature = "panic_immediate_abort")]
|
||||||
@ -89,9 +90,12 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
|||||||
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
|
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
|
pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
|
||||||
#[inline] // this should always be inlined into `panic_nounwind_fmt`
|
const_eval_select!(
|
||||||
#[track_caller]
|
@capture { fmt: fmt::Arguments<'_>, force_no_backtrace: bool } -> !:
|
||||||
fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
|
if const #[track_caller] {
|
||||||
|
// We don't unwind anyway at compile-time so we can call the regular `panic_fmt`.
|
||||||
|
panic_fmt(fmt)
|
||||||
|
} else #[track_caller] {
|
||||||
if cfg!(feature = "panic_immediate_abort") {
|
if cfg!(feature = "panic_immediate_abort") {
|
||||||
super::intrinsics::abort()
|
super::intrinsics::abort()
|
||||||
}
|
}
|
||||||
@ -114,15 +118,7 @@ fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
|
|||||||
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
|
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
|
||||||
unsafe { panic_impl(&pi) }
|
unsafe { panic_impl(&pi) }
|
||||||
}
|
}
|
||||||
|
)
|
||||||
#[inline]
|
|
||||||
#[track_caller]
|
|
||||||
const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
|
|
||||||
// We don't unwind anyway at compile-time so we can call the regular `panic_fmt`.
|
|
||||||
panic_fmt(fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
|
// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
|
||||||
|
@ -33,14 +33,12 @@ impl<T: ?Sized> *const T {
|
|||||||
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
#[inline]
|
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||||
fn runtime_impl(ptr: *const u8) -> bool {
|
// considering their "data" part for null-ness.
|
||||||
ptr.addr() == 0
|
let ptr = self as *const u8;
|
||||||
}
|
const_eval_select!(
|
||||||
|
@capture { ptr: *const u8 } -> bool:
|
||||||
#[inline]
|
if const #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")] {
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
|
||||||
const fn const_impl(ptr: *const u8) -> bool {
|
|
||||||
match (ptr).guaranteed_eq(null_mut()) {
|
match (ptr).guaranteed_eq(null_mut()) {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
// To remain maximally convervative, we stop execution when we don't
|
// To remain maximally convervative, we stop execution when we don't
|
||||||
@ -48,11 +46,10 @@ const fn const_impl(ptr: *const u8) -> bool {
|
|||||||
// We can *not* return `false` here, that would be unsound in `NonNull::new`!
|
// We can *not* return `false` here, that would be unsound in `NonNull::new`!
|
||||||
None => panic!("null-ness of this pointer cannot be determined in const context"),
|
None => panic!("null-ness of this pointer cannot be determined in const context"),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ptr.addr() == 0
|
||||||
}
|
}
|
||||||
|
)
|
||||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
|
||||||
// considering their "data" part for null-ness.
|
|
||||||
const_eval_select((self as *const u8,), const_impl, runtime_impl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts to a pointer of another type.
|
/// Casts to a pointer of another type.
|
||||||
@ -410,22 +407,21 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
|
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
|
||||||
#[inline]
|
// We can use const_eval_select here because this is only for UB checks.
|
||||||
fn runtime(this: *const (), count: isize, size: usize) -> bool {
|
const_eval_select!(
|
||||||
// We know `size <= isize::MAX` so the `as` cast here is not lossy.
|
@capture { this: *const (), count: isize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// `size` is the size of a Rust type, so we know that
|
||||||
|
// `size <= isize::MAX` and thus `as` cast here is not lossy.
|
||||||
let Some(byte_offset) = count.checked_mul(size as isize) else {
|
let Some(byte_offset) = count.checked_mul(size as isize) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let (_, overflow) = this.addr().overflowing_add_signed(byte_offset);
|
let (_, overflow) = this.addr().overflowing_add_signed(byte_offset);
|
||||||
!overflow
|
!overflow
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: isize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can use const_eval_select here because this is only for UB checks.
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ub_checks::assert_unsafe_precondition!(
|
ub_checks::assert_unsafe_precondition!(
|
||||||
@ -763,14 +759,14 @@ pub fn mask(self, mask: usize) -> *const T {
|
|||||||
{
|
{
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool {
|
const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool {
|
||||||
fn runtime(this: *const (), origin: *const ()) -> bool {
|
const_eval_select!(
|
||||||
|
@capture { this: *const (), origin: *const () } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
this >= origin
|
this >= origin
|
||||||
}
|
}
|
||||||
const fn comptime(_: *const (), _: *const ()) -> bool {
|
)
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsics::const_eval_select((this, origin), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ub_checks::assert_unsafe_precondition!(
|
ub_checks::assert_unsafe_precondition!(
|
||||||
@ -924,20 +920,18 @@ pub const fn guaranteed_ne(self, other: *const T) -> Option<bool>
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
||||||
#[inline]
|
const_eval_select!(
|
||||||
fn runtime(this: *const (), count: usize, size: usize) -> bool {
|
@capture { this: *const (), count: usize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
let Some(byte_offset) = count.checked_mul(size) else {
|
let Some(byte_offset) = count.checked_mul(size) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let (_, overflow) = this.addr().overflowing_add(byte_offset);
|
let (_, overflow) = this.addr().overflowing_add(byte_offset);
|
||||||
byte_offset <= (isize::MAX as usize) && !overflow
|
byte_offset <= (isize::MAX as usize) && !overflow
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
||||||
@ -1033,19 +1027,17 @@ const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
||||||
#[inline]
|
const_eval_select!(
|
||||||
fn runtime(this: *const (), count: usize, size: usize) -> bool {
|
@capture { this: *const (), count: usize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
let Some(byte_offset) = count.checked_mul(size) else {
|
let Some(byte_offset) = count.checked_mul(size) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset
|
byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::cmp::Ordering::{Equal, Greater, Less};
|
use crate::cmp::Ordering::{Equal, Greater, Less};
|
||||||
|
use crate::intrinsics::const_eval_select;
|
||||||
use crate::mem::SizedTypeProperties;
|
use crate::mem::SizedTypeProperties;
|
||||||
use crate::slice::{self, SliceIndex};
|
use crate::slice::{self, SliceIndex};
|
||||||
|
|
||||||
@ -404,8 +405,12 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
|
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
|
||||||
#[inline]
|
// We can use const_eval_select here because this is only for UB checks.
|
||||||
fn runtime(this: *const (), count: isize, size: usize) -> bool {
|
const_eval_select!(
|
||||||
|
@capture { this: *const (), count: isize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
// `size` is the size of a Rust type, so we know that
|
// `size` is the size of a Rust type, so we know that
|
||||||
// `size <= isize::MAX` and thus `as` cast here is not lossy.
|
// `size <= isize::MAX` and thus `as` cast here is not lossy.
|
||||||
let Some(byte_offset) = count.checked_mul(size as isize) else {
|
let Some(byte_offset) = count.checked_mul(size as isize) else {
|
||||||
@ -414,13 +419,7 @@ fn runtime(this: *const (), count: isize, size: usize) -> bool {
|
|||||||
let (_, overflow) = this.addr().overflowing_add_signed(byte_offset);
|
let (_, overflow) = this.addr().overflowing_add_signed(byte_offset);
|
||||||
!overflow
|
!overflow
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: isize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can use const_eval_select here because this is only for UB checks.
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ub_checks::assert_unsafe_precondition!(
|
ub_checks::assert_unsafe_precondition!(
|
||||||
@ -1002,20 +1001,18 @@ pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
||||||
#[inline]
|
const_eval_select!(
|
||||||
fn runtime(this: *const (), count: usize, size: usize) -> bool {
|
@capture { this: *const (), count: usize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
let Some(byte_offset) = count.checked_mul(size) else {
|
let Some(byte_offset) = count.checked_mul(size) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let (_, overflow) = this.addr().overflowing_add(byte_offset);
|
let (_, overflow) = this.addr().overflowing_add(byte_offset);
|
||||||
byte_offset <= (isize::MAX as usize) && !overflow
|
byte_offset <= (isize::MAX as usize) && !overflow
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
||||||
@ -1111,19 +1108,17 @@ const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
|
||||||
#[inline]
|
const_eval_select!(
|
||||||
fn runtime(this: *const (), count: usize, size: usize) -> bool {
|
@capture { this: *const (), count: usize, size: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
let Some(byte_offset) = count.checked_mul(size) else {
|
let Some(byte_offset) = count.checked_mul(size) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset
|
byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset
|
||||||
}
|
}
|
||||||
|
)
|
||||||
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsics::const_eval_select((this, count, size), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
|
||||||
|
@ -351,14 +351,11 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
|
|||||||
const fn is_ascii(s: &[u8]) -> bool {
|
const fn is_ascii(s: &[u8]) -> bool {
|
||||||
// The runtime version behaves the same as the compiletime version, it's
|
// The runtime version behaves the same as the compiletime version, it's
|
||||||
// just more optimized.
|
// just more optimized.
|
||||||
return const_eval_select((s,), compiletime, runtime);
|
const_eval_select!(
|
||||||
|
@capture { s: &[u8] } -> bool:
|
||||||
const fn compiletime(s: &[u8]) -> bool {
|
if const {
|
||||||
is_ascii_simple(s)
|
is_ascii_simple(s)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn runtime(s: &[u8]) -> bool {
|
|
||||||
const USIZE_SIZE: usize = mem::size_of::<usize>();
|
const USIZE_SIZE: usize = mem::size_of::<usize>();
|
||||||
|
|
||||||
let len = s.len();
|
let len = s.len();
|
||||||
@ -436,4 +433,5 @@ fn runtime(s: &[u8]) -> bool {
|
|||||||
|
|
||||||
!contains_nonascii(last_word)
|
!contains_nonascii(last_word)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Indexing implementations for `[T]`.
|
//! Indexing implementations for `[T]`.
|
||||||
|
|
||||||
use crate::macros::const_panic;
|
use crate::panic::const_panic;
|
||||||
use crate::ub_checks::assert_unsafe_precondition;
|
use crate::ub_checks::assert_unsafe_precondition;
|
||||||
use crate::{ops, range};
|
use crate::{ops, range};
|
||||||
|
|
||||||
|
@ -56,14 +56,11 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
|
|||||||
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
|
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
|
||||||
// The runtime version behaves the same as the compiletime version, it's
|
// The runtime version behaves the same as the compiletime version, it's
|
||||||
// just more optimized.
|
// just more optimized.
|
||||||
return const_eval_select((x, text), compiletime, runtime);
|
const_eval_select!(
|
||||||
|
@capture { x: u8, text: &[u8] } -> Option<usize>:
|
||||||
const fn compiletime(x: u8, text: &[u8]) -> Option<usize> {
|
if const {
|
||||||
memchr_naive(x, text)
|
memchr_naive(x, text)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn runtime(x: u8, text: &[u8]) -> Option<usize> {
|
|
||||||
// Scan for a single byte value by reading two `usize` words at a time.
|
// Scan for a single byte value by reading two `usize` words at a time.
|
||||||
//
|
//
|
||||||
// Split `text` in three parts
|
// Split `text` in three parts
|
||||||
@ -111,6 +108,7 @@ fn runtime(x: u8, text: &[u8]) -> Option<usize> {
|
|||||||
unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) };
|
unsafe { super::from_raw_parts(text.as_ptr().add(offset), text.len() - offset) };
|
||||||
if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None }
|
if let Some(i) = memchr_naive(x, slice) { Some(offset + i) } else { None }
|
||||||
}
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last index matching the byte `x` in `text`.
|
/// Returns the last index matching the byte `x` in `text`.
|
||||||
|
@ -132,19 +132,16 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
|||||||
|
|
||||||
let ascii_block_size = 2 * USIZE_BYTES;
|
let ascii_block_size = 2 * USIZE_BYTES;
|
||||||
let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
|
let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
|
||||||
let align = {
|
|
||||||
const fn compiletime(_v: &[u8]) -> usize {
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
fn runtime(v: &[u8]) -> usize {
|
|
||||||
v.as_ptr().align_offset(USIZE_BYTES)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Below, we safely fall back to a slower codepath if the offset is `usize::MAX`,
|
// Below, we safely fall back to a slower codepath if the offset is `usize::MAX`,
|
||||||
// so the end-to-end behavior is the same at compiletime and runtime.
|
// so the end-to-end behavior is the same at compiletime and runtime.
|
||||||
const_eval_select((v,), compiletime, runtime)
|
let align = const_eval_select!(
|
||||||
};
|
@capture { v: &[u8] } -> usize:
|
||||||
|
if const {
|
||||||
|
usize::MAX
|
||||||
|
} else {
|
||||||
|
v.as_ptr().align_offset(USIZE_BYTES)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
while index < len {
|
while index < len {
|
||||||
let old_offset = index;
|
let old_offset = index;
|
||||||
|
@ -95,20 +95,18 @@ const fn precondition_check($($name:$ty),*) {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
pub(crate) const fn check_language_ub() -> bool {
|
pub(crate) const fn check_language_ub() -> bool {
|
||||||
#[inline]
|
// Only used for UB checks so we may const_eval_select.
|
||||||
fn runtime() -> bool {
|
intrinsics::ub_checks()
|
||||||
|
&& const_eval_select!(
|
||||||
|
@capture { } -> bool:
|
||||||
|
if const {
|
||||||
|
// Always disable UB checks.
|
||||||
|
false
|
||||||
|
} else {
|
||||||
// Disable UB checks in Miri.
|
// Disable UB checks in Miri.
|
||||||
!cfg!(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 the given alignment, and
|
/// Checks whether `ptr` is properly aligned with respect to the given alignment, and
|
||||||
@ -120,19 +118,15 @@ const fn comptime() -> bool {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
||||||
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
||||||
#[inline]
|
// This is just for safety checks so we can const_eval_select.
|
||||||
fn runtime(ptr: *const (), align: usize, is_zst: bool) -> bool {
|
const_eval_select!(
|
||||||
|
@capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
|
||||||
|
if const #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] {
|
||||||
|
is_zst || !ptr.is_null()
|
||||||
|
} else {
|
||||||
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
|
||||||
}
|
}
|
||||||
|
)
|
||||||
#[inline]
|
|
||||||
#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
|
|
||||||
const fn comptime(ptr: *const (), _align: usize, is_zst: bool) -> bool {
|
|
||||||
is_zst || !ptr.is_null()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just for safety checks so we can const_eval_select.
|
|
||||||
const_eval_select((ptr, align, is_zst), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -154,8 +148,12 @@ pub(crate) const fn is_nonoverlapping(
|
|||||||
size: usize,
|
size: usize,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
#[inline]
|
// This is just for safety checks so we can const_eval_select.
|
||||||
fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
|
const_eval_select!(
|
||||||
|
@capture { src: *const (), dst: *const (), size: usize, count: usize } -> bool:
|
||||||
|
if const {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
let src_usize = src.addr();
|
let src_usize = src.addr();
|
||||||
let dst_usize = dst.addr();
|
let dst_usize = dst.addr();
|
||||||
let Some(size) = size.checked_mul(count) else {
|
let Some(size) = size.checked_mul(count) else {
|
||||||
@ -168,12 +166,5 @@ fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
|
|||||||
// they do not overlap.
|
// they do not overlap.
|
||||||
diff >= size
|
diff >= size
|
||||||
}
|
}
|
||||||
|
)
|
||||||
#[inline]
|
|
||||||
const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just for safety checks so we can const_eval_select.
|
|
||||||
const_eval_select((src, dst, size, count), comptime, runtime)
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ error[E0080]: evaluation of constant value failed
|
|||||||
|
|
|
|
||||||
= note: the evaluated program panicked at 'null-ness of this pointer cannot be determined in const context', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: the evaluated program panicked at 'null-ness of this pointer cannot be determined in const context', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||||
|
|
|
|
||||||
note: inside `std::ptr::const_ptr::<impl *const T>::is_null::const_impl`
|
note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime`
|
||||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||||
note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
|
note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
|
||||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||||
@ -12,7 +12,7 @@ note: inside `MAYBE_NULL`
|
|||||||
|
|
|
|
||||||
LL | assert!(!ptr.wrapping_sub(512).is_null());
|
LL | assert!(!ptr.wrapping_sub(512).is_null());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user