diff --git a/Cargo.lock b/Cargo.lock index 4bea3af7f3bfa..e1e511a51eef0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -611,6 +611,16 @@ dependencies = [ "tracing-tree", ] +[[package]] +name = "chrono" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" +dependencies = [ + "num", + "time 0.1.43", +] + [[package]] name = "chrono" version = "0.4.19" @@ -625,6 +635,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ci_info" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a62f39080c8c83e899dff6abd46c4fac05c1cf8dafece96ad8238e79addbf8" +dependencies = [ + "envmnt", +] + [[package]] name = "clap" version = "3.2.20" @@ -1414,6 +1433,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "envmnt" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d73999a2b8871e74c8b8bc23759ee9f3d85011b24fafc91a4b3b5c8cc8185501" +dependencies = [ + "fsio", + "indexmap", +] + [[package]] name = "errno" version = "0.2.8" @@ -1619,6 +1648,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" +[[package]] +name = "fsio" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad0ce30be0cc441b325c5d705c8b613a0ca0d92b6a8953d41bd236dc09a36d0" +dependencies = [ + "dunce", +] + [[package]] name = "futf" version = "0.1.5" @@ -2535,7 +2573,7 @@ checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9" dependencies = [ "ammonia", "anyhow", - "chrono", + "chrono 0.4.19", "clap 3.2.20", "clap_complete", "elasticlunr-rs", @@ -2703,6 +2741,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-integer", + "num-iter", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.43" @@ -2713,6 +2762,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.12" @@ -3915,9 +3975,13 @@ dependencies = [ name = "rustc_driver" version = "0.0.0" dependencies = [ + "backtrace", + "chrono 0.2.25", + "ci_info", "libc", "rustc_ast", "rustc_ast_pretty", + "rustc_codegen_llvm", "rustc_codegen_ssa", "rustc_data_structures", "rustc_error_codes", @@ -3934,12 +3998,15 @@ dependencies = [ "rustc_middle", "rustc_parse", "rustc_plugin_impl", + "rustc_query_impl", + "rustc_query_system", "rustc_save_analysis", "rustc_session", "rustc_span", "rustc_target", "serde_json", "tracing", + "urlqstring", "winapi", ] @@ -5248,7 +5315,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3c02f6eb7e7b4100c272f685a9ccaccaab302324e8c7ec3e2ee72340fb29ff3" dependencies = [ - "chrono", + "chrono 0.4.19", "log", "nom", "serde", @@ -6054,6 +6121,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlqstring" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ef3473a06a065718d8ec7cd7acc6a35fc20f836dee7661ad3b64ea3cc2e0cc" + [[package]] name = "utf-8" version = "0.7.5" diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 246e82545c874..a220aa27b5be2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -23,7 +23,7 @@ extern crate tracing; use back::write::{create_informational_target_machine, create_target_machine}; use errors::FailParsingTargetMachineConfigToTargetMachine; -pub use llvm_util::target_features; +pub use llvm_util::{get_version, target_features}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 59e937777483e..a2d6b5f07e2fb 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -7,8 +7,12 @@ edition = "2021" crate-type = ["dylib"] [dependencies] -tracing = { version = "0.1.35" } +backtrace = "0.3.66" serde_json = "1.0.59" +chrono = "0.2" +ci_info = "0.14.9" +urlqstring = "*" +tracing = { version = "0.1.35" } rustc_log = { path = "../rustc_log" } rustc_middle = { path = "../rustc_middle" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -25,11 +29,14 @@ rustc_parse = { path = "../rustc_parse" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_save_analysis = { path = "../rustc_save_analysis" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_codegen_llvm = { path = "../rustc_codegen_llvm" } rustc_session = { path = "../rustc_session" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_interface = { path = "../rustc_interface" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } +rustc_query_system = { path = "../rustc_query_system" } +rustc_query_impl = { path = "../rustc_query_impl" } rustc_hir_analysis = { path = "../rustc_hir_analysis" } [target.'cfg(unix)'.dependencies] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 16f64235562f1..7e7997a84f840 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -8,6 +8,8 @@ #![feature(is_terminal)] #![feature(once_cell)] #![feature(decl_macro)] +#![feature(panic_info_message)] +#![feature(backtrace_frames)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] @@ -30,6 +32,8 @@ use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; use rustc_metadata::locator; +use rustc_query_impl::QueryCtxt; +use rustc_query_system::query::QueryContext; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; @@ -45,7 +49,6 @@ use rustc_target::json::ToJson; use std::borrow::Cow; use std::cmp::max; -use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, IsTerminal, Read, Write}; @@ -55,6 +58,7 @@ use std::process::{self, Command, Stdio}; use std::str; use std::sync::LazyLock; use std::time::Instant; +use std::{backtrace, env}; pub mod args; pub mod pretty; @@ -72,7 +76,7 @@ pub const EXIT_SUCCESS: i32 = 0; pub const EXIT_FAILURE: i32 = 1; const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ - ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; + ?labels=C-bug%2CI-ICE%2CT-compiler&template=ice.yaml"; const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"]; @@ -1181,6 +1185,100 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } +struct IceError; + +impl From for IceError { + fn from(_: std::io::Error) -> IceError { + IceError + } +} + +fn write_ice_to_disk(info: &panic::PanicInfo<'_>) -> Result<(String, String), IceError> { + let mut args = vec![]; + let capture = backtrace::Backtrace::force_capture(); + let now = chrono::UTC::now(); + let file_now = now.format("%Y-%m-%d_%H:%M:%S"); + let now = now.format("%Y-%m-%d %H:%M:%S"); + let mut path = std::env::current_dir()?; + path.push(format!("rustc-ice-context-{file_now}.txt")); + let mut file = std::fs::File::create(&path)?; + let (llvm_major, llvm_minor, llvm_dot) = rustc_codegen_llvm::get_version(); + let version = format!( + "rustc {}{} running on {} at {now} with LLVM {llvm_major}.{llvm_minor}.{llvm_dot}", + util::version_str!().unwrap_or("unknown_version"), + match (option_env!("CFG_VER_HASH"), option_env!("CFG_VER_DATE")) { + (Some(hash), Some(date)) => format!(" ({hash} - {date})"), + (Some(val), None) | (None, Some(val)) => format!(" ({val})"), + (None, None) => String::new(), + }, + config::host_triple(), + ); + + writeln!(file, "{}", version)?; + args.push(("version", version.as_str())); + + if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { + writeln!(file, "compiler flags:")?; + for flag in &flags { + writeln!(file, " {flag}")?; + } + if excluded_cargo_defaults { + writeln!(file, "some of the compiler flags provided by cargo are hidden")?; + } + } + writeln!(file, "")?; + match (info.message(), info.location()) { + (Some(message), Some(location)) => { + writeln!(file, "panicked at {location}:\n{message}")?; + } + (None, Some(location)) => { + writeln!(file, "panicked at {location}")?; + } + (Some(message), None) => { + writeln!(file, "panicked\n{message}")?; + } + (None, None) => { + writeln!(file, "panicked")?; + } + } + + writeln!(file, "")?; + let capture = format!("{capture}"); + writeln!(file, "{capture}")?; + + // Be careful relying on global state here: this code is called from + // a panic hook, which means that the global `Handler` may be in a weird + // state if it was responsible for triggering the panic. + // This the same as `interface::try_print_query_stack` but writing to file. + rustc_middle::ty::tls::with_context_opt(|icx| { + let Some(icx) = icx else { return Err(IceError); }; + let qcx = QueryCtxt::from_tcx(icx.tcx); + let query_map = qcx.try_collect_active_jobs(); + let mut i = 0; + let mut current_query = icx.query; + writeln!(file, "")?; + writeln!(file, "query stack during panic:")?; + while let Some(query) = current_query { + let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else { + break; + }; + writeln!( + file, + "#{} [{:?}] {}", + i, query_info.query.dep_kind, query_info.query.description + )?; + current_query = query_info.job.parent; + i += 1; + } + writeln!(file, "end of query stack")?; + Ok(()) + })?; + Ok(( + path.display().to_string(), + format!("{BUG_REPORT_URL}&{}", urlqstring::QueryParams::from(args).stringify()), + )) +} + static DEFAULT_HOOK: LazyLock) + Sync + Send + 'static>> = LazyLock::new(|| { let hook = panic::take_hook(); @@ -1196,9 +1294,18 @@ static DEFAULT_HOOK: LazyLock) + Sync + Send + } }; + let is_dev = util::version_str!().map_or_else( + || std::env::var("RUSTC_BACKTRACE_FORCE").as_deref() != Ok("1"), + |v| { + v.ends_with("-dev") + && std::env::var("RUSTC_BACKTRACE_FORCE").as_deref() != Ok("0") + }, + ); + let written_ice = + if !is_dev && !ci_info::is_ci() { write_ice_to_disk(info) } else { Err(IceError) }; // Invoke the default handler, which prints the actual panic message and optionally a backtrace // Don't do this for delayed bugs, which already emit their own more useful backtrace. - if !info.payload().is::() { + if !info.payload().is::() && written_ice.is_err() { (*DEFAULT_HOOK)(info); // Separate the output with an empty line @@ -1206,7 +1313,7 @@ static DEFAULT_HOOK: LazyLock) + Sync + Send + } // Print the ICE message - report_ice(info, BUG_REPORT_URL); + report_ice(info, BUG_REPORT_URL, written_ice.ok()); })); hook }); @@ -1217,7 +1324,11 @@ static DEFAULT_HOOK: LazyLock) + Sync + Send + /// /// 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) { +pub fn report_ice( + info: &panic::PanicInfo<'_>, + bug_report_url: &str, + reported_ice: Option<(String, String)>, +) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( @@ -1238,39 +1349,51 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { if !info.payload().is::() && !info.payload().is::() { - let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic"); + let mut d = rustc_errors::Diagnostic::new( + rustc_errors::Level::Bug, + "the compiler unexpectedly panicked. this is a bug.", + ); handler.emit_diagnostic(&mut d); } - 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 {}", - util::version_str!().unwrap_or("unknown_version"), - config::host_triple() - ) - .into(), - ]; - - if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { - xs.push(format!("compiler flags: {}", flags.join(" ")).into()); - - if excluded_cargo_defaults { - xs.push("some of the compiler flags provided by cargo are hidden".into()); + let xs: Vec> = if let Some((path, custom_url)) = &reported_ice { + let link = format!("\x1b]8;;{custom_url}\x07{bug_report_url}\x1b]8;;\x07"); + vec![ + format!("all necessary context about this bug was written to `{path}`").into(), + format!("we would appreciate a bug report with this context at {link}").into(), + ] + } else { + let mut xs = vec![ + format!("we would appreciate a bug report at <{bug_report_url}>").into(), + format!( + "rustc {} running on {}", + util::version_str!().unwrap_or("unknown_version"), + config::host_triple() + ) + .into(), + ]; + if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() { + xs.push(format!("compiler flags: {}", flags.join(" ")).into()); + + if excluded_cargo_defaults { + xs.push("some of the compiler flags provided by cargo are hidden".into()); + } } - } + xs + }; for note in &xs { handler.note_without_error(note.as_ref()); } - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); + if reported_ice.is_none() { + // If backtraces are enabled, also print the query stack + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - let num_frames = if backtrace { None } else { Some(2) }; + let num_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(&handler, num_frames); + interface::try_print_query_stack(&handler, num_frames); + } #[cfg(windows)] unsafe { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 29501d2d3b6be..3cc9ad30593d0 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -96,6 +96,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "arrayvec", "atty", "autocfg", + "backtrace", "bitflags", "block-buffer", "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown. diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs index 86ce42631b432..203a59430ffd4 100644 --- a/tests/ui/chalkify/bugs/async.rs +++ b/tests/ui/chalkify/bugs/async.rs @@ -6,7 +6,8 @@ // failure-status:101 // normalize-stderr-test "note: .*" -> "" // normalize-stderr-test "thread 'rustc' .*" -> "" -// normalize-stderr-test " .*\n" -> "" +// normalize-stderr-test " ? ?\d\d?\d?:.*\n" -> "" +// normalize-stderr-test " .*\n" -> "" // normalize-stderr-test "DefId([^)]*)" -> "..." fn main() -> () {} diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr index 7e2466dece438..dc296c645b54e 100644 --- a/tests/ui/chalkify/bugs/async.stderr +++ b/tests/ui/chalkify/bugs/async.stderr @@ -1,17 +1,37 @@ -error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future -LL |LL | |LL | | } - - -error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:14:29: 16:2] as Future>::Output` cannot be known at compilation time -LL |LL | |LL | | } - - -error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future +error[E0277]: `[async fn body@$DIR/async.rs:15:29: --> $DIR/async.rs:15:29 + | +LL | async fn foo(x: u32) -> u32 { + | _____________________________- +LL | | x +LL | | } + | | ^ + | | | + | |_`[async fn body@$DIR/async.rs:15:29: | required by a bound introduced by this call + | + = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:15:29: = + + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + +error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:15:29: --> $DIR/async.rs:15:29 + | +LL | async fn foo(x: u32) -> u32 { + | _____________________________^ +LL | | x +LL | | } + | |_^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:15:29: + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + +error[E0277]: `[async fn body@$DIR/async.rs:15:29: --> $DIR/async.rs:15:25 + | LL | async fn foo(x: u32) -> u32 { + | = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:15:29: = -error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:14:29: 16:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)` +error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:15:29: --> $DIR/async.rs:15:25 + | LL | async fn foo(x: u32) -> u32 { - + | stack backtrace: @@ -21,8 +41,6 @@ stack backtrace: - - query stack during panic: #0 [typeck] type-checking `foo` #1 [thir_body] building THIR for `foo` diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr index 6c4aa35679d5b..581630118df5a 100644 --- a/tests/ui/impl-trait/issues/issue-86800.stderr +++ b/tests/ui/impl-trait/issues/issue-86800.stderr @@ -9,9 +9,7 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future