Skip to content

Commit 572d3d9

Browse files
committed
Auto merge of #60584 - jonas-schievink:ice-panic-hook, r=oli-obk
Use `panic::set_hook` to print the ICE message This allows custom frontends and backends to override the hook with their own, for example to point people to a different issue tracker. ICE messages are printed in a slightly different order now. Nightly prints: ``` thread 'rustc' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:347:21 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports note: rustc 1.36.0-nightly (08bfe16 2019-05-02) running on x86_64-unknown-linux-gnu ``` After this PR, rustc prints: ``` thread 'rustc' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:347:21 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports note: rustc 1.36.0-dev running on x86_64-unknown-linux-gnu error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. ```
2 parents b35ebac + dab6813 commit 572d3d9

14 files changed

+116
-94
lines changed

Cargo.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -3014,7 +3014,6 @@ dependencies = [
30143014
"fmt_macros",
30153015
"graphviz",
30163016
"jobserver",
3017-
"lazy_static 1.3.0",
30183017
"log",
30193018
"measureme",
30203019
"num_cpus",
@@ -3370,6 +3369,7 @@ version = "0.0.0"
33703369
dependencies = [
33713370
"env_logger",
33723371
"graphviz",
3372+
"lazy_static 1.3.0",
33733373
"log",
33743374
"rustc",
33753375
"rustc_ast_borrowck",

src/librustc/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ bitflags = "1.0"
1515
fmt_macros = { path = "../libfmt_macros" }
1616
graphviz = { path = "../libgraphviz" }
1717
jobserver = "0.1"
18-
lazy_static = "1.0.0"
1918
num_cpus = "1.0"
2019
scoped-tls = "1.0"
2120
log = { version = "0.4", features = ["release_max_level_info", "std"] }

src/librustc/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767

6868
#[macro_use] extern crate bitflags;
6969
extern crate getopts;
70-
#[macro_use] extern crate lazy_static;
7170
#[macro_use] extern crate scoped_tls;
7271
#[cfg(windows)]
7372
extern crate libc;

src/librustc/util/common.rs

-37
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,13 @@ use rustc_data_structures::{fx::FxHashMap, sync::Lock};
55
use std::cell::{RefCell, Cell};
66
use std::fmt::Debug;
77
use std::hash::Hash;
8-
use std::panic;
9-
use std::env;
108
use std::time::{Duration, Instant};
119

1210
use std::sync::mpsc::{Sender};
1311
use syntax_pos::{SpanData};
1412
use syntax::symbol::{Symbol, sym};
1513
use rustc_macros::HashStable;
16-
use crate::ty::TyCtxt;
1714
use crate::dep_graph::{DepNode};
18-
use lazy_static;
1915
use crate::session::Session;
2016

2117
#[cfg(test)]
@@ -31,39 +27,6 @@ pub struct ErrorReported;
3127

3228
thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
3329

34-
lazy_static! {
35-
static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
36-
let hook = panic::take_hook();
37-
panic::set_hook(Box::new(panic_hook));
38-
hook
39-
};
40-
}
41-
42-
fn panic_hook(info: &panic::PanicInfo<'_>) {
43-
(*DEFAULT_HOOK)(info);
44-
45-
let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
46-
47-
if backtrace {
48-
TyCtxt::try_print_query_stack();
49-
}
50-
51-
#[cfg(windows)]
52-
unsafe {
53-
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
54-
extern "system" {
55-
fn DebugBreak();
56-
}
57-
// Trigger a debugger if we crashed during bootstrap.
58-
DebugBreak();
59-
}
60-
}
61-
}
62-
63-
pub fn install_panic_hook() {
64-
lazy_static::initialize(&DEFAULT_HOOK);
65-
}
66-
6730
/// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
6831
#[derive(Clone,Debug)]
6932
pub struct ProfQDumpParams {

src/librustc_driver/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ crate-type = ["dylib"]
1111

1212
[dependencies]
1313
graphviz = { path = "../libgraphviz" }
14+
lazy_static = "1.0"
1415
log = "0.4"
1516
env_logger = { version = "0.6", default-features = false }
1617
rustc = { path = "../librustc" }

src/librustc_driver/lib.rs

+94-49
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub extern crate getopts;
2020
extern crate libc;
2121
#[macro_use]
2222
extern crate log;
23+
#[macro_use]
24+
extern crate lazy_static;
2325

2426
pub extern crate rustc_plugin_impl as plugin;
2527

@@ -35,8 +37,8 @@ use rustc::session::{early_error, early_warn};
3537
use rustc::lint::Lint;
3638
use rustc::lint;
3739
use rustc::hir::def_id::LOCAL_CRATE;
38-
use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry};
39-
use rustc::util::common::{set_time_depth, time};
40+
use rustc::ty::TyCtxt;
41+
use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported};
4042
use rustc_metadata::locator;
4143
use rustc_metadata::cstore::CStore;
4244
use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -161,8 +163,6 @@ pub fn run_compiler(
161163
None => return Ok(()),
162164
};
163165

