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        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}