summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_driver_impl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_driver_impl
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_driver_impl')
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml11
-rw-r--r--compiler/rustc_driver_impl/messages.ftl20
-rw-r--r--compiler/rustc_driver_impl/src/args.rs5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs246
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs14
-rw-r--r--compiler/rustc_driver_impl/src/print.rs20
6 files changed, 191 insertions, 125 deletions
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 73a1f79a0..67352c55c 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -18,6 +18,7 @@ rustc_const_eval = { path = "../rustc_const_eval" }
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_expand = { path = "../rustc_expand" }
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_infer = { path = "../rustc_infer" }
rustc_mir_build = { path = "../rustc_mir_build" }
@@ -50,12 +51,13 @@ rustc_interface = { path = "../rustc_interface" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_mir_transform = { path = "../rustc_mir_transform" }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(windows)'.dependencies.windows]
-version = "0.46.0"
+version = "0.48.0"
features = [
"Win32_System_Diagnostics_Debug",
]
@@ -63,5 +65,8 @@ features = [
[features]
llvm = ['rustc_interface/llvm']
max_level_info = ['rustc_log/max_level_info']
-rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
- 'rustc_middle/rustc_use_parallel_compiler']
+rustc_use_parallel_compiler = [
+ 'rustc_data_structures/rustc_use_parallel_compiler',
+ 'rustc_interface/rustc_use_parallel_compiler',
+ 'rustc_middle/rustc_use_parallel_compiler'
+]
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index f19b1ff64..22b4ec6b0 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -1,19 +1,19 @@
-driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
-
-driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
+driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_ice_flags = compiler flags: {$flags}
+driver_impl_ice_version = rustc {$version} running on {$triple}
driver_impl_rlink_empty_version_number = The input does not contain version number
driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
+driver_impl_rlink_no_a_file = rlink must be a file
+
driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
-driver_impl_rlink_no_a_file = rlink must be a file
+driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
-driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
+driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
-driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
-driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
-driver_impl_ice_version = rustc {$version} running on {$triple}
-driver_impl_ice_flags = compiler flags: {$flags}
-driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index 42c97cc6a..eb92ccc17 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
}
}
+/// **Note:** This function doesn't interpret argument 0 in any special way.
+/// If this function is intended to be used with command line arguments,
+/// `argv[0]` must be removed prior to calling it manually.
pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
let mut args = Vec::new();
for arg in at_args {
@@ -25,7 +28,7 @@ pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
Ok(arg) => args.extend(arg),
Err(err) => rustc_session::early_error(
rustc_session::config::ErrorOutputType::default(),
- &format!("Failed to load argument file: {err}"),
+ format!("Failed to load argument file: {err}"),
),
}
}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b9f0e756e..0b5d73709 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -25,13 +25,13 @@ use rustc_data_structures::profiling::{
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{
- DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl,
+ DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl,
};
use rustc_feature::find_gated_cfg;
+use rustc_fluent_macro::fluent_messages;
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
-use rustc_macros::fluent_messages;
use rustc_metadata::locator;
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
@@ -55,11 +55,19 @@ use std::panic::{self, catch_unwind};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
use std::str;
-use std::sync::LazyLock;
+use std::sync::OnceLock;
use std::time::Instant;
+// This import blocks the use of panicking `print` and `println` in all the code
+// below. Please use `safe_print` and `safe_println` to avoid ICE when
+// encountering an I/O error during print.
+#[allow(unused_imports)]
+use std::{compile_error as print, compile_error as println};
+
pub mod args;
pub mod pretty;
+#[macro_use]
+mod print;
mod session_diagnostics;
use crate::session_diagnostics::{
@@ -91,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
rustc_middle::DEFAULT_LOCALE_RESOURCE,
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
+ rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
rustc_passes::DEFAULT_LOCALE_RESOURCE,
@@ -111,7 +120,7 @@ pub const EXIT_SUCCESS: i32 = 0;
/// Exit status code used for compilation failures and invalid flags.
pub const EXIT_FAILURE: i32 = 1;
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
@@ -241,12 +250,25 @@ fn run_compiler(
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
) -> interface::Result<()> {
+ // Throw away the first argument, the name of the binary.
+ // In case of at_args being empty, as might be the case by
+ // passing empty argument array to execve under some platforms,
+ // just use an empty slice.
+ //
+ // This situation was possible before due to arg_expand_all being
+ // called before removing the argument, enabling a crash by calling
+ // the compiler with @empty_file as argv[0] and no more arguments.
+ let at_args = at_args.get(1..).unwrap_or_default();
+
let args = args::arg_expand_all(at_args);
let Some(matches) = handle_options(&args) else { return Ok(()) };
let sopts = config::build_session_options(&matches);
+ // Set parallel mode before thread pool creation, which will create `Lock`s.
+ interface::set_thread_safe_mode(&sopts.unstable_opts);
+
if let Some(ref code) = matches.opt_str("explain") {
handle_explain(diagnostics_registry(), code, sopts.error_format);
return Ok(());
@@ -310,7 +332,7 @@ fn run_compiler(
1 => panic!("make_input should have provided valid inputs"),
_ => early_error(
config.opts.error_format,
- &format!(
+ format!(
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
matches.free[0], matches.free[1],
),
@@ -511,11 +533,11 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
if io::stdout().is_terminal() {
show_content_with_pager(&text);
} else {
- print!("{text}");
+ safe_print!("{text}");
}
}
Err(InvalidErrorCode) => {
- early_error(output, &format!("{code} is not a valid error code"));
+ early_error(output, format!("{code} is not a valid error code"));
}
}
}
@@ -547,7 +569,7 @@ fn show_content_with_pager(content: &str) {
// If pager fails for whatever reason, we should still print the content
// to standard output
if fallback_to_println {
- print!("{content}");
+ safe_print!("{content}");
}
}
@@ -560,7 +582,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
let rlink_data = fs::read(file).unwrap_or_else(|err| {
sess.emit_fatal(RlinkUnableToRead { err });
});
- let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) {
+ let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) {
Ok(codegen) => codegen,
Err(err) => {
match err {
@@ -574,10 +596,10 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
rlink_version,
})
}
- CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => {
+ CodegenErrors::RustcVersionMismatch { rustc_version } => {
sess.emit_fatal(RLinkRustcVersionMismatch {
rustc_version,
- current_version,
+ current_version: sess.cfg_version,
})
}
};
@@ -601,7 +623,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
let path = &(*ifile);
let mut v = Vec::new();
locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
- println!("{}", String::from_utf8(v).unwrap());
+ safe_println!("{}", String::from_utf8(v).unwrap());
}
Input::Str { .. } => {
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
@@ -642,12 +664,12 @@ fn print_crate_info(
TargetList => {
let mut targets = rustc_target::spec::TARGETS.to_vec();
targets.sort_unstable();
- println!("{}", targets.join("\n"));
+ safe_println!("{}", targets.join("\n"));
}
- Sysroot => println!("{}", sess.sysroot.display()),
- TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+ Sysroot => safe_println!("{}", sess.sysroot.display()),
+ TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()),
TargetSpec => {
- println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+ safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
}
AllTargetSpecs => {
let mut targets = BTreeMap::new();
@@ -656,7 +678,7 @@ fn print_crate_info(
let target = Target::expect_builtin(&triple);
targets.insert(name, target.to_json());
}
- println!("{}", serde_json::to_string_pretty(&targets).unwrap());
+ safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap());
}
FileNames | CrateName => {
let Some(attrs) = attrs.as_ref() else {
@@ -666,14 +688,14 @@ fn print_crate_info(
let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
let id = rustc_session::output::find_crate_name(sess, attrs);
if *req == PrintRequest::CrateName {
- println!("{id}");
+ safe_println!("{id}");
continue;
}
let crate_types = collect_crate_types(sess, attrs);
for &style in &crate_types {
let fname =
rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
- println!("{}", fname.file_name().unwrap().to_string_lossy());
+ safe_println!("{}", fname.file_name().unwrap().to_string_lossy());
}
}
Cfg => {
@@ -707,13 +729,13 @@ fn print_crate_info(
cfgs.sort();
for cfg in cfgs {
- println!("{cfg}");
+ safe_println!("{cfg}");
}
}
CallingConventions => {
let mut calling_conventions = rustc_target::spec::abi::all_names();
calling_conventions.sort_unstable();
- println!("{}", calling_conventions.join("\n"));
+ safe_println!("{}", calling_conventions.join("\n"));
}
RelocationModels
| CodeModels
@@ -733,10 +755,26 @@ fn print_crate_info(
let stable = sess.target.options.supported_split_debuginfo.contains(split);
let unstable_ok = sess.unstable_options();
if stable || unstable_ok {
- println!("{split}");
+ safe_println!("{split}");
}
}
}
+ DeploymentTarget => {
+ use rustc_target::spec::current_apple_deployment_target;
+
+ if sess.target.is_like_osx {
+ safe_println!(
+ "deployment_target={}",
+ current_apple_deployment_target(&sess.target)
+ .expect("unknown Apple target OS")
+ )
+ } else {
+ early_error(
+ ErrorOutputType::default(),
+ "only Apple targets currently support deployment version info",
+ )
+ }
+ }
}
}
Compilation::Stop
@@ -770,14 +808,14 @@ pub fn version_at_macro_invocation(
) {
let verbose = matches.opt_present("verbose");
- println!("{binary} {version}");
+ safe_println!("{binary} {version}");
if verbose {
- println!("binary: {binary}");
- println!("commit-hash: {commit_hash}");
- println!("commit-date: {commit_date}");
- println!("host: {}", config::host_triple());
- println!("release: {release}");
+ safe_println!("binary: {binary}");
+ safe_println!("commit-hash: {commit_hash}");
+ safe_println!("commit-date: {commit_date}");
+ safe_println!("host: {}", config::host_triple());
+ safe_println!("release: {release}");
let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -807,7 +845,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
} else {
""
};
- println!(
+ safe_println!(
"{options}{at_path}\nAdditional help:
-C help Print codegen options
-W help \
@@ -820,7 +858,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
}
fn print_wall_help() {
- println!(
+ safe_println!(
"
The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
default. Use `rustc -W help` to see all available lints. It's more common to put
@@ -832,7 +870,7 @@ the command line flag directly.
/// Write to stdout lint command options, together with a list of all available lints
pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
- println!(
+ safe_println!(
"
Available lint options:
-W <foo> Warn about <foo>
@@ -877,21 +915,21 @@ Available lint options:
s
};
- println!("Lint checks provided by rustc:\n");
+ safe_println!("Lint checks provided by rustc:\n");
let print_lints = |lints: Vec<&Lint>| {
- println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
- println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
+ safe_println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
+ safe_println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
for lint in lints {
let name = lint.name_lower().replace('_', "-");
- println!(
+ safe_println!(
" {} {:7.7} {}",
padded(&name),
lint.default_level(sess.edition()).as_str(),
lint.desc
);
}
- println!("\n");
+ safe_println!("\n");
};
print_lints(builtin);
@@ -912,14 +950,14 @@ Available lint options:
s
};
- println!("Lint groups provided by rustc:\n");
+ safe_println!("Lint groups provided by rustc:\n");
let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
- println!(" {} sub-lints", padded("name"));
- println!(" {} ---------", padded("----"));
+ safe_println!(" {} sub-lints", padded("name"));
+ safe_println!(" {} ---------", padded("----"));
if all_warnings {
- println!(" {} all lints that are set to issue warnings", padded("warnings"));
+ safe_println!(" {} all lints that are set to issue warnings", padded("warnings"));
}
for (name, to) in lints {
@@ -929,26 +967,26 @@ Available lint options:
.map(|x| x.to_string().replace('_', "-"))
.collect::<Vec<String>>()
.join(", ");
- println!(" {} {}", padded(&name), desc);
+ safe_println!(" {} {}", padded(&name), desc);
}
- println!("\n");
+ safe_println!("\n");
};
print_lint_groups(builtin_groups, true);
match (loaded_plugins, plugin.len(), plugin_groups.len()) {
(false, 0, _) | (false, _, 0) => {
- println!("Lint tools like Clippy can provide additional lints and lint groups.");
+ safe_println!("Lint tools like Clippy can provide additional lints and lint groups.");
}
(false, ..) => panic!("didn't load lint plugins but got them anyway!"),
- (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
+ (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."),
(true, l, g) => {
if l > 0 {
- println!("Lint checks provided by plugins loaded by this crate:\n");
+ safe_println!("Lint checks provided by plugins loaded by this crate:\n");
print_lints(plugin);
}
if g > 0 {
- println!("Lint groups provided by plugins loaded by this crate:\n");
+ safe_println!("Lint groups provided by plugins loaded by this crate:\n");
print_lint_groups(plugin_groups, false);
}
}
@@ -996,12 +1034,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
}
fn describe_debug_flags() {
- println!("\nAvailable options:\n");
+ safe_println!("\nAvailable options:\n");
print_flag_list("-Z", config::Z_OPTIONS);
}
fn describe_codegen_flags() {
- println!("\nAvailable codegen options:\n");
+ safe_println!("\nAvailable codegen options:\n");
print_flag_list("-C", config::CG_OPTIONS);
}
@@ -1012,7 +1050,7 @@ fn print_flag_list<T>(
let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
for &(name, _, _, desc) in flag_list {
- println!(
+ safe_println!(
" {} {:>width$}=val -- {}",
cmdline_opt,
name.replace('_', "-"),
@@ -1046,9 +1084,6 @@ fn print_flag_list<T>(
/// So with all that in mind, the comments below have some more detail about the
/// contortions done here to get things to work out correctly.
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
- // Throw away the first argument, the name of the binary
- let args = &args[1..];
-
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
@@ -1074,7 +1109,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
.map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
_ => None,
};
- early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
+ early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string()));
});
// For all options we just parsed, we check a few aspects:
@@ -1170,6 +1205,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
if value.is::<rustc_errors::FatalErrorMarker>() {
+ #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
} else {
panic::resume_unwind(value);
@@ -1187,35 +1223,59 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
}
}
-static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
- LazyLock::new(|| {
- let hook = panic::take_hook();
- panic::set_hook(Box::new(|info| {
- // If the error was caused by a broken pipe then this is not a bug.
- // Write the error and return immediately. See #98700.
- #[cfg(windows)]
- if let Some(msg) = info.payload().downcast_ref::<String>() {
- if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
- {
- early_error_no_abort(ErrorOutputType::default(), &msg);
- return;
- }
- };
+/// Stores the default panic hook, from before [`install_ice_hook`] was called.
+static DEFAULT_HOOK: OnceLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+ OnceLock::new();
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// The hook is intended to be useable even by external tools. You can pass a custom
+/// `bug_report_url`, or report arbitrary info in `extra_info`. Note that `extra_info` is called in
+/// a context where *the thread is currently panicking*, so it must not panic or the process will
+/// abort.
+///
+/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
+/// extra_info.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
+ // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
+ // full backtraces. When a compiler ICE happens, we want to gather
+ // as much information as possible to present in the issue opened
+ // by the user. Compiler developers and other rustc users can
+ // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+ // (e.g. `RUST_BACKTRACE=1`)
+ if std::env::var("RUST_BACKTRACE").is_err() {
+ std::env::set_var("RUST_BACKTRACE", "full");
+ }
- // 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::<rustc_errors::DelayedBugPanic>() {
- (*DEFAULT_HOOK)(info);
+ let default_hook = DEFAULT_HOOK.get_or_init(panic::take_hook);
- // Separate the output with an empty line
- eprintln!();
+ panic::set_hook(Box::new(move |info| {
+ // If the error was caused by a broken pipe then this is not a bug.
+ // Write the error and return immediately. See #98700.
+ #[cfg(windows)]
+ if let Some(msg) = info.payload().downcast_ref::<String>() {
+ if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
+ // the error code is already going to be reported when the panic unwinds up the stack
+ let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str());
+ return;
}
+ };
- // Print the ICE message
- report_ice(info, BUG_REPORT_URL);
- }));
- hook
- });
+ // 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::<rustc_errors::DelayedBugPanic>() {
+ (*default_hook)(info);
+
+ // Separate the output with an empty line
+ eprintln!();
+ }
+
+ // Print the ICE message
+ report_ice(info, bug_report_url, extra_info);
+ }));
+}
/// Prints the ICE message, including query stack, but without backtrace.
///
@@ -1223,7 +1283,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + 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, extra_info: fn(&Handler)) {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
@@ -1262,12 +1322,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
// If backtraces are enabled, also print the query stack
- let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
+ let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0");
let num_frames = if backtrace { None } else { Some(2) };
interface::try_print_query_stack(&handler, num_frames);
+ // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
+ // printed all the relevant info.
+ extra_info(&handler);
+
#[cfg(windows)]
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
// Trigger a debugger if we crashed during bootstrap
@@ -1275,22 +1339,6 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
}
-/// 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() {
- // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
- // full backtraces. When a compiler ICE happens, we want to gather
- // as much information as possible to present in the issue opened
- // by the user. Compiler developers and other rustc users can
- // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
- // (e.g. `RUST_BACKTRACE=1`)
- if std::env::var("RUST_BACKTRACE").is_err() {
- std::env::set_var("RUST_BACKTRACE", "full");
- }
- LazyLock::force(&DEFAULT_HOOK);
-}
-
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
@@ -1302,7 +1350,7 @@ pub fn init_rustc_env_logger() {
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
if let Err(error) = rustc_log::init_env_logger(env) {
- early_error(ErrorOutputType::default(), &error.to_string());
+ early_error(ErrorOutputType::default(), error.to_string());
}
}
@@ -1361,7 +1409,7 @@ pub fn main() -> ! {
init_rustc_env_logger();
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
- install_ice_hook();
+ install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
let exit_code = catch_with_exit_code(|| {
let args = env::args_os()
.enumerate()
@@ -1369,7 +1417,7 @@ pub fn main() -> ! {
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
- &format!("argument {i} is not valid Unicode: {arg:?}"),
+ format!("argument {i} is not valid Unicode: {arg:?}"),
)
})
})
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 446c6832c..ee64b18d3 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -488,12 +488,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR tree");
for did in tcx.hir().body_owners() {
- let _ = writeln!(
- out,
- "{:?}:\n{}\n",
- did,
- tcx.thir_tree(ty::WithOptConstParam::unknown(did))
- );
+ let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
}
out
}
@@ -503,12 +498,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR flat");
for did in tcx.hir().body_owners() {
- let _ = writeln!(
- out,
- "{:?}:\n{}\n",
- did,
- tcx.thir_flat(ty::WithOptConstParam::unknown(did))
- );
+ let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
}
out
}
diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs
new file mode 100644
index 000000000..70de55320
--- /dev/null
+++ b/compiler/rustc_driver_impl/src/print.rs
@@ -0,0 +1,20 @@
+use std::fmt;
+use std::io::{self, Write as _};
+
+macro_rules! safe_print {
+ ($($arg:tt)*) => {{
+ $crate::print::print(std::format_args!($($arg)*));
+ }};
+}
+
+macro_rules! safe_println {
+ ($($arg:tt)*) => {
+ safe_print!("{}\n", std::format_args!($($arg)*))
+ };
+}
+
+pub(crate) fn print(args: fmt::Arguments<'_>) {
+ if let Err(_) = io::stdout().write_fmt(args) {
+ rustc_errors::FatalError.raise();
+ }
+}