about summary refs log tree commit diff
path: root/compiler/rustc_errors/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src/lib.rs')
-rw-r--r--compiler/rustc_errors/src/lib.rs104
1 files changed, 88 insertions, 16 deletions
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 6555b93ac0b..68abdd0bad1 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![feature(adt_const_params)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![feature(result_option_inspect)]
@@ -459,6 +460,7 @@ struct HandlerInner {
 pub enum StashKey {
     ItemNoType,
     UnderscoreForArrayLengths,
+    EarlySyntaxWarning,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
@@ -626,19 +628,13 @@ impl Handler {
     /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
     pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
         let mut inner = self.inner.borrow_mut();
-        // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
-        // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
-        // See the PR for a discussion.
-        inner.stashed_diagnostics.insert((span, key), diag);
+        inner.stash((span, key), diag);
     }
 
     /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
     pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
-        self.inner
-            .borrow_mut()
-            .stashed_diagnostics
-            .remove(&(span, key))
-            .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+        let mut inner = self.inner.borrow_mut();
+        inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
     }
 
     /// Emit all stashed diagnostics.
@@ -646,6 +642,15 @@ impl Handler {
         self.inner.borrow_mut().emit_stashed_diagnostics()
     }
 
+    /// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`.
+    #[rustc_lint_diagnostics]
+    pub fn struct_diagnostic<G: EmissionGuarantee>(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, G> {
+        G::make_diagnostic_builder(self, msg)
+    }
+
     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
     ///
     /// Attempting to `.emit()` the builder will only emit if either:
@@ -1106,13 +1111,31 @@ impl HandlerInner {
 
     /// Emit all stashed diagnostics.
     fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
+        let has_errors = self.has_errors();
         let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
         let mut reported = None;
         for mut diag in diags {
+            // Decrement the count tracking the stash; emitting will increment it.
             if diag.is_error() {
-                reported = Some(ErrorGuaranteed(()));
+                if matches!(diag.level, Level::Error { lint: true }) {
+                    self.lint_err_count -= 1;
+                } else {
+                    self.err_count -= 1;
+                }
+            } else {
+                if diag.is_force_warn() {
+                    self.warn_count -= 1;
+                } else {
+                    // Unless they're forced, don't flush stashed warnings when
+                    // there are errors, to avoid causing warning overload. The
+                    // stash would've been stolen already if it were important.
+                    if has_errors {
+                        continue;
+                    }
+                }
             }
-            self.emit_diagnostic(&mut diag);
+            let reported_this = self.emit_diagnostic(&mut diag);
+            reported = reported.or(reported_this);
         }
         reported
     }
@@ -1226,9 +1249,13 @@ impl HandlerInner {
     }
 
     fn treat_err_as_bug(&self) -> bool {
-        self.flags
-            .treat_err_as_bug
-            .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
+        self.flags.treat_err_as_bug.map_or(false, |c| {
+            self.err_count()
+                + self.lint_err_count
+                + self.delayed_span_bugs.len()
+                + self.delayed_good_path_bugs.len()
+                >= c.get()
+        })
     }
 
     fn print_error_count(&mut self, registry: &Registry) {
@@ -1302,9 +1329,47 @@ impl HandlerInner {
         }
     }
 
+    fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
+        // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
+        // yet; that happens when we actually emit the diagnostic.
+        if diagnostic.is_error() {
+            if matches!(diagnostic.level, Level::Error { lint: true }) {
+                self.lint_err_count += 1;
+            } else {
+                self.err_count += 1;
+            }
+        } else {
+            // Warnings are only automatically flushed if they're forced.
+            if diagnostic.is_force_warn() {
+                self.warn_count += 1;
+            }
+        }
+
+        // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
+        // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
+        // See the PR for a discussion.
+        self.stashed_diagnostics.insert(key, diagnostic);
+    }
+
+    fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
+        let diagnostic = self.stashed_diagnostics.remove(&key)?;
+        if diagnostic.is_error() {
+            if matches!(diagnostic.level, Level::Error { lint: true }) {
+                self.lint_err_count -= 1;
+            } else {
+                self.err_count -= 1;
+            }
+        } else {
+            if diagnostic.is_force_warn() {
+                self.warn_count -= 1;
+            }
+        }
+        Some(diagnostic)
+    }
+
     #[inline]
     fn err_count(&self) -> usize {
-        self.err_count + self.stashed_diagnostics.len()
+        self.err_count
     }
 
     fn has_errors(&self) -> bool {
@@ -1346,7 +1411,14 @@ impl HandlerInner {
         // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
         // incrementing `err_count` by one, so we need to +1 the comparing.
         // FIXME: Would be nice to increment err_count in a more coherent way.
-        if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
+        if self.flags.treat_err_as_bug.map_or(false, |c| {
+            self.err_count()
+                + self.lint_err_count
+                + self.delayed_span_bugs.len()
+                + self.delayed_good_path_bugs.len()
+                + 1
+                >= c.get()
+        }) {
             // FIXME: don't abort here if report_delayed_bugs is off
             self.span_bug(sp, msg);
         }