about summary refs log tree commit diff
path: root/compiler/rustc_errors/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src')
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs32
-rw-r--r--compiler/rustc_errors/src/json.rs1
-rw-r--r--compiler/rustc_errors/src/timings.rs47
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(&section) {
+            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(&section) {
+                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.