mirror of https://github.com/rust-lang/rust.git
add const_panic macro to make it easier to fall back to non-formatting panic in const
This commit is contained in:
parent
07cbbdd693
commit
bc757f9034
|
@ -1,7 +1,7 @@
|
|||
//! impl char {}
|
||||
|
||||
use super::*;
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::macros::const_panic;
|
||||
use crate::slice;
|
||||
use crate::str::from_utf8_unchecked_mut;
|
||||
use crate::unicode::printable::is_printable;
|
||||
|
@ -1774,17 +1774,7 @@ const fn len_utf16(code: u32) -> usize {
|
|||
#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))]
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
|
||||
const fn panic_at_const(_code: u32, _len: usize, _dst_len: usize) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
panic!("encode_utf8: buffer does not have enough bytes to encode code point");
|
||||
}
|
||||
fn panic_at_rt(code: u32, len: usize, dst_len: usize) {
|
||||
panic!(
|
||||
"encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}",
|
||||
);
|
||||
}
|
||||
let len = len_utf8(code);
|
||||
match (len, &mut *dst) {
|
||||
(1, [a, ..]) => {
|
||||
|
@ -1805,8 +1795,15 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
|
|||
*c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*d = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
_ => const_eval_select((code, len, dst.len()), panic_at_const, panic_at_rt),
|
||||
_ => {
|
||||
const_panic!(
|
||||
"encode_utf8: buffer does not have enough bytes to encode code point",
|
||||
"encode_utf8: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}",
|
||||
code: u32 = code,
|
||||
len: usize = len,
|
||||
dst_len: usize = dst.len(),
|
||||
)
|
||||
}
|
||||
};
|
||||
// SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds.
|
||||
unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) }
|
||||
|
@ -1827,15 +1824,6 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
|
|||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] {
|
||||
const fn panic_at_const(_code: u32, _len: usize, _dst_len: usize) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
panic!("encode_utf16: buffer does not have enough bytes to encode code point");
|
||||
}
|
||||
fn panic_at_rt(code: u32, len: usize, dst_len: usize) {
|
||||
panic!(
|
||||
"encode_utf16: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}",
|
||||
);
|
||||
}
|
||||
let len = len_utf16(code);
|
||||
match (len, &mut *dst) {
|
||||
(1, [a, ..]) => {
|
||||
|
@ -1846,8 +1834,15 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] {
|
|||
*a = (code >> 10) as u16 | 0xD800;
|
||||
*b = (code & 0x3FF) as u16 | 0xDC00;
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
_ => const_eval_select((code, len, dst.len()), panic_at_const, panic_at_rt),
|
||||
_ => {
|
||||
const_panic!(
|
||||
"encode_utf16: buffer does not have enough bytes to encode code point",
|
||||
"encode_utf16: need {len} bytes to encode U+{code:04X} but buffer has just {dst_len}",
|
||||
code: u32 = code,
|
||||
len: usize = len,
|
||||
dst_len: usize = dst.len(),
|
||||
)
|
||||
}
|
||||
};
|
||||
// SAFETY: `<&mut [u16]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds.
|
||||
unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) }
|
||||
|
|
|
@ -12,6 +12,54 @@ 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`]).
|
||||
///
|
||||
/// Assertions are always checked in both debug and release builds, and cannot
|
||||
|
@ -196,6 +244,19 @@ pub macro assert_matches {
|
|||
},
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use crate::convert::FloatToInt;
|
||||
#[cfg(not(test))]
|
||||
use crate::intrinsics;
|
||||
use crate::macros::const_assert;
|
||||
use crate::mem;
|
||||
use crate::num::FpCategory;
|
||||
|
||||
|
@ -1263,17 +1264,14 @@ impl f128 {
|
|||
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
pub const fn clamp(mut self, min: f128, max: f128) -> f128 {
|
||||
#[inline] // inline to avoid LLVM crash
|
||||
const fn assert_at_const(min: f128, max: f128) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
assert!(min <= max, "min > max, or either was NaN");
|
||||
}
|
||||
#[inline] // inline to avoid codegen regression
|
||||
fn assert_at_rt(min: f128, max: f128) {
|
||||
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
|
||||
const_assert!(
|
||||
min <= max,
|
||||
"min > max, or either was NaN",
|
||||
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
|
||||
min: f128,
|
||||
max: f128,
|
||||
);
|
||||
|
||||
if self < min {
|
||||
self = min;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use crate::convert::FloatToInt;
|
||||
#[cfg(not(test))]
|
||||
use crate::intrinsics;
|
||||
use crate::macros::const_assert;
|
||||
use crate::mem;
|
||||
use crate::num::FpCategory;
|
||||
|
||||
|
@ -1238,17 +1239,14 @@ impl f16 {
|
|||
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
|
||||
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||
pub const fn clamp(mut self, min: f16, max: f16) -> f16 {
|
||||
#[inline] // inline to avoid LLVM crash
|
||||
const fn assert_at_const(min: f16, max: f16) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
assert!(min <= max, "min > max, or either was NaN");
|
||||
}
|
||||
#[inline] // inline to avoid codegen regression
|
||||
fn assert_at_rt(min: f16, max: f16) {
|
||||
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
|
||||
const_assert!(
|
||||
min <= max,
|
||||
"min > max, or either was NaN",
|
||||
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
|
||||
min: f16,
|
||||
max: f16,
|
||||
);
|
||||
|
||||
if self < min {
|
||||
self = min;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use crate::convert::FloatToInt;
|
||||
#[cfg(not(test))]
|
||||
use crate::intrinsics;
|
||||
use crate::macros::const_assert;
|
||||
use crate::mem;
|
||||
use crate::num::FpCategory;
|
||||
|
||||
|
@ -1409,16 +1410,14 @@ impl f32 {
|
|||
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
|
||||
#[inline]
|
||||
pub const fn clamp(mut self, min: f32, max: f32) -> f32 {
|
||||
const fn assert_at_const(min: f32, max: f32) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
assert!(min <= max, "min > max, or either was NaN");
|
||||
}
|
||||
#[inline] // inline to avoid codegen regression
|
||||
fn assert_at_rt(min: f32, max: f32) {
|
||||
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
|
||||
const_assert!(
|
||||
min <= max,
|
||||
"min > max, or either was NaN",
|
||||
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
|
||||
min: f32,
|
||||
max: f32,
|
||||
);
|
||||
|
||||
if self < min {
|
||||
self = min;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use crate::convert::FloatToInt;
|
||||
#[cfg(not(test))]
|
||||
use crate::intrinsics;
|
||||
use crate::macros::const_assert;
|
||||
use crate::mem;
|
||||
use crate::num::FpCategory;
|
||||
|
||||
|
@ -1409,16 +1410,14 @@ impl f64 {
|
|||
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
|
||||
#[inline]
|
||||
pub const fn clamp(mut self, min: f64, max: f64) -> f64 {
|
||||
const fn assert_at_const(min: f64, max: f64) {
|
||||
// Note that we cannot format in constant expressions.
|
||||
assert!(min <= max, "min > max, or either was NaN");
|
||||
}
|
||||
#[inline] // inline to avoid codegen regression
|
||||
fn assert_at_rt(min: f64, max: f64) {
|
||||
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
|
||||
}
|
||||
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
|
||||
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
|
||||
const_assert!(
|
||||
min <= max,
|
||||
"min > max, or either was NaN",
|
||||
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
|
||||
min: f64,
|
||||
max: f64,
|
||||
);
|
||||
|
||||
if self < min {
|
||||
self = min;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::macros::const_panic;
|
||||
use crate::str::FromStr;
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
use crate::{ascii, intrinsics, mem};
|
||||
|
@ -1460,24 +1461,16 @@ pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8])
|
|||
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
const fn from_str_radix_panic_ct(_radix: u32) -> ! {
|
||||
panic!("from_str_radix_int: must lie in the range `[2, 36]`");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn from_str_radix_panic_rt(radix: u32) -> ! {
|
||||
panic!("from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix);
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
const fn from_str_radix_panic(radix: u32) {
|
||||
// The only difference between these two functions is their panic message.
|
||||
intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
|
||||
const fn from_str_radix_panic(radix: u32) -> ! {
|
||||
const_panic!(
|
||||
"from_str_radix_int: must lie in the range `[2, 36]`",
|
||||
"from_str_radix_int: must lie in the range `[2, 36]` - found {radix}",
|
||||
radix: u32 = radix,
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! from_str_radix {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Indexing implementations for `[T]`.
|
||||
|
||||
use crate::intrinsics::const_eval_select;
|
||||
use crate::macros::const_panic;
|
||||
use crate::ub_checks::assert_unsafe_precondition;
|
||||
use crate::{ops, range};
|
||||
|
||||
|
@ -31,67 +31,37 @@ where
|
|||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
||||
// FIXME(const-hack): once integer formatting in panics is possible, we
|
||||
// should use the same implementation at compiletime and runtime.
|
||||
const_eval_select((index, len), slice_start_index_len_fail_ct, slice_start_index_len_fail_rt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
|
||||
panic!("range start index {index} out of range for slice of length {len}");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
|
||||
panic!("slice start index is out of range for slice");
|
||||
const_panic!(
|
||||
"slice start index is out of range for slice",
|
||||
"range start index {index} out of range for slice of length {len}",
|
||||
index: usize,
|
||||
len: usize,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
||||
// FIXME(const-hack): once integer formatting in panics is possible, we
|
||||
// should use the same implementation at compiletime and runtime.
|
||||
const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
|
||||
panic!("range end index {index} out of range for slice of length {len}");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
|
||||
panic!("slice end index is out of range for slice");
|
||||
const_panic!(
|
||||
"slice end index is out of range for slice",
|
||||
"range end index {index} out of range for slice of length {len}",
|
||||
index: usize,
|
||||
len: usize,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
||||
// FIXME(const-hack): once integer formatting in panics is possible, we
|
||||
// should use the same implementation at compiletime and runtime.
|
||||
const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
|
||||
panic!("slice index starts at {index} but ends at {end}");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
|
||||
panic!("slice index start is larger than end");
|
||||
const_panic!(
|
||||
"slice index start is larger than end",
|
||||
"slice index starts at {index} but ends at {end}",
|
||||
index: usize,
|
||||
end: usize,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
|
|
Loading…
Reference in New Issue