From a8926a5e9c5becdf18acede5f7e114cd5f8655b6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 6 May 2019 13:47:58 +0200 Subject: [PATCH] Use `panic::set_hook` to print the ICE message --- Cargo.lock | 1 + src/librustc_driver/Cargo.toml | 1 + src/librustc_driver/lib.rs | 109 +++++++++++++++---------- src/librustdoc/lib.rs | 2 +- src/test/ui-fulldeps/compiler-calls.rs | 2 +- 5 files changed, 68 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae641d6ae32b1..179bf59388a29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3204,6 +3204,7 @@ version = "0.0.0" dependencies = [ "env_logger 0.5.13", "graphviz", + "lazy_static 1.3.0", "log", "rustc", "rustc_ast_borrowck", diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index b030517e28ec2..8bd61c25843aa 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } +lazy_static = "1.0" log = "0.4" env_logger = { version = "0.5", default-features = false } rustc = { path = "../librustc" } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e3ea92dc8ab38..5b7ac14ba3585 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -21,6 +21,8 @@ pub extern crate getopts; extern crate libc; #[macro_use] extern crate log; +#[macro_use] +extern crate lazy_static; pub extern crate rustc_plugin_impl as plugin; @@ -1143,61 +1145,77 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { } } -/// Runs a procedure which will detect panics in the compiler and print nicer -/// error messages rather than just failing the test. +/// Runs a closure and catches unwinds triggered by fatal errors. /// -/// The diagnostic emitter yielded to the procedure should be used for reporting -/// errors of the compiler. -pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result { +/// The compiler currently panics with a special sentinel value to abort +/// compilation on fatal errors. This function catches that sentinel and turns +/// the panic into a `Result` instead. +pub fn catch_fatal_errors R, R>(f: F) -> Result { catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::() { ErrorReported } else { - // Thread panicked without emitting a fatal diagnostic - eprintln!(""); - - let emitter = Box::new(errors::emitter::EmitterWriter::stderr( - errors::ColorConfig::Auto, - None, - false, - false, - None, - )); - let handler = errors::Handler::with_emitter(true, None, emitter); - - // a .span_bug or .bug call has already printed what - // it wants to print. - if !value.is::() { - handler.emit(&MultiSpan::new(), - "unexpected panic", - errors::Level::Bug); - } + panic::resume_unwind(value); + } + }) +} - let mut xs: Vec> = vec![ - "the compiler unexpectedly panicked. this is a bug.".into(), - format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(), - format!("rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple()).into(), - ]; +lazy_static! { + static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { + let hook = panic::take_hook(); + panic::set_hook(Box::new(report_ice)); + hook + }; +} - if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { - xs.push(format!("compiler flags: {}", flags.join(" ")).into()); +pub fn report_ice(info: &panic::PanicInfo<'_>) { + (*DEFAULT_HOOK)(info); + + // Thread panicked without emitting a fatal diagnostic + eprintln!(); + + let emitter = Box::new(errors::emitter::EmitterWriter::stderr( + errors::ColorConfig::Auto, + None, + false, + false, + None, + )); + let handler = errors::Handler::with_emitter(true, None, emitter); + + // a .span_bug or .bug call has already printed what + // it wants to print. + if !info.payload().is::() { + handler.emit(&MultiSpan::new(), + "unexpected panic", + errors::Level::Bug); + } - if excluded_cargo_defaults { - xs.push("some of the compiler flags provided by cargo are hidden".into()); - } - } + let mut xs: Vec> = vec![ + "the compiler unexpectedly panicked. this is a bug.".into(), + format!("we would appreciate a bug report: {}", BUG_REPORT_URL).into(), + format!("rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple()).into(), + ]; - for note in &xs { - handler.emit(&MultiSpan::new(), - note, - errors::Level::Note); - } + if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { + xs.push(format!("compiler flags: {}", flags.join(" ")).into()); - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); + if excluded_cargo_defaults { + xs.push("some of the compiler flags provided by cargo are hidden".into()); } - }) + } + + for note in &xs { + handler.emit(&MultiSpan::new(), + note, + errors::Level::Note); + } +} + +pub fn install_ice_hook() { + lazy_static::initialize(&DEFAULT_HOOK); } /// This allows tools to enable rust logging without having to magically match rustc's @@ -1210,7 +1228,8 @@ pub fn main() { let start = Instant::now(); init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); - let result = report_ices_to_stderr_if_any(|| { + install_ice_hook(); + let result = catch_fatal_errors(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { early_error(ErrorOutputType::default(), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 87dac0f226896..0b366da29d37e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -453,7 +453,7 @@ where R: 'static + Send, // First, parse the crate and extract all relevant information. info!("starting to run rustc"); - let result = rustc_driver::report_ices_to_stderr_if_any(move || { + let result = rustc_driver::catch_fatal_errors(move || { let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); let (mut krate, renderinfo, renderopts) = core::run_core(options); diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index ea24f5809d52a..bd9113c7079ea 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for TestCalls<'_> { fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; - rustc_driver::report_ices_to_stderr_if_any(|| { + rustc_driver::catch_fatal_errors(|| { rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); }).ok(); assert_eq!(count, 2);