diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 546159c9d13dd..e36e231418ed3 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -30,6 +30,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; use std::borrow::Cow; use std::cmp::{max, min, Reverse}; use std::error::Report; +use std::fs::File; use std::io::prelude::*; use std::io::{self, IsTerminal}; use std::iter; @@ -538,7 +539,7 @@ impl Emitter for EmitterWriter { &primary_span, &children, suggestions, - self.track_diagnostics.then_some(&diag.emitted_at), + &diag.emitted_at, ); } @@ -637,6 +638,7 @@ pub struct EmitterWriter { macro_backtrace: bool, track_diagnostics: bool, + metrics: Option<File>, terminal_url: TerminalUrl, } @@ -666,6 +668,7 @@ impl EmitterWriter { diagnostic_width: None, macro_backtrace: false, track_diagnostics: false, + metrics: None, terminal_url: TerminalUrl::No, } } @@ -2079,8 +2082,9 @@ impl EmitterWriter { span: &MultiSpan, children: &[SubDiagnostic], suggestions: &[CodeSuggestion], - emitted_at: Option<&DiagnosticLocation>, + emitted_at_location: &DiagnosticLocation, ) { + let emitted_at = self.track_diagnostics.then_some(emitted_at_location); let max_line_num_len = if self.ui_testing { ANONYMIZED_LINE_NUM.len() } else { @@ -2088,6 +2092,17 @@ impl EmitterWriter { num_decimal_digits(n) }; + if let Some(ref mut file) = &mut self.metrics { + let _ = writeln!( + file, + "{:?},{:?},{},{}", + code, + emitted_at_location, + children.len(), + suggestions.len() + ); + } + match self.emit_messages_default_inner( span, messages, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e436591fdd99b..4457c218b1c38 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -514,7 +514,7 @@ fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnosti pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> = AtomicRef::new(&(default_track_diagnostic as _)); -#[derive(Copy, Clone, Default)] +#[derive(Clone, Default)] pub struct DiagCtxtFlags { /// If false, warning-level lints are suppressed. /// (rustc: see `--allow warnings` and `--cap-lints`) @@ -535,6 +535,8 @@ pub struct DiagCtxtFlags { pub deduplicate_diagnostics: bool, /// Track where errors are created. Enabled with `-Ztrack-diagnostics`. pub track_diagnostics: bool, + /// Track whether error metrics are stored. Enabled with `-Zerror-metrics=path`. + pub metrics: Option<PathBuf>, } impl Drop for DiagCtxtInner { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e1640d7fca93d..9612c876208e4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1165,6 +1165,7 @@ impl UnstableOptions { macro_backtrace: self.macro_backtrace, deduplicate_diagnostics: self.deduplicate_diagnostics, track_diagnostics: self.track_diagnostics, + metrics: self.error_metrics.clone(), } } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8274fd05bc057..386e2f3e935bb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1621,6 +1621,8 @@ options! { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), + error_metrics: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], + "stores metrics about the errors being emitted by rustc to disk"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9ee7625e5bfeb..6d084d4fcad64 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -41,6 +41,7 @@ use std::any::Any; use std::cell::{self, RefCell}; use std::env; use std::fmt; +use std::fs::File; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -1009,6 +1010,12 @@ fn default_emitter( ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { + let metrics = sopts.unstable_opts.error_metrics.as_ref().and_then(|path| { + let mut path = path.clone(); + std::fs::create_dir_all(&path).ok()?; + path.push(format!("error_metrics_{}", std::process::id())); + File::options().create(true).append(true).open(&path).ok() + }); let emitter = EmitterWriter::stderr(color_config, fallback_bundle) .fluent_bundle(bundle) .sm(Some(source_map)) @@ -1018,6 +1025,7 @@ fn default_emitter( .macro_backtrace(macro_backtrace) .track_diagnostics(track_diagnostics) .terminal_url(terminal_url) + .metrics(metrics) .ignored_directories_in_source_blocks( sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(), );