Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen const panic messages as function calls #122671

Merged
merged 1 commit into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
Expand Down
24 changes: 8 additions & 16 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,14 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
);
}
_ => {
let msg_str = msg.description();
codegen_panic(fx, msg_str, source_info);
let location = fx.get_caller_location(source_info).load_scalar(fx);

codegen_panic_inner(
fx,
msg.panic_function(),
&[location],
Some(source_info.span),
);
}
}
}
Expand Down Expand Up @@ -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>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
msg_str: &str,
Expand Down
30 changes: 30 additions & 0 deletions compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
fn panic_cannot_unwind() -> ! {
unsafe {
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,10 +651,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
}
_ => {
let msg = bx.const_str(msg.description());
// It's `pub fn panic(expr: &str)`, with the wide reference being passed
// as two arguments, and `#[track_caller]` adds an implicit third argument.
(LangItem::Panic, vec![msg.0, msg.1, location])
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
(msg.panic_function(), vec![location])
}
};

Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,25 @@ language_item_table! {
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
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);
/// 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
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;

Expand Down
73 changes: 49 additions & 24 deletions compiler/rustc_middle/src/mir/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,44 +149,45 @@ impl<O> AssertKind<O> {
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
/// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
/// instead of printing a static message.
pub fn description(&self) -> &'static str {
/// instead of printing a static message. Those have dynamic arguments that aren't present for
/// the rest of the messages here.
pub fn panic_function(&self) -> LangItem {
use AssertKind::*;
match self {
Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
OverflowNeg(_) => "attempt to negate with overflow",
Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
OverflowNeg(_) => LangItem::PanicNegOverflow,
Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
DivisionByZero(_) => "attempt to divide by zero",
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => "coroutine resumed after completion",
DivisionByZero(_) => LangItem::PanicDivZero,
RemainderByZero(_) => LangItem::PanicRemZero,
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
"`async fn` resumed after completion"
LangItem::PanicAsyncFnResumed
}
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
"`async gen fn` resumed after completion"
LangItem::PanicAsyncGenFnResumed
}
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, _)) => {
"`async fn` resumed after panicking"
LangItem::PanicAsyncFnResumedPanic
}
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
"`async gen fn` resumed after panicking"
LangItem::PanicAsyncGenFnResumedPanic
}
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
"`gen fn` should just keep returning `None` after panicking"
LangItem::PanicGenFnNonePanic
}

BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
Expand All @@ -198,7 +199,7 @@ impl<O> AssertKind<O> {
/// 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
/// `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
/// 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
Expand Down Expand Up @@ -246,20 +247,44 @@ impl<O> AssertKind<O> {
Overflow(BinOp::Shl, _, r) => {
write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
}
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
MisalignedPointerDereference { required, found } => {
write!(
f,
"\"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).
///
/// 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
/// numbers that overflowed -- it is much easier to do so here than at runtime.
pub fn diagnostic_message(&self) -> DiagMessage {
Expand Down
21 changes: 11 additions & 10 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,16 +971,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
}
}
}
mir::TerminatorKind::Assert { ref msg, .. } => {
let lang_item = match &**msg {
mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
mir::AssertKind::MisalignedPointerDereference { .. } => {
LangItem::PanicMisalignedPointerDereference
}
_ => LangItem::Panic,
};
push_mono_lang_item(self, lang_item);
}
mir::TerminatorKind::Assert { ref msg, .. } => match &**msg {
mir::AssertKind::BoundsCheck { .. } => {
push_mono_lang_item(self, LangItem::PanicBoundsCheck);
}
mir::AssertKind::MisalignedPointerDereference { .. } => {
push_mono_lang_item(self, LangItem::PanicMisalignedPointerDereference);
}
_ => {
push_mono_lang_item(self, msg.panic_function());
}
},
mir::TerminatorKind::UnwindTerminate(reason) => {
push_mono_lang_item(self, reason.lang_item());
}
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,24 @@ symbols! {
panic_abort,
panic_bounds_check,
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_handler,
panic_impl,
Expand Down
Loading
Loading