164-
install_panic_hook();
165-
166166
let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
167167

168168
let mut dummy_config = |sopts, cfg, diagnostic_output| {
@@ -1151,61 +1151,105 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
11511151
}
11521152
}
11531153

1154-
/// Runs a procedure which will detect panics in the compiler and print nicer
1155-
/// error messages rather than just failing the test.
1154+
/// Runs a closure and catches unwinds triggered by fatal errors.
11561155
///
1157-
/// The diagnostic emitter yielded to the procedure should be used for reporting
1158-
/// errors of the compiler.
1159-
pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
1156+
/// The compiler currently unwinds with a special sentinel value to abort
1157+
/// compilation on fatal errors. This function catches that sentinel and turns
1158+
/// the panic into a `Result` instead.
1159+
pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
11601160
catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
11611161
if value.is::<errors::FatalErrorMarker>() {
11621162
ErrorReported
11631163
} else {
1164-
// Thread panicked without emitting a fatal diagnostic
1165-
eprintln!("");
1166-
1167-
let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
1168-
errors::ColorConfig::Auto,
1169-
None,
1170-
false,
1171-
false,
1172-
None,
1173-
));
1174-
let handler = errors::Handler::with_emitter(true, None, emitter);
1175-
1176-
// a .span_bug or .bug call has already printed what
1177-
// it wants to print.
1178-
if !value.is::<errors::ExplicitBug>() {
1179-
handler.emit(&MultiSpan::new(),
1180-
"unexpected panic",
1181-
errors::Level::Bug);
1182-
}
1164+
panic::resume_unwind(value);
1165+
}
1166+
})
1167+
}
11831168

1184-
let mut xs: Vec<Cow<'static, str>> = vec![
1185-
"the compiler unexpectedly panicked. this is a bug.".into(),
1186-
format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(),
1187-
format!("rustc {} running on {}",
1188-
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
1189-
config::host_triple()).into(),
1190-
];
1169+
lazy_static! {
1170+
static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
1171+
let hook = panic::take_hook();
1172+
panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL)));
1173+
hook
1174+
};
1175+
}
11911176

1192-
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
1193-
xs.push(format!("compiler flags: {}", flags.join(" ")).into());
1177+
/// Prints the ICE message, including backtrace and query stack.
1178+
///
1179+
/// The message will point the user at `bug_report_url` to report the ICE.
1180+
///
1181+
/// When `install_ice_hook` is called, this function will be called as the panic
1182+
/// hook.
1183+
pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
1184+
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
1185+
(*DEFAULT_HOOK)(info);
1186+
1187+
// Separate the output with an empty line
1188+
eprintln!();
1189+
1190+
let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
1191+
errors::ColorConfig::Auto,
1192+
None,
1193+
false,
1194+
false,
1195+
None,
1196+
));
1197+
let handler = errors::Handler::with_emitter(true, None, emitter);
1198+
1199+
// a .span_bug or .bug call has already printed what
1200+
// it wants to print.
1201+
if !info.payload().is::<errors::ExplicitBug>() {
1202+
handler.emit(&MultiSpan::new(),
1203+
"unexpected panic",
1204+
errors::Level::Bug);
1205+
}
11941206

1195-
if excluded_cargo_defaults {
1196-
xs.push("some of the compiler flags provided by cargo are hidden".into());
1197-
}
1198-
}
1207+
let mut xs: Vec<Cow<'static, str>> = vec![
1208+
"the compiler unexpectedly panicked. this is a bug.".into(),
1209+
format!("we would appreciate a bug report: {}", bug_report_url).into(),
1210+
format!("rustc {} running on {}",
1211+
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
1212+
config::host_triple()).into(),
1213+
];
11991214

1200-
for note in &xs {
1201-
handler.emit(&MultiSpan::new(),
1202-
note,
1203-
errors::Level::Note);
1204-
}
1215+
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
1216+
xs.push(format!("compiler flags: {}", flags.join(" ")).into());
12051217

