Currently panic!
is implemented as such:
// for std
static ARGS: _ = (format_args!("format string", args...), file!(), line!(), column!())
std::rt::begin_panic_fmt(&ARGS)
// for core
static ARGS: _ = (format_args!("format string", args...), file!(), line!(), column!())
core::panicking::panic(&ARGS)
This implementation is tuned very heavily to make sure that at the panic location as little code is generated as possible, and as much of it, as possible, is generated at compile time.
In LLVM this desugars to code as trivial as (somewhat abridged):
@str.6 = internal constant [6 x i8] c"peach.rs"
@ref.7 = private unnamed_addr constant { { [0 x i8]*, i64 }, i32, i32 } { { [0 x i8]*, i64 } { [0 x i8]* bitcast ([6 x i8]* @str.6 to [0 x i8]*), i64 6 }, i32 9, i32 5 }, align 8
define void @banana() unnamed_addr #1 personality i32 (...)* @rust_eh_personality {
; constructs ArgumentsV1 with some more global constants
invoke void @"core::panicking::panic_fmt"(%"core::fmt::Arguments"* noalias nocapture nonnull dereferenceable(48) %_1, { { [0 x i8]*, i64 }, i32, i32 }* noalias readonly dereferenceable(24) bitcast ({ { [0 x i8]*, i64 }, i32, i32 }* @ref.7 to { { [0 x i8]*, i64 }, i32, i32 }*))
to label %unreachable unwind label %cleanup
}
; later on
declare void @"core::panicking::panic_fmt"(%"core::fmt::Arguments"* noalias nocapture dereferenceable(48), { { [0 x i8]*, i64 }, i32, i32 }* noalias readonly dereferenceable(24)) unnamed_addr #3
This means that LLVM has no insight whatsoever into what is within the panic_fmt
, and therefore must be conservative wrt the optimisations involving the globals.
Consider for example, a fairly common scenario in embedded/wasm, where the implementation of panic_fmt
language item does not use any of this information from ARGS
(or uses only some of it). LLVM is unable to remove any of these constants from the binary unless very aggressive optimisation options are employed. Due to panic_fmt
wrapper, LLVM wouldn’t be able to remove the information even in the scenario where "all" the code, including the implementation of the panic_fmt
language item, is within the same crate.
In other words, this panic_fmt
wrapper is preventing optimisations even in areas where such optimisation would be otherwise possible.