about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2024-03-01 09:20:08 +1100
committerNicholas Nethercote <n.nethercote@gmail.com>2024-03-01 10:18:54 +1100
commit44f0043e82fb2d3156434797f2e638cb61b07ce9 (patch)
treedfb4d8eba146d966e4e688f50fb6748561ac4ab4
parent721c741756a023f13064a232280a72fceba0b813 (diff)
downloadrust-44f0043e82fb2d3156434797f2e638cb61b07ce9.tar.gz
rust-44f0043e82fb2d3156434797f2e638cb61b07ce9.zip
Handle stashing of delayed bugs.
By just emitting them immediately, because it does happen in practice,
when errors are downgraded to delayed bugs.

We already had one case in `lint.rs` where we handled this at the
callsite. This commit changes things so it's handled within
`stash_diagnostic` instead, because #121812 identified a second case,
and it's possible there are more.

Fixes #121812.
-rw-r--r--compiler/rustc_errors/src/lib.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs12
-rw-r--r--tests/ui/typeck/invalid-stashed-level-issue-121812.rs8
-rw-r--r--tests/ui/typeck/invalid-stashed-level-issue-121812.stderr9
4 files changed, 44 insertions, 21 deletions
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index c03d65f9454..6b1ccbc5f7c 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -712,6 +712,7 @@ impl DiagCtxt {
     /// Stashes a diagnostic for possible later improvement in a different,
     /// later stage of the compiler. Possible actions depend on the diagnostic
     /// level:
+    /// - Level::Bug, Level:Fatal: not allowed, will trigger a panic.
     /// - Level::Error: immediately counted as an error that has occurred, because it
     ///   is guaranteed to be emitted eventually. Can be later accessed with the
     ///   provided `span` and `key` through
@@ -719,26 +720,39 @@ impl DiagCtxt {
     ///   [`DiagCtxt::try_steal_replace_and_emit_err`]. These do not allow
     ///   cancellation or downgrading of the error. Returns
     ///   `Some(ErrorGuaranteed)`.
+    /// - Level::DelayedBug: this does happen occasionally with errors that are
+    ///   downgraded to delayed bugs. It is not stashed, but immediately
+    ///   emitted as a delayed bug. This is because stashing it would cause it
+    ///   to be counted by `err_count` which we don't want. It doesn't matter
+    ///   that we cannot steal and improve it later, because it's not a
+    ///   user-facing error. Returns `Some(ErrorGuaranteed)` as is normal for
+    ///   delayed bugs.
     /// - Level::Warning and lower (i.e. !is_error()): can be accessed with the
     ///   provided `span` and `key` through [`DiagCtxt::steal_non_err()`]. This
     ///   allows cancelling and downgrading of the diagnostic. Returns `None`.
-    /// - Others: not allowed, will trigger a panic.
     pub fn stash_diagnostic(
         &self,
         span: Span,
         key: StashKey,
         diag: DiagInner,
     ) -> Option<ErrorGuaranteed> {
-        let guar = if diag.level() == Level::Error {
-            // This `unchecked_error_guaranteed` is valid. It is where the
-            // `ErrorGuaranteed` for stashed errors originates. See
-            // `DiagCtxtInner::drop`.
-            #[allow(deprecated)]
-            Some(ErrorGuaranteed::unchecked_error_guaranteed())
-        } else if !diag.is_error() {
-            None
-        } else {
-            self.span_bug(span, format!("invalid level in `stash_diagnostic`: {}", diag.level));
+        let guar = match diag.level {
+            Bug | Fatal => {
+                self.span_bug(
+                    span,
+                    format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
+                );
+            }
+            Error => {
+                // This `unchecked_error_guaranteed` is valid. It is where the
+                // `ErrorGuaranteed` for stashed errors originates. See
+                // `DiagCtxtInner::drop`.
+                #[allow(deprecated)]
+                Some(ErrorGuaranteed::unchecked_error_guaranteed())
+            }
+            DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag),
+            ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
+            | Expect(_) => None,
         };
 
         // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index 227254b4cc8..fb5f3426cea 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -1,5 +1,5 @@
 use rustc_ast::TraitObjectSyntax;
-use rustc_errors::{codes::*, Diag, EmissionGuarantee, Level, StashKey};
+use rustc_errors::{codes::*, Diag, EmissionGuarantee, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
@@ -237,15 +237,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
                 // check if the impl trait that we are considering is a impl of a local trait
                 self.maybe_lint_blanket_trait_impl(self_ty, &mut diag);
-                match diag.level() {
-                    Level::Error => {
-                        diag.stash(self_ty.span, StashKey::TraitMissingMethod);
-                    }
-                    Level::DelayedBug => {
-                        diag.emit();
-                    }
-                    _ => unreachable!(),
-                }
+                diag.stash(self_ty.span, StashKey::TraitMissingMethod);
             } else {
                 let msg = "trait objects without an explicit `dyn` are deprecated";
                 tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
diff --git a/tests/ui/typeck/invalid-stashed-level-issue-121812.rs b/tests/ui/typeck/invalid-stashed-level-issue-121812.rs
new file mode 100644
index 00000000000..4b61f4f2c63
--- /dev/null
+++ b/tests/ui/typeck/invalid-stashed-level-issue-121812.rs
@@ -0,0 +1,8 @@
+union U {
+    a: u16,
+    b: [u8; 3],
+}
+
+fn main() {
+    _ = U { b: [()] }; //~ ERROR mismatched types
+}
diff --git a/tests/ui/typeck/invalid-stashed-level-issue-121812.stderr b/tests/ui/typeck/invalid-stashed-level-issue-121812.stderr
new file mode 100644
index 00000000000..9465935c8c2
--- /dev/null
+++ b/tests/ui/typeck/invalid-stashed-level-issue-121812.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/invalid-stashed-level-issue-121812.rs:7:17
+   |
+LL |     _ = U { b: [()] };
+   |                 ^^ expected `u8`, found `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.