1206-
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
1218+
if excluded_cargo_defaults {
1219+
xs.push("some of the compiler flags provided by cargo are hidden".into());
12071220
}
1208-
})
1221+
}
1222+
1223+
for note in &xs {
1224+
handler.emit(&MultiSpan::new(),
1225+
note,
1226+
errors::Level::Note);
1227+
}
1228+
1229+
// If backtraces are enabled, also print the query stack
1230+
let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
1231+
1232+
if backtrace {
1233+
TyCtxt::try_print_query_stack();
1234+
}
1235+
1236+
#[cfg(windows)]
1237+
unsafe {
1238+
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
1239+
extern "system" {
1240+
fn DebugBreak();
1241+
}
1242+
// Trigger a debugger if we crashed during bootstrap
1243+
DebugBreak();
1244+
}
1245+
}
1246+
}
1247+
1248+
/// Installs a panic hook that will print the ICE message on unexpected panics.
1249+
///
1250+
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
1251+
pub fn install_ice_hook() {
1252+
lazy_static::initialize(&DEFAULT_HOOK);
12091253
}
12101254

12111255
/// This allows tools to enable rust logging without having to magically match rustc's
@@ -1218,7 +1262,8 @@ pub fn main() {
12181262
let start = Instant::now();
12191263
init_rustc_env_logger();
12201264
let mut callbacks = TimePassesCallbacks::default();
1221-
let result = report_ices_to_stderr_if_any(|| {
1265+
install_ice_hook();
1266+
let result = catch_fatal_errors(|| {
12221267
let args = env::args_os().enumerate()
12231268
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
12241269
early_error(ErrorOutputType::default(),

src/librustdoc/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ where R: 'static + Send,
473473
// First, parse the crate and extract all relevant information.
474474
info!("starting to run rustc");
475475

476-
let result = rustc_driver::report_ices_to_stderr_if_any(move || {
476+
let result = rustc_driver::catch_fatal_errors(move || {
477477
let crate_name = options.crate_name.clone();
478478
let crate_version = options.crate_version.clone();
479479
let (mut krate, renderinfo, renderopts) = core::run_core(options);

src/test/ui-fulldeps/compiler-calls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for TestCalls<'_> {
2424
fn main() {
2525
let mut count = 1;
2626
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
27-
rustc_driver::report_ices_to_stderr_if_any(|| {
27+
rustc_driver::catch_fatal_errors(|| {
2828
rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
2929
}).ok();
3030
assert_eq!(count, 2);

src/test/ui/proc-macro/invalid-punct-ident-1.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
// FIXME https://github.com/rust-lang/rust/issues/59998
44
// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
55
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
6+
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
7+
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
8+
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
9+
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
10+
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
611

712
#[macro_use]
813
extern crate invalid_punct_ident;

src/test/ui/proc-macro/invalid-punct-ident-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: proc macro panicked
2-
--> $DIR/invalid-punct-ident-1.rs:10:1
2+
--> $DIR/invalid-punct-ident-1.rs:15:1
33
|
44
LL | invalid_punct!();
55
| ^^^^^^^^^^^^^^^^^

src/test/ui/proc-macro/invalid-punct-ident-2.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
// FIXME https://github.com/rust-lang/rust/issues/59998
44
// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
55
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
6+
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
7+
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
8+
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
9+
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
10+
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
611

712
#[macro_use]
813
extern crate invalid_punct_ident;

src/test/ui/proc-macro/invalid-punct-ident-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: proc macro panicked
2-
--> $DIR/invalid-punct-ident-2.rs:10:1
2+
--> $DIR/invalid-punct-ident-2.rs:15:1
33
|
44
LL | invalid_ident!();
55
| ^^^^^^^^^^^^^^^^^

src/test/ui/proc-macro/invalid-punct-ident-3.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
// FIXME https://github.com/rust-lang/rust/issues/59998
44
// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> ""
55
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
6+
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
7+
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
8+
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
9+
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
10+
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
611

712
#[macro_use]
813
extern crate invalid_punct_ident;

src/test/ui/proc-macro/invalid-punct-ident-3.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: proc macro panicked
2-
--> $DIR/invalid-punct-ident-3.rs:10:1
2+
--> $DIR/invalid-punct-ident-3.rs:15:1
33
|
44
LL | invalid_raw_ident!();
55
| ^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)