Add -Zerror-metrics=PATH to save diagnostic metadata to disk

This commit is contained in:
Jane Losare-Lusby 2024-07-31 11:47:07 -07:00
parent 2b78d92096
commit 5212c75907
4 changed files with 103 additions and 23 deletions

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ Session.vim
*.iml *.iml
.vscode .vscode
.project .project
.vim/
.favorites.json .favorites.json
.settings/ .settings/
.vs/ .vs/

View File

@ -51,7 +51,8 @@ use rustc_metadata::creader::MetadataLoader;
use rustc_metadata::locator; use rustc_metadata::locator;
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_session::config::{ use rustc_session::config::{
nightly_options, ErrorOutputType, Input, OutFileName, OutputType, CG_OPTIONS, Z_OPTIONS, nightly_options, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, CG_OPTIONS,
Z_OPTIONS,
}; };
use rustc_session::getopts::{self, Matches}; use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId}; use rustc_session::lint::{Lint, LintId};
@ -301,6 +302,8 @@ fn run_compiler(
let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) }; let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) };
let sopts = config::build_session_options(&mut default_early_dcx, &matches); let sopts = config::build_session_options(&mut default_early_dcx, &matches);
// fully initialize ice path static once unstable options are available as context
let ice_file = ice_path_with_config(Some(&sopts.unstable_opts)).clone();
if let Some(ref code) = matches.opt_str("explain") { if let Some(ref code) = matches.opt_str("explain") {
handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color); handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color);
@ -315,7 +318,7 @@ fn run_compiler(
input: Input::File(PathBuf::new()), input: Input::File(PathBuf::new()),
output_file: ofile, output_file: ofile,
output_dir: odir, output_dir: odir,
ice_file: ice_path().clone(), ice_file,
file_loader, file_loader,
locale_resources: DEFAULT_LOCALE_RESOURCES, locale_resources: DEFAULT_LOCALE_RESOURCES,
lint_caps: Default::default(), lint_caps: Default::default(),
@ -1306,25 +1309,43 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new(); static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
// This function should only be called from the ICE hook.
//
// The intended behavior is that `run_compiler` will invoke `ice_path_with_config` early in the
// initialization process to properly initialize the ICE_PATH static based on parsed CLI flags.
//
// Subsequent calls to either function will then return the proper ICE path as configured by
// the environment and cli flags
fn ice_path() -> &'static Option<PathBuf> { fn ice_path() -> &'static Option<PathBuf> {
ice_path_with_config(None)
}
fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<PathBuf> {
if ICE_PATH.get().is_some() && config.is_some() && cfg!(debug_assertions) {
tracing::warn!(
"ICE_PATH has already been initialized -- files may be emitted at unintended paths"
)
}
ICE_PATH.get_or_init(|| { ICE_PATH.get_or_init(|| {
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
return None; return None;
} }
if let Some(s) = std::env::var_os("RUST_BACKTRACE")
&& s == "0"
{
return None;
}
let mut path = match std::env::var_os("RUSTC_ICE") { let mut path = match std::env::var_os("RUSTC_ICE") {
Some(s) => { Some(s) => {
if s == "0" { if s == "0" {
// Explicitly opting out of writing ICEs to disk. // Explicitly opting out of writing ICEs to disk.
return None; return None;
} }
if let Some(unstable_opts) = config && unstable_opts.metrics_dir.is_some() {
tracing::warn!("ignoring -Zerror-metrics in favor of RUSTC_ICE for destination of ICE report files");
}
PathBuf::from(s) PathBuf::from(s)
} }
None => std::env::current_dir().unwrap_or_default(), None => config
.and_then(|unstable_opts| unstable_opts.metrics_dir.to_owned())
.or_else(|| std::env::current_dir().ok())
.unwrap_or_default(),
}; };
let now: OffsetDateTime = SystemTime::now().into(); let now: OffsetDateTime = SystemTime::now().into();
let file_now = now let file_now = now

View File

@ -1827,6 +1827,8 @@ options! {
the same values as the target option of the same name"), the same values as the target option of the same name"),
meta_stats: bool = (false, parse_bool, [UNTRACKED], meta_stats: bool = (false, parse_bool, [UNTRACKED],
"gather metadata statistics (default: no)"), "gather metadata statistics (default: no)"),
metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"stores metrics about the errors being emitted by rustc to disk"),
mir_emit_retag: bool = (false, parse_bool, [TRACKED], mir_emit_retag: bool = (false, parse_bool, [TRACKED],
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"), (default: no)"),

View File

@ -4,6 +4,10 @@
// or full. // or full.
// - Check that disabling ICE logging results in zero files created. // - Check that disabling ICE logging results in zero files created.
// - Check that the ICE files contain some of the expected strings. // - Check that the ICE files contain some of the expected strings.
// - exercise the -Zmetrics-dir nightly flag
// - verify what happens when both the nightly flag and env variable are set
// - test the RUST_BACKTRACE=0 behavior against the file creation
// See https://github.com/rust-lang/rust/pull/108714 // See https://github.com/rust-lang/rust/pull/108714
use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_files}; use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_files};
@ -11,8 +15,8 @@ use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_
fn main() { fn main() {
rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
let default = get_text_from_ice(".").lines().count(); let default = get_text_from_ice(".").lines().count();
clear_ice_files();
clear_ice_files();
rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
let ice_text = get_text_from_ice(cwd()); let ice_text = get_text_from_ice(cwd());
let default_set = ice_text.lines().count(); let default_set = ice_text.lines().count();
@ -25,7 +29,28 @@ fn main() {
ice_files.first().and_then(|f| f.file_name()).and_then(|n| n.to_str()).unwrap(); ice_files.first().and_then(|f| f.file_name()).and_then(|n| n.to_str()).unwrap();
// Ensure that the ICE dump path doesn't contain `:`, because they cause problems on Windows. // Ensure that the ICE dump path doesn't contain `:`, because they cause problems on Windows.
assert!(!ice_file_name.contains(":"), "{ice_file_name}"); assert!(!ice_file_name.contains(":"), "{ice_file_name}");
assert_eq!(default, default_set);
assert!(default > 0);
// Some of the expected strings in an ICE file should appear.
assert!(content.contains("thread 'rustc' panicked at"));
assert!(content.contains("stack backtrace:"));
test_backtrace_short(default);
test_backtrace_full(default);
test_backtrace_disabled(default);
clear_ice_files();
// The ICE dump is explicitly disabled. Therefore, this should produce no files.
rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
let ice_files = shallow_find_files(cwd(), |path| {
has_prefix(path, "rustc-ice") && has_extension(path, "txt")
});
assert!(ice_files.is_empty()); // There should be 0 ICE files.
metrics_dir(default);
}
fn test_backtrace_short(baseline: usize) {
clear_ice_files(); clear_ice_files();
rustc() rustc()
.env("RUSTC_ICE", cwd()) .env("RUSTC_ICE", cwd())
@ -34,6 +59,11 @@ fn main() {
.arg("-Ztreat-err-as-bug=1") .arg("-Ztreat-err-as-bug=1")
.run_fail(); .run_fail();
let short = get_text_from_ice(cwd()).lines().count(); let short = get_text_from_ice(cwd()).lines().count();
// backtrace length in dump shouldn't be changed by RUST_BACKTRACE
assert_eq!(short, baseline);
}
fn test_backtrace_full(baseline: usize) {
clear_ice_files(); clear_ice_files();
rustc() rustc()
.env("RUSTC_ICE", cwd()) .env("RUSTC_ICE", cwd())
@ -42,23 +72,49 @@ fn main() {
.arg("-Ztreat-err-as-bug=1") .arg("-Ztreat-err-as-bug=1")
.run_fail(); .run_fail();
let full = get_text_from_ice(cwd()).lines().count(); let full = get_text_from_ice(cwd()).lines().count();
// backtrace length in dump shouldn't be changed by RUST_BACKTRACE
assert_eq!(full, baseline);
}
fn test_backtrace_disabled(baseline: usize) {
clear_ice_files(); clear_ice_files();
rustc()
.env("RUSTC_ICE", cwd())
.input("lib.rs")
.env("RUST_BACKTRACE", "0")
.arg("-Ztreat-err-as-bug=1")
.run_fail();
let disabled = get_text_from_ice(cwd()).lines().count();
// backtrace length in dump shouldn't be changed by RUST_BACKTRACE
assert_eq!(disabled, baseline);
}
// The ICE dump is explicitly disabled. Therefore, this should produce no files. fn metrics_dir(baseline: usize) {
rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail(); test_flag_only(baseline);
let ice_files = shallow_find_files(cwd(), |path| { test_flag_and_env(baseline);
has_prefix(path, "rustc-ice") && has_extension(path, "txt") }
});
assert!(ice_files.is_empty()); // There should be 0 ICE files.
// The line count should not change. fn test_flag_only(baseline: usize) {
assert_eq!(short, default_set); clear_ice_files();
assert_eq!(short, default); let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
assert_eq!(full, default_set); rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").arg(metrics_arg).run_fail();
assert!(default > 0); let output = get_text_from_ice(cwd()).lines().count();
// Some of the expected strings in an ICE file should appear. assert_eq!(output, baseline);
assert!(content.contains("thread 'rustc' panicked at")); }
assert!(content.contains("stack backtrace:"));
fn test_flag_and_env(baseline: usize) {
clear_ice_files();
let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
let real_dir = cwd().join("actually_put_ice_here");
rfs::create_dir(real_dir.clone());
rustc()
.input("lib.rs")
.env("RUSTC_ICE", real_dir.clone())
.arg("-Ztreat-err-as-bug=1")
.arg(metrics_arg)
.run_fail();
let output = get_text_from_ice(real_dir).lines().count();
assert_eq!(output, baseline);
} }
fn clear_ice_files() { fn clear_ice_files() {