diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f872fd47546..6af7a23f66d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -139,6 +139,19 @@ pub mod target_features { const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; +const ICE_REPORT_COMPILER_FLAGS: &'static [&'static str] = &[ + "Z", + "C", + "crate-type", +]; +const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &'static [&'static str] = &[ + "metadata", + "extra-filename", +]; +const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &'static [&'static str] = &[ + "incremental", +]; + pub fn abort_on_err(result: Result, sess: &Session) -> T { match result { Err(CompileIncomplete::Errored(ErrorReported)) => { @@ -1431,6 +1444,57 @@ pub fn in_rustc_thread(f: F) -> Result> thread.unwrap().join() } +/// Get a list of extra command-line flags provided by the user, as strings. +/// +/// This function is used during ICEs to show more information useful for +/// debugging, since some ICEs only happens with non-default compiler flags +/// (and the users don't always report them). +fn extra_compiler_flags() -> Option<(Vec, bool)> { + let mut args = Vec::new(); + for arg in env::args_os() { + args.push(arg.to_string_lossy().to_string()); + } + + let matches = if let Some(matches) = handle_options(&args) { + matches + } else { + return None; + }; + + let mut result = Vec::new(); + let mut excluded_cargo_defaults = false; + for flag in ICE_REPORT_COMPILER_FLAGS { + let prefix = if flag.len() == 1 { "-" } else { "--" }; + + for content in &matches.opt_strs(flag) { + // Split always returns the first element + let name = if let Some(first) = content.split('=').next() { + first + } else { + &content + }; + + let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { + name + } else { + content + }; + + if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) { + result.push(format!("{}{} {}", prefix, flag, content)); + } else { + excluded_cargo_defaults = true; + } + } + } + + if result.len() > 0 { + Some((result, excluded_cargo_defaults)) + } else { + None + } +} + /// Run a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// @@ -1462,11 +1526,22 @@ pub fn monitor(f: F) { errors::Level::Bug); } - let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(), - format!("we would appreciate a bug report: {}", BUG_REPORT_URL), - format!("rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple())]; + let mut xs = vec![ + "the compiler unexpectedly panicked. this is a bug.".to_string(), + format!("we would appreciate a bug report: {}", BUG_REPORT_URL), + format!("rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple()), + ]; + + if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { + xs.push(format!("compiler flags: {}", flags.join(" "))); + + if excluded_cargo_defaults { + xs.push("some of the compiler flags provided by cargo are hidden".to_string()); + } + } + for note in &xs { handler.emit(&MultiSpan::new(), ¬e,