solar_interface/panic_hook.rs
1//! Functions for installing a custom panic hook.
2
3use crate::diagnostics::{DiagCtxt, ExplicitBug, FatalAbort};
4use std::panic::PanicHookInfo;
5
6const BUG_REPORT_URL: &str =
7 "https://github.com/paradigmxyz/solar/issues/new/?labels=C-bug%2C+I-ICE&template=ice.yml";
8
9/// Install the compiler's default panic hook.
10pub fn install() {
11 if std::env::var_os("RUST_BACKTRACE").is_none() {
12 unsafe { std::env::set_var("RUST_BACKTRACE", "1") };
13 }
14
15 update_hook(|default_hook, info| {
16 if info.payload().is::<FatalAbort>() {
17 std::process::exit(1);
18 }
19
20 // Lock stderr to prevent interleaving of concurrent panics.
21 let _guard = std::io::stderr().lock();
22
23 default_hook(info);
24
25 // Separate the output with an empty line.
26 eprintln!();
27
28 panic_hook(info);
29 });
30}
31
32fn panic_hook(info: &PanicHookInfo<'_>) {
33 let dcx = DiagCtxt::new_early();
34
35 // An explicit `bug()` call has already printed what it wants to print.
36 if !info.payload().is::<ExplicitBug>() {
37 dcx.err("the compiler unexpectedly panicked; this is a bug.").emit();
38 }
39
40 dcx.note(format!("we would appreciate a bug report: {BUG_REPORT_URL}")).emit();
41}
42
43#[cfg(feature = "nightly")]
44use std::panic::update_hook;
45
46/// Polyfill for [`std::panic::update_hook`].
47#[cfg(not(feature = "nightly"))]
48fn update_hook<F>(hook_fn: F)
49where
50 F: Fn(&(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), &PanicHookInfo<'_>)
51 + Sync
52 + Send
53 + 'static,
54{
55 let default_hook = std::panic::take_hook();
56 std::panic::set_hook(Box::new(move |info| hook_fn(&default_hook, info)));
57}