Codegen const panic messages as function calls
This skips emitting extra arguments at every callsite (of which there can be many). For a librustc_driver build with overflow checks enabled, this cuts 0.7MB from the resulting binary.
This commit is contained in:
parent
0ad927c0c0
commit
00f4daa276
@ -465,6 +465,36 @@ pub fn panic(_msg: &'static str) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! panic_const {
|
||||||
|
($($lang:ident = $message:expr,)+) => {
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub mod panic_const {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[track_caller]
|
||||||
|
#[lang = stringify!($lang)]
|
||||||
|
pub fn $lang() -> ! {
|
||||||
|
panic($message);
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic_const! {
|
||||||
|
panic_const_add_overflow = "attempt to add with overflow",
|
||||||
|
panic_const_sub_overflow = "attempt to subtract with overflow",
|
||||||
|
panic_const_mul_overflow = "attempt to multiply with overflow",
|
||||||
|
panic_const_div_overflow = "attempt to divide with overflow",
|
||||||
|
panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
|
||||||
|
panic_const_neg_overflow = "attempt to negate with overflow",
|
||||||
|
panic_const_shr_overflow = "attempt to shift right with overflow",
|
||||||
|
panic_const_shl_overflow = "attempt to shift left with overflow",
|
||||||
|
panic_const_div_by_zero = "attempt to divide by zero",
|
||||||
|
panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
|
||||||
|
}
|
||||||
|
|
||||||
#[lang = "panic_bounds_check"]
|
#[lang = "panic_bounds_check"]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn panic_bounds_check(index: usize, len: usize) -> ! {
|
fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||||
|
@ -369,8 +369,14 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg_str = msg.description();
|
let location = fx.get_caller_location(source_info).load_scalar(fx);
|
||||||
codegen_panic(fx, msg_str, source_info);
|
|
||||||
|
codegen_panic_inner(
|
||||||
|
fx,
|
||||||
|
msg.panic_function(),
|
||||||
|
&[location],
|
||||||
|
Some(source_info.span),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -954,20 +960,6 @@ pub(crate) fn codegen_operand<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn codegen_panic<'tcx>(
|
|
||||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
|
||||||
msg_str: &str,
|
|
||||||
source_info: mir::SourceInfo,
|
|
||||||
) {
|
|
||||||
let location = fx.get_caller_location(source_info).load_scalar(fx);
|
|
||||||
|
|
||||||
let msg_ptr = fx.anonymous_str(msg_str);
|
|
||||||
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
|
|
||||||
let args = [msg_ptr, msg_len, location];
|
|
||||||
|
|
||||||
codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, Some(source_info.span));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn codegen_panic_nounwind<'tcx>(
|
pub(crate) fn codegen_panic_nounwind<'tcx>(
|
||||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||||
msg_str: &str,
|
msg_str: &str,
|
||||||
|
@ -418,6 +418,36 @@ pub fn panic(_msg: &'static str) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! panic_const {
|
||||||
|
($($lang:ident = $message:expr,)+) => {
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub mod panic_const {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[track_caller]
|
||||||
|
#[lang = stringify!($lang)]
|
||||||
|
pub fn $lang() -> ! {
|
||||||
|
panic($message);
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic_const! {
|
||||||
|
panic_const_add_overflow = "attempt to add with overflow",
|
||||||
|
panic_const_sub_overflow = "attempt to subtract with overflow",
|
||||||
|
panic_const_mul_overflow = "attempt to multiply with overflow",
|
||||||
|
panic_const_div_overflow = "attempt to divide with overflow",
|
||||||
|
panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
|
||||||
|
panic_const_neg_overflow = "attempt to negate with overflow",
|
||||||
|
panic_const_shr_overflow = "attempt to shift right with overflow",
|
||||||
|
panic_const_shl_overflow = "attempt to shift left with overflow",
|
||||||
|
panic_const_div_by_zero = "attempt to divide by zero",
|
||||||
|
panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
|
||||||
|
}
|
||||||
|
|
||||||
#[lang = "panic_cannot_unwind"]
|
#[lang = "panic_cannot_unwind"]
|
||||||
fn panic_cannot_unwind() -> ! {
|
fn panic_cannot_unwind() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -651,10 +651,8 @@ fn codegen_assert_terminator(
|
|||||||
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
|
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = bx.const_str(msg.description());
|
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
|
||||||
// It's `pub fn panic(expr: &str)`, with the wide reference being passed
|
(msg.panic_function(), vec![location])
|
||||||
// as two arguments, and `#[track_caller]` adds an implicit third argument.
|
|
||||||
(LangItem::Panic, vec![msg.0, msg.1, location])
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -246,6 +246,25 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
|
|||||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
||||||
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
|
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
|
||||||
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);
|
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);
|
||||||
|
/// Constant panic messages, used for codegen of MIR asserts.
|
||||||
|
PanicAddOverflow, sym::panic_const_add_overflow, panic_const_add_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicSubOverflow, sym::panic_const_sub_overflow, panic_const_sub_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicMulOverflow, sym::panic_const_mul_overflow, panic_const_mul_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicDivOverflow, sym::panic_const_div_overflow, panic_const_div_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicRemOverflow, sym::panic_const_rem_overflow, panic_const_rem_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicNegOverflow, sym::panic_const_neg_overflow, panic_const_neg_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicShrOverflow, sym::panic_const_shr_overflow, panic_const_shr_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicShlOverflow, sym::panic_const_shl_overflow, panic_const_shl_overflow, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicDivZero, sym::panic_const_div_by_zero, panic_const_div_by_zero, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicRemZero, sym::panic_const_rem_by_zero, panic_const_rem_by_zero, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicCoroutineResumed, sym::panic_const_coroutine_resumed, panic_const_coroutine_resumed, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicAsyncFnResumed, sym::panic_const_async_fn_resumed, panic_const_async_fn_resumed, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicAsyncGenFnResumed, sym::panic_const_async_gen_fn_resumed, panic_const_async_gen_fn_resumed, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicGenFnNone, sym::panic_const_gen_fn_none, panic_const_gen_fn_none, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicCoroutineResumedPanic, sym::panic_const_coroutine_resumed_panic, panic_const_coroutine_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicAsyncFnResumedPanic, sym::panic_const_async_fn_resumed_panic, panic_const_async_fn_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
|
||||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||||
|
|
||||||
|
@ -149,44 +149,45 @@ pub fn is_optional_overflow_check(&self) -> bool {
|
|||||||
matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
|
matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the message that is printed at runtime when this assertion fails.
|
/// Get the lang item that is invoked to print a static message when this assert fires.
|
||||||
///
|
///
|
||||||
/// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` by
|
/// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` by
|
||||||
/// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
|
/// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
|
||||||
/// instead of printing a static message.
|
/// instead of printing a static message. Those have dynamic arguments that aren't present for
|
||||||
pub fn description(&self) -> &'static str {
|
/// the rest of the messages here.
|
||||||
|
pub fn panic_function(&self) -> LangItem {
|
||||||
use AssertKind::*;
|
use AssertKind::*;
|
||||||
match self {
|
match self {
|
||||||
Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
|
Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
|
||||||
Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
|
Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
|
||||||
Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
|
Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
|
||||||
Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
|
Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
|
||||||
Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
|
Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
|
||||||
OverflowNeg(_) => "attempt to negate with overflow",
|
OverflowNeg(_) => LangItem::PanicNegOverflow,
|
||||||
Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
|
Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
|
||||||
Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
|
Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
|
||||||
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
|
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
|
||||||
DivisionByZero(_) => "attempt to divide by zero",
|
DivisionByZero(_) => LangItem::PanicDivZero,
|
||||||
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
|
RemainderByZero(_) => LangItem::PanicRemZero,
|
||||||
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => "coroutine resumed after completion",
|
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
|
||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
"`async fn` resumed after completion"
|
LangItem::PanicAsyncFnResumed
|
||||||
}
|
}
|
||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
||||||
"`async gen fn` resumed after completion"
|
LangItem::PanicAsyncGenFnResumed
|
||||||
}
|
}
|
||||||
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
"`gen fn` should just keep returning `None` after completion"
|
LangItem::PanicGenFnNone
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => "coroutine resumed after panicking",
|
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
|
||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
"`async fn` resumed after panicking"
|
LangItem::PanicAsyncFnResumedPanic
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
||||||
"`async gen fn` resumed after panicking"
|
LangItem::PanicAsyncGenFnResumedPanic
|
||||||
}
|
}
|
||||||
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
"`gen fn` should just keep returning `None` after panicking"
|
LangItem::PanicGenFnNonePanic
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
|
BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
|
||||||
@ -198,7 +199,7 @@ pub fn description(&self) -> &'static str {
|
|||||||
/// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
|
/// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
|
||||||
///
|
///
|
||||||
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
||||||
/// `AssertKind::description` and the lang items mentioned in its docs).
|
/// `AssertKind::panic_function` and the lang items mentioned in its docs).
|
||||||
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
||||||
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
||||||
pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
|
pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
|
||||||
@ -246,20 +247,44 @@ pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
|
|||||||
Overflow(BinOp::Shl, _, r) => {
|
Overflow(BinOp::Shl, _, r) => {
|
||||||
write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
|
write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
|
||||||
}
|
}
|
||||||
|
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
|
||||||
MisalignedPointerDereference { required, found } => {
|
MisalignedPointerDereference { required, found } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
|
"\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => write!(f, "\"{}\"", self.description()),
|
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
|
||||||
|
write!(f, "\"coroutine resumed after completion\"")
|
||||||
|
}
|
||||||
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
|
write!(f, "\"`async fn` resumed after completion\"")
|
||||||
|
}
|
||||||
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
||||||
|
write!(f, "\"`async gen fn` resumed after completion\"")
|
||||||
|
}
|
||||||
|
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
|
write!(f, "\"`gen fn` should just keep returning `None` after completion\"")
|
||||||
|
}
|
||||||
|
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
|
||||||
|
write!(f, "\"coroutine resumed after panicking\"")
|
||||||
|
}
|
||||||
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
|
||||||
|
write!(f, "\"`async fn` resumed after panicking\"")
|
||||||
|
}
|
||||||
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
|
||||||
|
write!(f, "\"`async gen fn` resumed after panicking\"")
|
||||||
|
}
|
||||||
|
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
|
||||||
|
write!(f, "\"`gen fn` should just keep returning `None` after panicking\"")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval).
|
/// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval).
|
||||||
///
|
///
|
||||||
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
||||||
/// `AssertKind::description` and the lang items mentioned in its docs).
|
/// `AssertKind::panic_function` and the lang items mentioned in its docs).
|
||||||
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
||||||
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
||||||
pub fn diagnostic_message(&self) -> DiagMessage {
|
pub fn diagnostic_message(&self) -> DiagMessage {
|
||||||
|
@ -971,16 +971,17 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::Assert { ref msg, .. } => {
|
mir::TerminatorKind::Assert { ref msg, .. } => match &**msg {
|
||||||
let lang_item = match &**msg {
|
mir::AssertKind::BoundsCheck { .. } => {
|
||||||
mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
|
push_mono_lang_item(self, LangItem::PanicBoundsCheck);
|
||||||
|
}
|
||||||
mir::AssertKind::MisalignedPointerDereference { .. } => {
|
mir::AssertKind::MisalignedPointerDereference { .. } => {
|
||||||
LangItem::PanicMisalignedPointerDereference
|
push_mono_lang_item(self, LangItem::PanicMisalignedPointerDereference);
|
||||||
}
|
}
|
||||||
_ => LangItem::Panic,
|
_ => {
|
||||||
};
|
push_mono_lang_item(self, msg.panic_function());
|
||||||
push_mono_lang_item(self, lang_item);
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
mir::TerminatorKind::UnwindTerminate(reason) => {
|
mir::TerminatorKind::UnwindTerminate(reason) => {
|
||||||
push_mono_lang_item(self, reason.lang_item());
|
push_mono_lang_item(self, reason.lang_item());
|
||||||
}
|
}
|
||||||
|
@ -1297,6 +1297,24 @@
|
|||||||
panic_abort,
|
panic_abort,
|
||||||
panic_bounds_check,
|
panic_bounds_check,
|
||||||
panic_cannot_unwind,
|
panic_cannot_unwind,
|
||||||
|
panic_const_add_overflow,
|
||||||
|
panic_const_async_fn_resumed,
|
||||||
|
panic_const_async_fn_resumed_panic,
|
||||||
|
panic_const_async_gen_fn_resumed,
|
||||||
|
panic_const_async_gen_fn_resumed_panic,
|
||||||
|
panic_const_coroutine_resumed,
|
||||||
|
panic_const_coroutine_resumed_panic,
|
||||||
|
panic_const_div_by_zero,
|
||||||
|
panic_const_div_overflow,
|
||||||
|
panic_const_gen_fn_none,
|
||||||
|
panic_const_gen_fn_none_panic,
|
||||||
|
panic_const_mul_overflow,
|
||||||
|
panic_const_neg_overflow,
|
||||||
|
panic_const_rem_by_zero,
|
||||||
|
panic_const_rem_overflow,
|
||||||
|
panic_const_shl_overflow,
|
||||||
|
panic_const_shr_overflow,
|
||||||
|
panic_const_sub_overflow,
|
||||||
panic_fmt,
|
panic_fmt,
|
||||||
panic_handler,
|
panic_handler,
|
||||||
panic_impl,
|
panic_impl,
|
||||||
|
@ -130,17 +130,80 @@ const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
|
|||||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
|
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
|
||||||
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
|
#[lang = "panic"] // used by lints and miri for panics
|
||||||
pub const fn panic(expr: &'static str) -> ! {
|
pub const fn panic(expr: &'static str) -> ! {
|
||||||
// Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
|
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
|
||||||
// reduce size overhead. The format_args! macro uses str's Display trait to
|
// reduce size overhead. The format_args! macro uses str's Display trait to
|
||||||
// write expr, which calls Formatter::pad, which must accommodate string
|
// write expr, which calls Formatter::pad, which must accommodate string
|
||||||
// truncation and padding (even though none is used here). Using
|
// truncation and padding (even though none is used here). Using
|
||||||
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
// Arguments::new_const may allow the compiler to omit Formatter::pad from the
|
||||||
// output binary, saving up to a few kilobytes.
|
// output binary, saving up to a few kilobytes.
|
||||||
panic_fmt(fmt::Arguments::new_const(&[expr]));
|
panic_fmt(fmt::Arguments::new_const(&[expr]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We generate functions for usage by compiler-generated assertions.
|
||||||
|
//
|
||||||
|
// Placing these functions in libcore means that all Rust programs can generate a jump into this
|
||||||
|
// code rather than expanding to panic("...") above, which adds extra bloat to call sites (for the
|
||||||
|
// constant string argument's pointer and length).
|
||||||
|
//
|
||||||
|
// This is especially important when this code is called often (e.g., with -Coverflow-checks) for
|
||||||
|
// reducing binary size impact.
|
||||||
|
macro_rules! panic_const {
|
||||||
|
($($lang:ident = $message:expr,)+) => {
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub mod panic_const {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
$(
|
||||||
|
/// This is a panic called with a message that's a result of a MIR-produced Assert.
|
||||||
|
//
|
||||||
|
// never inline unless panic_immediate_abort to avoid code
|
||||||
|
// bloat at the call sites as much as possible
|
||||||
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||||
|
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||||
|
#[track_caller]
|
||||||
|
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
|
||||||
|
#[lang = stringify!($lang)]
|
||||||
|
pub const fn $lang() -> ! {
|
||||||
|
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
|
||||||
|
// reduce size overhead. The format_args! macro uses str's Display trait to
|
||||||
|
// write expr, which calls Formatter::pad, which must accommodate string
|
||||||
|
// truncation and padding (even though none is used here). Using
|
||||||
|
// Arguments::new_const may allow the compiler to omit Formatter::pad from the
|
||||||
|
// output binary, saving up to a few kilobytes.
|
||||||
|
panic_fmt(fmt::Arguments::new_const(&[$message]));
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfortunately this set of strings is replicated here and in a few places in the compiler in
|
||||||
|
// slightly different forms. It's not clear if there's a good way to deduplicate without adding
|
||||||
|
// special cases to the compiler (e.g., a const generic function wouldn't have a single definition
|
||||||
|
// shared across crates, which is exactly what we want here).
|
||||||
|
panic_const! {
|
||||||
|
panic_const_add_overflow = "attempt to add with overflow",
|
||||||
|
panic_const_sub_overflow = "attempt to subtract with overflow",
|
||||||
|
panic_const_mul_overflow = "attempt to multiply with overflow",
|
||||||
|
panic_const_div_overflow = "attempt to divide with overflow",
|
||||||
|
panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
|
||||||
|
panic_const_neg_overflow = "attempt to negate with overflow",
|
||||||
|
panic_const_shr_overflow = "attempt to shift right with overflow",
|
||||||
|
panic_const_shl_overflow = "attempt to shift left with overflow",
|
||||||
|
panic_const_div_by_zero = "attempt to divide by zero",
|
||||||
|
panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
|
||||||
|
panic_const_coroutine_resumed = "coroutine resumed after completion",
|
||||||
|
panic_const_async_fn_resumed = "`async fn` resumed after completion",
|
||||||
|
panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
|
||||||
|
panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
|
||||||
|
panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
|
||||||
|
panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
|
||||||
|
panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
|
||||||
|
panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
|
||||||
|
}
|
||||||
|
|
||||||
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
|
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
|
||||||
/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
|
/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
|
||||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||||
|
@ -256,8 +256,16 @@ fn assert_panic(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// Forward everything else to `panic` lang item.
|
// Call the lang item associated with this message.
|
||||||
this.start_panic(msg.description(), unwind)?;
|
let fn_item = this.tcx.require_lang_item(msg.panic_function(), None);
|
||||||
|
let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
|
||||||
|
this.call_function(
|
||||||
|
instance,
|
||||||
|
Abi::Rust,
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
StackPopCleanup::Goto { ret: None, unwind },
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -16,10 +16,17 @@ struct Location<'a> {
|
|||||||
_col: u32,
|
_col: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "panic"]
|
#[lang = "panic_const_div_by_zero"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn panic(_: &'static str) -> ! {
|
fn panic_div_zero() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "panic_const_div_overflow"]
|
||||||
|
#[inline]
|
||||||
|
#[track_caller]
|
||||||
|
fn panic_div_overflow() -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,4 +62,5 @@ pub fn foo() {
|
|||||||
|
|
||||||
//~ MONO_ITEM fn foo
|
//~ MONO_ITEM fn foo
|
||||||
//~ MONO_ITEM fn <i32 as Div>::div
|
//~ MONO_ITEM fn <i32 as Div>::div
|
||||||
//~ MONO_ITEM fn panic
|
//~ MONO_ITEM fn panic_div_zero
|
||||||
|
//~ MONO_ITEM fn panic_div_overflow
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
//@[NOASSERT] compile-flags: -Coverflow-checks=off
|
//@[NOASSERT] compile-flags: -Coverflow-checks=off
|
||||||
|
|
||||||
// CHECK-LABEL: define{{.*}} @assertion
|
// CHECK-LABEL: define{{.*}} @assertion
|
||||||
// ASSERT: call void @{{.*4core9panicking5panic}}
|
// ASSERT: call void @{{.*4core9panicking11panic_const24panic_const_add_overflow}}
|
||||||
// NOASSERT: ret i8 0
|
// NOASSERT: ret i8 0
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn assertion() -> u8 {
|
pub fn assertion() -> u8 {
|
||||||
|
Loading…
Reference in New Issue
Block a user