about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/lib.rs19
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs13
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs30
-rw-r--r--compiler/rustc_errors/src/lib.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs11
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs32
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs24
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs76
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs4
-rw-r--r--src/librustdoc/doctest.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs2
-rw-r--r--src/tools/rustfmt/src/parse/parser.rs4
-rw-r--r--src/tools/rustfmt/src/parse/session.rs8
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.stderr2
-rw-r--r--tests/ui/consts/const-eval/const-eval-query-stack.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-86800.stderr2
-rw-r--r--tests/ui/panics/default-backtrace-ice.stderr2
-rw-r--r--tests/ui/treat-err-as-bug/err.stderr2
20 files changed, 118 insertions, 158 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 495b255583c..0457b4e6ddc 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2399,10 +2399,10 @@ mod error {
         /// and we want only the best of those errors.
         ///
         /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
-        /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
-        /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
-        /// all move errors have been reported, any diagnostics in this map are added to the buffer
-        /// to be emitted.
+        /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
+        /// the `Place` of the previous most diagnostic. This happens instead of buffering the
+        /// error. Once all move errors have been reported, any diagnostics in this map are added
+        /// to the buffer to be emitted.
         ///
         /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
         /// when errors in the map are being re-added to the error buffer so that errors with the
@@ -2410,7 +2410,8 @@ mod error {
         buffered_move_errors:
             BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
         buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
-        /// Diagnostics to be reported buffer.
+        /// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
+        /// because it has a mixture of error diagnostics and non-error diagnostics.
         buffered: Vec<Diagnostic>,
         /// Set to Some if we emit an error during borrowck
         tainted_by_errors: Option<ErrorGuaranteed>,
@@ -2434,11 +2435,11 @@ mod error {
                     "diagnostic buffered but not emitted",
                 ))
             }
-            t.buffer(&mut self.buffered);
+            self.buffered.push(t.into_diagnostic());
         }
 
         pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
-            t.buffer(&mut self.buffered);
+            self.buffered.push(t.into_diagnostic());
         }
 
         pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
@@ -2486,13 +2487,13 @@ mod error {
             // Buffer any move errors that we collected and de-duplicated.
             for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
                 // We have already set tainted for this error, so just buffer it.
-                diag.buffer(&mut self.errors.buffered);
+                self.errors.buffered.push(diag.into_diagnostic());
             }
             for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
                 if count > 10 {
                     diag.note(format!("...and {} other attempted mutable borrows", count - 10));
                 }
-                diag.buffer(&mut self.errors.buffered);
+                self.errors.buffered.push(diag.into_diagnostic());
             }
 
             if !self.errors.buffered.is_empty() {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 738c532964a..ae9595d7e64 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -1,6 +1,6 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
@@ -214,7 +214,7 @@ pub struct Checker<'mir, 'tcx> {
     local_has_storage_dead: Option<BitSet<Local>>,
 
     error_emitted: Option<ErrorGuaranteed>,
-    secondary_errors: Vec<Diagnostic>,
+    secondary_errors: Vec<DiagnosticBuilder<'tcx>>,
 }
 
 impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> {
@@ -272,14 +272,17 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         }
 
         // If we got through const-checking without emitting any "primary" errors, emit any
-        // "secondary" errors if they occurred.
+        // "secondary" errors if they occurred. Otherwise, cancel the "secondary" errors.
         let secondary_errors = mem::take(&mut self.secondary_errors);
         if self.error_emitted.is_none() {
             for error in secondary_errors {
-                self.tcx.dcx().emit_diagnostic(error);
+                error.emit();
             }
         } else {
             assert!(self.tcx.dcx().has_errors().is_some());
+            for error in secondary_errors {
+                error.cancel();
+            }
         }
     }
 
@@ -347,7 +350,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 self.error_emitted = Some(reported);
             }
 
