From 721c741756a023f13064a232280a72fceba0b813 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Mar 2024 09:54:00 +1100 Subject: [PATCH 1/2] Remove unnecessary `Level::` qualifiers. We have `use Level::*;` in this file. --- compiler/rustc_errors/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0a533833e64bd..c03d65f9454ac 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -780,11 +780,11 @@ impl DiagCtxt { let err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key); err.map(|(err, guar)| { // The use of `::` is safe because level is `Level::Error`. - assert_eq!(err.level, Level::Error); + assert_eq!(err.level, Error); assert!(guar.is_some()); let mut err = Diag::::new_diagnostic(self, err); modify_err(&mut err); - assert_eq!(err.level, Level::Error); + assert_eq!(err.level, Error); err.emit() }) } @@ -803,7 +803,7 @@ impl DiagCtxt { let old_err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key); match old_err { Some((old_err, guar)) => { - assert_eq!(old_err.level, Level::Error); + assert_eq!(old_err.level, Error); assert!(guar.is_some()); // Because `old_err` has already been counted, it can only be // safely cancelled because the `new_err` supplants it. @@ -1367,7 +1367,7 @@ impl DiagCtxtInner { } if diagnostic.has_future_breakage() { - // Future breakages aren't emitted if they're Level::Allow, + // Future breakages aren't emitted if they're `Level::Allow`, // but they still need to be constructed and stashed below, // so they'll trigger the must_produce_diag check. self.suppressed_expected_diag = true; @@ -1453,7 +1453,7 @@ impl DiagCtxtInner { diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); if already_emitted { let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`"; - diagnostic.sub(Level::Note, msg, MultiSpan::new()); + diagnostic.sub(Note, msg, MultiSpan::new()); } if is_error { @@ -1623,7 +1623,7 @@ impl DiagCtxtInner { bug.arg("level", bug.level); let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level; let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call - bug.sub(Level::Note, msg, bug.span.primary_span().unwrap().into()); + bug.sub(Note, msg, bug.span.primary_span().unwrap().into()); } bug.level = Bug; @@ -1671,7 +1671,7 @@ impl DelayedDiagInner { diag.arg("emitted_at", diag.emitted_at.clone()); diag.arg("note", self.note); let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); // after the `arg` calls - diag.sub(Level::Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into()); + diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into()); diag } } From 44f0043e82fb2d3156434797f2e638cb61b07ce9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Mar 2024 09:20:08 +1100 Subject: [PATCH 2/2] 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. --- compiler/rustc_errors/src/lib.rs | 36 +++++++++++++------ .../rustc_hir_analysis/src/astconv/lint.rs | 12 ++----- .../invalid-stashed-level-issue-121812.rs | 8 +++++ .../invalid-stashed-level-issue-121812.stderr | 9 +++++ 4 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 tests/ui/typeck/invalid-stashed-level-issue-121812.rs create mode 100644 tests/ui/typeck/invalid-stashed-level-issue-121812.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c03d65f9454ac..6b1ccbc5f7c40 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 { - 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 227254b4cc8b3..fb5f3426cea6a 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 0000000000000..4b61f4f2c63ab --- /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 0000000000000..9465935c8c235 --- /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`.