diff --git a/Cargo.lock b/Cargo.lock index ae641d6ae32b1..91ff6cd1006ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2844,7 +2844,6 @@ dependencies = [ "fmt_macros", "graphviz", "jobserver", - "lazy_static 1.3.0", "log", "measureme", "num_cpus", @@ -3204,6 +3203,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/Cargo.toml b/src/librustc/Cargo.toml index 0222a3dde7ab9..4ab982f6f91f5 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -15,7 +15,6 @@ bitflags = "1.0" fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" -lazy_static = "1.0.0" num_cpus = "1.0" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 368f5bb64fe6c..c2befabcb69b3 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,7 +68,6 @@ #[macro_use] extern crate bitflags; extern crate getopts; -#[macro_use] extern crate lazy_static; #[macro_use] extern crate scoped_tls; #[cfg(windows)] extern crate libc; diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 7118d05204c3b..2475b93d95f32 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -5,17 +5,13 @@ use rustc_data_structures::{fx::FxHashMap, sync::Lock}; use std::cell::{RefCell, Cell}; use std::fmt::Debug; use std::hash::Hash; -use std::panic; -use std::env; use std::time::{Duration, Instant}; use std::sync::mpsc::{Sender}; use syntax_pos::{SpanData}; use syntax::symbol::{Symbol, sym}; use rustc_macros::HashStable; -use crate::ty::TyCtxt; use crate::dep_graph::{DepNode}; -use lazy_static; use crate::session::Session; #[cfg(test)] @@ -31,39 +27,6 @@ pub struct ErrorReported; thread_local!(static TIME_DEPTH: Cell = Cell::new(0)); -lazy_static! { - static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { - let hook = panic::take_hook(); - panic::set_hook(Box::new(panic_hook)); - hook - }; -} - -fn panic_hook(info: &panic::PanicInfo<'_>) { - (*DEFAULT_HOOK)(info); - - let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - - if backtrace { - TyCtxt::try_print_query_stack(); - } - - #[cfg(windows)] - unsafe { - if env::var("RUSTC_BREAK_ON_ICE").is_ok() { - extern "system" { - fn DebugBreak(); - } - // Trigger a debugger if we crashed during bootstrap. - DebugBreak(); - } - } -} - -pub fn install_panic_hook() { - lazy_static::initialize(&DEFAULT_HOOK); -} - /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`. #[derive(Clone,Debug)] pub struct ProfQDumpParams { 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..fe1ed10884a4d 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; @@ -36,8 +38,8 @@ use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; use rustc::hir::def_id::LOCAL_CRATE; -use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry}; -use rustc::util::common::{set_time_depth, time}; +use rustc::ty::TyCtxt; +use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported}; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -162,8 +164,6 @@ pub fn run_compiler( None => return Ok(()), }; - install_panic_hook(); - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); let mut dummy_config = |sopts, cfg, diagnostic_output| { @@ -1143,61 +1143,105 @@ 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 unwinds 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(|info| report_ice(info, BUG_REPORT_URL))); + hook + }; +} - if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { - xs.push(format!("compiler flags: {}", flags.join(" ")).into()); +/// Prints the ICE message, including backtrace and query stack. +/// +/// The message will point the user at `bug_report_url` to report the ICE. +/// +/// When `install_ice_hook` is called, this function will be called as the panic +/// hook. +pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { + // Invoke the default handler, which prints the actual panic message and optionally a backtrace + (*DEFAULT_HOOK)(info); + + // Separate the output with an empty line + 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); + } + + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + + if backtrace { + TyCtxt::try_print_query_stack(); + } + + #[cfg(windows)] + unsafe { + if env::var("RUSTC_BREAK_ON_ICE").is_ok() { + extern "system" { + fn DebugBreak(); + } + // Trigger a debugger if we crashed during bootstrap + DebugBreak(); + } + } +} + +/// Installs a panic hook that will print the ICE message on unexpected panics. +/// +/// A custom rustc driver can skip calling this to set up a custom ICE hook. +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 +1254,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); diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index c9881ad2c38af..94a4b403d5a3f 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -3,6 +3,11 @@ // FIXME https://github.com/rust-lang/rust/issues/59998 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index 40333a3f4c211..107f5fb515b1c 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:10:1 + --> $DIR/invalid-punct-ident-1.rs:15:1 | LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs index 15e2286a65049..778b7eeecd7a9 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs @@ -3,6 +3,11 @@ // FIXME https://github.com/rust-lang/rust/issues/59998 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index ec97e265c3fcd..f1b9ecc6cbfe4 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-2.rs:10:1 + --> $DIR/invalid-punct-ident-2.rs:15:1 | LL | invalid_ident!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs index 629bbaa9e3888..f68ee3de7f456 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs @@ -3,6 +3,11 @@ // FIXME https://github.com/rust-lang/rust/issues/59998 // normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index a5e5ded65333a..6044b9887401e 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-3.rs:10:1 + --> $DIR/invalid-punct-ident-3.rs:15:1 | LL | invalid_raw_ident!(); | ^^^^^^^^^^^^^^^^^^^^^