diff options
Diffstat (limited to 'compiler/rustc_errors/src')
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 32 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/json.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/timings.rs | 47 |
3 files changed, 76 insertions, 4 deletions
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a11f81b55bb..8da7cdd9358 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -289,6 +289,9 @@ pub struct DiagInner { pub suggestions: Suggestions, pub args: DiagArgMap, + // This is used to store args and restore them after a subdiagnostic is rendered. + pub reserved_args: DiagArgMap, + /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of /// `span` if there is one. Otherwise, it is `DUMMY_SP`. @@ -319,6 +322,7 @@ impl DiagInner { children: vec![], suggestions: Suggestions::Enabled(vec![]), args: Default::default(), + reserved_args: Default::default(), sort_span: DUMMY_SP, is_lint: None, long_ty_path: None, @@ -390,7 +394,27 @@ impl DiagInner { } pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) { - self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path)); + let name = name.into(); + let value = arg.into_diag_arg(&mut self.long_ty_path); + // This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg. + debug_assert!( + !self.args.contains_key(&name) || self.args.get(&name) == Some(&value), + "arg {} already exists", + name + ); + self.args.insert(name, value); + } + + pub fn remove_arg(&mut self, name: &str) { + self.args.swap_remove(name); + } + + pub fn store_args(&mut self) { + self.reserved_args = self.args.clone(); + } + + pub fn restore_args(&mut self) { + self.args = std::mem::take(&mut self.reserved_args); } /// Fields used for Hash, and PartialEq trait. @@ -1423,6 +1447,12 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.downgrade_to_delayed_bug(); self.emit() } + + pub fn remove_arg(&mut self, name: &str) { + if let Some(diag) = self.diag.as_mut() { + diag.remove_arg(name); + } + } } /// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 6d600f896a0..4348610be0a 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -129,6 +129,7 @@ impl Emitter for JsonEmitter { }; let name = match record.section { TimingSection::Linking => "link", + TimingSection::Codegen => "codegen", }; let data = SectionTimestamp { name, event, timestamp: record.timestamp }; let result = self.emit(EmitTyped::SectionTiming(data)); diff --git a/compiler/rustc_errors/src/timings.rs b/compiler/rustc_errors/src/timings.rs index 27fc9df8d79..0d82f3e8db8 100644 --- a/compiler/rustc_errors/src/timings.rs +++ b/compiler/rustc_errors/src/timings.rs @@ -1,10 +1,15 @@ use std::time::Instant; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lock; + use crate::DiagCtxtHandle; /// A high-level section of the compilation process. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum TimingSection { + /// Time spent doing codegen. + Codegen, /// Time spent linking. Linking, } @@ -36,23 +41,59 @@ pub struct TimingSectionHandler { /// Time when the compilation session started. /// If `None`, timing is disabled. origin: Option<Instant>, + /// Sanity check to ensure that we open and close sections correctly. + opened_sections: Lock<FxHashSet<TimingSection>>, } impl TimingSectionHandler { pub fn new(enabled: bool) -> Self { let origin = if enabled { Some(Instant::now()) } else { None }; - Self { origin } + Self { origin, opened_sections: Lock::new(FxHashSet::default()) } } /// Returns a RAII guard that will immediately emit a start the provided section, and then emit /// its end when it is dropped. - pub fn start_section<'a>( + pub fn section_guard<'a>( &self, diag_ctxt: DiagCtxtHandle<'a>, section: TimingSection, ) -> TimingSectionGuard<'a> { + if self.is_enabled() && self.opened_sections.borrow().contains(§ion) { + diag_ctxt + .bug(format!("Section `{section:?}` was started again before it was finished")); + } + TimingSectionGuard::create(diag_ctxt, section, self.origin) } + + /// Start the provided section. + pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { + if let Some(origin) = self.origin { + let mut opened = self.opened_sections.borrow_mut(); + if !opened.insert(section) { + diag_ctxt + .bug(format!("Section `{section:?}` was started again before it was finished")); + } + + diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section)); + } + } + + /// End the provided section. + pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { + if let Some(origin) = self.origin { + let mut opened = self.opened_sections.borrow_mut(); + if !opened.remove(§ion) { + diag_ctxt.bug(format!("Section `{section:?}` was ended before being started")); + } + + diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section)); + } + } + + fn is_enabled(&self) -> bool { + self.origin.is_some() + } } /// RAII wrapper for starting and ending section timings. |