-            ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
+            ops::DiagnosticImportance::Secondary => self.secondary_errors.push(err),
         }
     }
 
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index a02909f29c4..bd7c58d904e 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -255,35 +255,13 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
     /// Stashes diagnostic for possible later improvement in a different,
     /// later stage of the compiler. The diagnostic can be accessed with
     /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
-    ///
-    /// As with `buffer`, this is unless the dcx has disabled such buffering.
     pub fn stash(self, span: Span, key: StashKey) {
-        if let Some((diag, dcx)) = self.into_diagnostic() {
-            dcx.stash_diagnostic(span, key, diag);
-        }
-    }
-
-    /// Converts the builder to a `Diagnostic` for later emission,
-    /// unless dcx has disabled such buffering.
-    fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
-        if self.dcx.inner.lock().flags.treat_err_as_bug.is_some() {
-            self.emit();
-            return None;
-        }
-
-        let diag = self.take_diag();
-
-        // Logging here is useful to help track down where in logs an error was
-        // actually emitted.
-        debug!("buffer: diag={:?}", diag);
-
-        Some((diag, self.dcx))
+        self.dcx.stash_diagnostic(span, key, self.into_diagnostic());
     }
 
-    /// Buffers the diagnostic for later emission,
-    /// unless dcx has disabled such buffering.
-    pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
-        buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
+    /// Converts the builder to a `Diagnostic` for later emission.
+    pub fn into_diagnostic(mut self) -> Diagnostic {
+        self.take_diag()
     }
 
     /// Delay emission of this diagnostic as a bug.
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 8fb539fc358..404c89ea01b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -981,6 +981,10 @@ impl DiagCtxt {
 
         inner.emit_stashed_diagnostics();
 
+        if inner.treat_err_as_bug() {
+            return;
+        }
+
         let warnings = match inner.deduplicated_warn_count {
             0 => Cow::from(""),
             1 => Cow::from("1 warning emitted"),
@@ -991,9 +995,6 @@ impl DiagCtxt {
             1 => Cow::from("aborting due to 1 previous error"),
             count => Cow::from(format!("aborting due to {count} previous errors")),
         };
-        if inner.treat_err_as_bug() {
-            return;
-        }
 
         match (errors.len(), warnings.len()) {
             (0, 0) => return,
@@ -1168,7 +1169,8 @@ impl DiagCtxt {
         let mut inner = self.inner.borrow_mut();
 
         if loud && lint_level.is_error() {
-            inner.bump_err_count();
+            inner.err_count += 1;
+            inner.panic_if_treat_err_as_bug();
         }
 
         inner.emitter.emit_unused_externs(lint_level, unused_externs)
@@ -1255,7 +1257,7 @@ impl DiagCtxtInner {
     }
 
     fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
-        if matches!(diagnostic.level, Error | Fatal) && self.treat_err_as_bug() {
+        if matches!(diagnostic.level, Error | Fatal) && self.treat_next_err_as_bug() {
             diagnostic.level = Bug;
         }
 
@@ -1353,10 +1355,11 @@ impl DiagCtxtInner {
             }
             if diagnostic.is_error() {
                 if diagnostic.is_lint {
-                    self.bump_lint_err_count();
+                    self.lint_err_count += 1;
                 } else {
-                    self.bump_err_count();
+                    self.err_count += 1;
                 }
+                self.panic_if_treat_err_as_bug();
 
                 #[allow(deprecated)]
                 {
@@ -1447,16 +1450,6 @@ impl DiagCtxtInner {
         panic::panic_any(DelayedBugPanic);
     }
 
-    fn bump_lint_err_count(&mut self) {
-        self.lint_err_count += 1;
-        self.panic_if_treat_err_as_bug();
-    }
-
-    fn bump_err_count(&mut self) {
-        self.err_count += 1;
-        self.panic_if_treat_err_as_bug();
-    }
-
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
             match (
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index c56a028321a..3430a5fb00d 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -498,14 +498,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     // order when emitting them.
                     let err =
                         self.tcx().dcx().struct_span_err(span, format!("user args: {user_args:?}"));
-                    err.buffer(&mut errors_buffer);
+                    errors_buffer.push(err);
                 }
             }
 
             if !errors_buffer.is_empty() {
                 errors_buffer.sort_by_key(|diag| diag.span.primary_span());
-                for diag in errors_buffer {
-                    self.tcx().dcx().emit_diagnostic(diag);
+                for err in errors_buffer {
+                    err.emit();
                 }
             }
         }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 6c000380e71..03335996c03 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -82,7 +82,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
                     Ok(..) => {}
                     Err(err) => err.cancel(),
                 },
-                Err(errs) => drop(errs),
+                Err(errs) => errs.into_iter().for_each(|err| err.cancel()),
             }
 
             // If the user tried to use a key="value" flag, but is missing the quotes, provide
@@ -129,9 +129,12 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
             error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
         };
 
-        let Ok(mut parser) = maybe_new_parser_from_source_str(&sess, filename, s.to_string())
-        else {
-            expected_error();
+        let mut parser = match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
+            Ok(parser) => parser,
+            Err(errs) => {
+                errs.into_iter().for_each(|err| err.cancel());
+                expected_error();
+            }
         };
 
         let meta_item = match parser.parse_meta_item() {
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 7db9291921f..d7ecf577ed6 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -7,7 +7,7 @@ use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{error_code, Applicability, DiagCtxt, Diagnostic, StashKey};
+use rustc_errors::{error_code, Applicability, DiagCtxt, DiagnosticBuilder, StashKey};
 use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::{Base, DocStyle, RawStrError};
 use rustc_lexer::{Cursor, LiteralKind};
@@ -42,12 +42,12 @@ pub struct UnmatchedDelim {
     pub candidate_span: Option<Span>,
 }
 
-pub(crate) fn parse_token_trees<'a>(
-    sess: &'a ParseSess,
-    mut src: &'a str,
+pub(crate) fn parse_token_trees<'sess, 'src>(
+    sess: &'sess ParseSess,
+    mut src: &'src str,
     mut start_pos: BytePos,
     override_span: Option<Span>,
-) -> Result<TokenStream, Vec<Diagnostic>> {
+) -> Result<TokenStream, Vec<DiagnosticBuilder<'sess>>> {
     // Skip `#!`, if present.
     if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
         src = &src[shebang_len..];
@@ -76,13 +76,13 @@ pub(crate) fn parse_token_trees<'a>(
             let mut buffer = Vec::with_capacity(1);
             for unmatched in unmatched_delims {
                 if let Some(err) = make_unclosed_delims_error(unmatched, sess) {
-                    err.buffer(&mut buffer);
+                    buffer.push(err);
                 }
             }
             if let Err(errs) = res {
                 // Add unclosing delimiter or diff marker errors
                 for err in errs {
-                    err.buffer(&mut buffer);
+                    buffer.push(err);
                 }
             }
             Err(buffer)
@@ -90,16 +90,16 @@ pub(crate) fn parse_token_trees<'a>(
     }
 }
 
-struct StringReader<'a> {
-    sess: &'a ParseSess,
+struct StringReader<'sess, 'src> {
+    sess: &'sess ParseSess,
     /// Initial position, read-only.
     start_pos: BytePos,
     /// The absolute offset within the source_map of the current character.
     pos: BytePos,
     /// Source text to tokenize.
-    src: &'a str,
+    src: &'src str,
     /// Cursor for getting lexer tokens.
-    cursor: Cursor<'a>,
+    cursor: Cursor<'src>,
     override_span: Option<Span>,
     /// When a "unknown start of token: \u{a0}" has already been emitted earlier
     /// in this file, it's safe to treat further occurrences of the non-breaking
@@ -107,8 +107,8 @@ struct StringReader<'a> {
     nbsp_is_whitespace: bool,
 }
 
-impl<'a> StringReader<'a> {
-    pub fn dcx(&self) -> &'a DiagCtxt {
+impl<'sess, 'src> StringReader<'sess, 'src> {
+    pub fn dcx(&self) -> &'sess DiagCtxt {
         &self.sess.dcx
     }
 
@@ -526,7 +526,7 @@ impl<'a> StringReader<'a> {
 
     /// Slice of the source text from `start` up to but excluding `self.pos`,
     /// meaning the slice does not include the character `self.ch`.
-    fn str_from(&self, start: BytePos) -> &'a str {
+    fn str_from(&self, start: BytePos) -> &'src str {
         self.str_from_to(start, self.pos)
     }
 
@@ -537,12 +537,12 @@ impl<'a> StringReader<'a> {
     }
 
     /// Slice of the source text spanning from `start` up to but excluding `end`.
-    fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str {
+    fn str_from_to(&self, start: BytePos, end: BytePos) -> &'src str {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
     /// Slice of the source text spanning from `start` until the end
-    fn str_from_to_end(&self, start: BytePos) -> &'a str {
+    fn str_from_to_end(&self, start: BytePos) -> &'src str {
         &self.src[self.src_index(start)..]
     }
 
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 64b3928689a..c9ff2d58e2c 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -8,18 +8,18 @@ use rustc_ast_pretty::pprust::token_to_string;
 use rustc_errors::{Applicability, PErr};
 use rustc_span::symbol::kw;
 
-pub(super) struct TokenTreesReader<'a> {
-    string_reader: StringReader<'a>,
+pub(super) struct TokenTreesReader<'sess, 'src> {
+    string_reader: StringReader<'sess, 'src>,
     /// The "next" token, which has been obtained from the `StringReader` but
     /// not yet handled by the `TokenTreesReader`.
     token: Token,
     diag_info: TokenTreeDiagInfo,
 }
 
-impl<'a> TokenTreesReader<'a> {
+impl<'sess, 'src> TokenTreesReader<'sess, 'src> {
     pub(super) fn parse_all_token_trees(
-        string_reader: StringReader<'a>,
-    ) -> (TokenStream, Result<(), Vec<PErr<'a>>>, Vec<UnmatchedDelim>) {
+        string_reader: StringReader<'sess, 'src>,
+    ) -> (TokenStream, Result<(), Vec<PErr<'sess>>>, Vec<UnmatchedDelim>) {
         let mut tt_reader = TokenTreesReader {
             string_reader,
             token: Token::dummy(),
@@ -35,7 +35,7 @@ impl<'a> TokenTreesReader<'a> {
     fn parse_token_trees(
         &mut self,
         is_delimited: bool,
-    ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'a>>>) {
+    ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'sess>>>) {
         // Move past the opening delimiter.
         let (_, open_spacing) = self.bump(false);
 
@@ -71,7 +71,7 @@ impl<'a> TokenTreesReader<'a> {
         }
     }
 
-    fn eof_err(&mut self) -> PErr<'a> {
+    fn eof_err(&mut self) -> PErr<'sess> {
         let msg = "this file contains an unclosed delimiter";
         let mut err = self.string_reader.sess.dcx.struct_span_err(self.token.span, msg);
         for &(_, sp) in &self.diag_info.open_braces {
@@ -99,7 +99,7 @@ impl<'a> TokenTreesReader<'a> {
     fn parse_token_tree_open_delim(
         &mut self,
         open_delim: Delimiter,
-    ) -> Result<TokenTree, Vec<PErr<'a>>> {
+    ) -> Result<TokenTree, Vec<PErr<'sess>>> {
         // The span for beginning of the delimited section
         let pre_span = self.token.span;
 
@@ -229,7 +229,11 @@ impl<'a> TokenTreesReader<'a> {
         (this_tok, this_spacing)
     }
 
-    fn unclosed_delim_err(&mut self, tts: TokenStream, mut errs: Vec<PErr<'a>>) -> Vec<PErr<'a>> {
+    fn unclosed_delim_err(
+        &mut self,
+        tts: TokenStream,
+        mut errs: Vec<PErr<'sess>>,
+    ) -> Vec<PErr<'sess>> {
         // If there are unclosed delims, see if there are diff markers and if so, point them
         // out instead of complaining about the unclosed delims.
         let mut parser = crate::stream_to_parser(self.string_reader.sess, tts, None);
@@ -285,7 +289,7 @@ impl<'a> TokenTreesReader<'a> {
         return errs;
     }
 
-    fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
+    fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'sess> {
         // An unexpected closing delimiter (i.e., there is no
         // matching opening delimiter).
         let token_str = token_to_string(&self.token);
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index dac7569e385..a136abaa28b 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -337,7 +337,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
 ];
 
 pub(super) fn check_for_substitution(
-    reader: &StringReader<'_>,
+    reader: &StringReader<'_, '_>,
     pos: BytePos,
     ch: char,
     count: usize,
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index b93f08a21e3..c00e318f227 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -19,7 +19,7 @@ use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AttrItem, Attribute, MetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Diagnostic, FatalError, Level, PResult};
+use rustc_errors::{DiagnosticBuilder, FatalError, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
 
@@ -45,14 +45,13 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 /// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
 /// `DiagnosticBuilder`.
 macro_rules! panictry_buffer {
-    ($handler:expr, $e:expr) => {{
-        use rustc_errors::FatalError;
+    ($e:expr) => {{
         use std::result::Result::{Err, Ok};
         match $e {
             Ok(e) => e,
             Err(errs) => {
                 for e in errs {
-                    $handler.emit_diagnostic(e);
+                    e.emit();
                 }
                 FatalError.raise()
             }
@@ -100,36 +99,41 @@ pub fn parse_stream_from_source_str(
 
 /// Creates a new parser from a source string.
 pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String) -> Parser<'_> {
-    panictry_buffer!(&sess.dcx, maybe_new_parser_from_source_str(sess, name, source))
+    panictry_buffer!(maybe_new_parser_from_source_str(sess, name, source))
 }
 
 /// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
-/// token stream.
+/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur
+/// when they are dropped.
 pub fn maybe_new_parser_from_source_str(
     sess: &ParseSess,
     name: FileName,
     source: String,
-) -> Result<Parser<'_>, Vec<Diagnostic>> {
+) -> Result<Parser<'_>, Vec<DiagnosticBuilder<'_>>> {
     maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))
 }
 
-/// Creates a new parser, handling errors as appropriate if the file doesn't exist.
-/// If a span is given, that is used on an error as the source of the problem.
+/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on
+/// an error as the source of the problem.
 pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> {
-    source_file_to_parser(sess, file_to_source_file(sess, path, sp))
-}
+    let source_file = sess.source_map().load_file(path).unwrap_or_else(|e| {
+        let msg = format!("couldn't read {}: {}", path.display(), e);
+        let mut err = sess.dcx.struct_fatal(msg);
+        if let Some(sp) = sp {
+            err.span(sp);
+        }
+        err.emit();
+    });
 
-/// Given a session and a `source_file`, returns a parser.
-fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> {
-    panictry_buffer!(&sess.dcx, maybe_source_file_to_parser(sess, source_file))
+    panictry_buffer!(maybe_source_file_to_parser(sess, source_file))
 }
 
-/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing the
-/// initial token stream.
+/// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing
+/// the initial token stream.
 fn maybe_source_file_to_parser(
     sess: &ParseSess,
     source_file: Lrc<SourceFile>,
-) -> Result<Parser<'_>, Vec<Diagnostic>> {
+) -> Result<Parser<'_>, Vec<DiagnosticBuilder<'_>>> {
     let end_pos = source_file.end_position();
     let stream = maybe_file_to_stream(sess, source_file, None)?;
     let mut parser = stream_to_parser(sess, stream, None);
@@ -142,52 +146,22 @@ fn maybe_source_file_to_parser(
 
 // Base abstractions
 
-/// Given a session and a path and an optional span (for error reporting),
-/// add the path to the session's source_map and return the new source_file or
-/// error when a file can't be read.
-fn try_file_to_source_file(
-    sess: &ParseSess,
-    path: &Path,
-    spanopt: Option<Span>,
-) -> Result<Lrc<SourceFile>, Diagnostic> {
-    sess.source_map().load_file(path).map_err(|e| {
-        let msg = format!("couldn't read {}: {}", path.display(), e);
-        let mut diag = Diagnostic::new(Level::Fatal, msg);
-        if let Some(sp) = spanopt {
-            diag.span(sp);
-        }
-        diag
-    })
-}
-
-/// Given a session and a path and an optional span (for error reporting),
-/// adds the path to the session's `source_map` and returns the new `source_file`.
-fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>) -> Lrc<SourceFile> {
-    match try_file_to_source_file(sess, path, spanopt) {
-        Ok(source_file) => source_file,
-        Err(d) => {
-            sess.dcx.emit_diagnostic(d);
-            FatalError.raise();
-        }
-    }
-}
-
 /// Given a `source_file`, produces a sequence of token trees.
 pub fn source_file_to_stream(
     sess: &ParseSess,
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
 ) -> TokenStream {
-    panictry_buffer!(&sess.dcx, maybe_file_to_stream(sess, source_file, override_span))
+    panictry_buffer!(maybe_file_to_stream(sess, source_file, override_span))
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
 /// parsing the token stream.
-pub fn maybe_file_to_stream(
-    sess: &ParseSess,
+fn maybe_file_to_stream<'sess>(
+    sess: &'sess ParseSess,
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
-) -> Result<TokenStream, Vec<Diagnostic>> {
+) -> Result<TokenStream, Vec<DiagnosticBuilder<'sess>>> {
     let src = source_file.src.as_ref().unwrap_or_else(|| {
         sess.dcx.bug(format!(
             "cannot lex `source_file` without source: {}",
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index 605f9e496c7..b736f4a7956 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -69,8 +69,8 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
     let mut parser =
         match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
             Ok(parser) => parser,
-            Err(diagnostics) => {
-                drop(diagnostics);
+            Err(errs) => {
+                errs.into_iter().for_each(|err| err.cancel());
                 return None;
             }
         };
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 9a900625268..82746a7ab03 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -589,7 +589,7 @@ pub(crate) fn make_test(
             let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source) {
                 Ok(p) => p,
                 Err(errs) => {
-                    drop(errs);
+                    errs.into_iter().for_each(|err| err.cancel());
                     return (found_main, found_extern_crate, found_macro);
                 }
             };
@@ -759,8 +759,10 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
             let mut parser =
                 match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) {
                     Ok(p) => p,
-                    Err(_) => {
-                        // If there is an unclosed delimiter, an error will be returned by the tokentrees.
+                    Err(errs) => {
+                        errs.into_iter().for_each(|err| err.cancel());
+                        // If there is an unclosed delimiter, an error will be returned by the
+                        // tokentrees.
                         return false;
                     }
                 };
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index a744b69ecb4..8b018220c17 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -53,7 +53,7 @@ pub fn check(
                 let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
                     Ok(p) => p,
                     Err(errs) => {
-                        drop(errs);
+                        errs.into_iter().for_each(|err| err.cancel());
                         return (false, test_attr_spans);
                     },
                 };
diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs
index 7045a7dd9ce..31226cf8c30 100644
--- a/src/tools/rustfmt/src/parse/parser.rs
+++ b/src/tools/rustfmt/src/parse/parser.rs
@@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
 
 use rustc_ast::token::TokenKind;
 use rustc_ast::{ast, attr, ptr};
-use rustc_errors::Diagnostic;
+use rustc_errors::DiagnosticBuilder;
 use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
 use rustc_span::{sym, Span};
 use thin_vec::ThinVec;
@@ -65,7 +65,7 @@ impl<'a> ParserBuilder<'a> {
     fn parser(
         sess: &'a rustc_session::parse::ParseSess,
         input: Input,
-    ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diagnostic>>> {
+    ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<DiagnosticBuilder<'a>>>> {
         match input {
             Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || {
                 new_parser_from_file(sess, file, None)
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index f4fb5073dfd..6dc3eac44d4 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -4,7 +4,9 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
 use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter};
 use rustc_errors::translation::Translate;
-use rustc_errors::{ColorConfig, DiagCtxt, Diagnostic, Level as DiagnosticLevel};
+use rustc_errors::{
+    ColorConfig, DiagCtxt, Diagnostic, DiagnosticBuilder, Level as DiagnosticLevel,
+};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
     source_map::{FilePathMapping, SourceMap},
@@ -283,9 +285,9 @@ impl ParseSess {
 
 // Methods that should be restricted within the parse module.
 impl ParseSess {
-    pub(super) fn emit_diagnostics(&self, diagnostics: Vec<Diagnostic>) {
+    pub(super) fn emit_diagnostics(&self, diagnostics: Vec<DiagnosticBuilder<'_>>) {
         for diagnostic in diagnostics {
-            self.parse_sess.dcx.emit_diagnostic(diagnostic);
+            diagnostic.emit();
         }
     }
 
diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr
index 869fcd20fac..06a52691310 100644
--- a/tests/rustdoc-ui/ice-bug-report-url.stderr
+++ b/tests/rustdoc-ui/ice-bug-report-url.stderr
@@ -1,4 +1,4 @@
-error: expected one of `->`, `where`, or `{`, found `<eof>`
+error: internal compiler error: expected one of `->`, `where`, or `{`, found `<eof>`
   --> $DIR/ice-bug-report-url.rs:14:10
    |
 LL | fn wrong()
diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr
index 01fb8153cf3..c748af608d1 100644
--- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant value failed
+error: internal compiler error[E0080]: evaluation of constant value failed
   --> $DIR/const-eval-query-stack.rs:16:16
    |
 LL | const X: i32 = 1 / 0;
diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr
index 07ba8eb021b..7af4846a959 100644
--- a/tests/ui/impl-trait/issues/issue-86800.stderr
+++ b/tests/ui/impl-trait/issues/issue-86800.stderr
@@ -4,7 +4,7 @@ error: unconstrained opaque type
 LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-error[E0792]: expected generic lifetime parameter, found `'_`
+error: internal compiler error[E0792]: expected generic lifetime parameter, found `'_`
   --> $DIR/issue-86800.rs:39:5
    |
 LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr
index 4b00f135047..9d27cb22ae9 100644
--- a/tests/ui/panics/default-backtrace-ice.stderr
+++ b/tests/ui/panics/default-backtrace-ice.stderr
@@ -1,4 +1,4 @@
-error[E0425]: cannot find value `missing_ident` in this scope
+error: internal compiler error[E0425]: cannot find value `missing_ident` in this scope
   --> $DIR/default-backtrace-ice.rs:21:13
    |
 LL | fn main() { missing_ident; }
diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr
index 3a56445a26b..4c5d0e5ae79 100644
--- a/tests/ui/treat-err-as-bug/err.stderr
+++ b/tests/ui/treat-err-as-bug/err.stderr
@@ -1,4 +1,4 @@
-error[E0080]: could not evaluate static initializer
+error: internal compiler error[E0080]: could not evaluate static initializer
   --> $DIR/err.rs:11:21
    |
 LL | pub static C: u32 = 0 - 1;