about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-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/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs11
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs30
-rw-r--r--compiler/rustc_errors/src/lib.rs27
-rw-r--r--compiler/rustc_fluent_macro/Cargo.toml2
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs6
-rw-r--r--compiler/rustc_interface/src/interface.rs11
-rw-r--r--compiler/rustc_macros/src/serialize.rs30
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs23
-rw-r--r--compiler/rustc_monomorphize/messages.ftl3
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs6
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs5
-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--compiler/rustc_passes/messages.ftl5
-rw-r--r--compiler/rustc_passes/src/errors.rs6
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs6
-rw-r--r--compiler/rustc_serialize/src/serialize.rs33
-rw-r--r--compiler/rustc_span/src/lib.rs23
-rw-r--r--compiler/rustc_target/src/spec/mod.rs17
32 files changed, 265 insertions, 227 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/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index fc3ff835a81..0c1fcecb571 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-annotate-snippets = "0.9"
+annotate-snippets = "0.10"
 derive_setters = "0.1.6"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 97f2efa7874..980ac310119 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -12,8 +12,7 @@ use crate::{
     CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
     LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
 };
-use annotate_snippets::display_list::{DisplayList, FormatOptions};
-use annotate_snippets::snippet::*;
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 use rustc_data_structures::sync::Lrc;
 use rustc_error_messages::FluentArgs;
 use rustc_span::source_map::SourceMap;
@@ -190,11 +189,6 @@ impl AnnotateSnippetEmitter {
                     annotation_type: annotation_type_for_level(*level),
                 }),
                 footer: vec![],
-                opt: FormatOptions {
-                    color: true,
-                    anonymized_line_numbers: self.ui_testing,
-                    margin: None,
-                },
                 slices: annotated_files
                     .iter()
                     .map(|(file_name, source, line_index, annotations)| {
@@ -222,7 +216,8 @@ impl AnnotateSnippetEmitter {
             // FIXME(#59346): Figure out if we can _always_ print to stderr or not.
             // `emitter.rs` has the `Destination` enum that lists various possible output
             // destinations.
-            eprintln!("{}", DisplayList::from(snippet))
+            let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing);
+            eprintln!("{}", renderer.render(snippet))
         }
         // FIXME(#59346): Is it ok to return None if there's no source_map?
     }
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_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml
index 872dd29a7a8..c5a53ae8313 100644
--- a/compiler/rustc_fluent_macro/Cargo.toml
+++ b/compiler/rustc_fluent_macro/Cargo.toml
@@ -8,7 +8,7 @@ proc-macro = true
 
 [dependencies]
 # tidy-alphabetical-start
-annotate-snippets = "0.9"
+annotate-snippets = "0.10"
 fluent-bundle = "0.15.2"
 fluent-syntax = "0.11"
 proc-macro2 = "1"
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 3b1b63455ed..520a64aaf5e 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
-    display_list::DisplayList,
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 use fluent_bundle::{FluentBundle, FluentError, FluentResource};
 use fluent_syntax::{
     ast::{
@@ -179,10 +176,9 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                             range: (pos.start, pos.end - 1),
                         }],
                     }],
-                    opt: Default::default(),
                 };
-                let dl = DisplayList::from(snippet);
-                eprintln!("{dl}\n");
+                let renderer = Renderer::plain();
+                eprintln!("{}\n", renderer.render(snippet));
             }
 
             return failed(&crate_name);
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 1f88aaa6a4b..2ad96a24891 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -300,13 +300,15 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .expect("missing associated item");
 
         if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
-            tcx.dcx()
+            let reported = tcx
+                .dcx()
                 .struct_span_err(
                     binding.span,
                     format!("{} `{}` is private", assoc_item.kind, binding.item_name),
                 )
                 .with_span_label(binding.span, format!("private {}", assoc_item.kind))
                 .emit();
+            self.set_tainted_by_errors(reported);
         }
         tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index fc2ed104b3d..7b23b74f829 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -354,7 +354,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
         self.note_ambiguous_inherent_assoc_type(&mut err, candidates, span);
-        err.emit()
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
@@ -843,7 +845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
-        err.emit();
+        self.set_tainted_by_errors(err.emit());
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 1f47564649e..2886ec21320 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -390,6 +390,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             infer_args,
         );
 
+        if let Err(err) = &arg_count.correct
+            && let Some(reported) = err.reported
+        {
+            self.set_tainted_by_errors(reported);
+        }
+
         // Skip processing if type has no generic parameters.
         // Traits always have `Self` as a generic parameter, which means they will not return early
         // here and so associated type bindings will be handled regardless of whether there are any
@@ -568,6 +574,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 span,
                 modifier: constness.as_str(),
             });
+            self.set_tainted_by_errors(e);
             arg_count.correct =
                 Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
         }
@@ -966,7 +973,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
             }
         }
-        err.emit()
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
     }
 
     // Search for a bound on a type parameter which includes the associated item
@@ -1043,6 +1052,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 span,
                 binding,
             );
+            self.set_tainted_by_errors(reported);
             return Err(reported);
         };
         debug!(?bound);
@@ -1120,6 +1130,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ));
             }
             let reported = err.emit();
+            self.set_tainted_by_errors(reported);
             if !where_bounds.is_empty() {
                 return Err(reported);
             }
@@ -1374,6 +1385,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         assoc_ident.name,
                     )
                 };
+                self.set_tainted_by_errors(reported);
                 return Err(reported);
             }
         };
@@ -1616,12 +1628,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let kind = tcx.def_kind_descr(kind, item);
             let msg = format!("{kind} `{name}` is private");
             let def_span = tcx.def_span(item);
-            tcx.dcx()
+            let reported = tcx
+                .dcx()
                 .struct_span_err(span, msg)
                 .with_code(rustc_errors::error_code!(E0624))
                 .with_span_label(span, format!("private {kind}"))
                 .with_span_label(def_span, format!("{kind} defined here"))
                 .emit();
+            self.set_tainted_by_errors(reported);
         }
         tcx.check_stability(item, Some(block), span, None);
     }
@@ -1862,7 +1876,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 err.span_label(span, format!("not allowed on {what}"));
             }
             extend(&mut err);
-            err.emit();
+            self.set_tainted_by_errors(err.emit());
             emitted = true;
         }
 
@@ -2184,7 +2198,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
-                    Ty::new_error(tcx, err.emit())
+                    let reported = err.emit();
+                    self.set_tainted_by_errors(reported);
+                    Ty::new_error(tcx, reported)
                 } else {
                     ty
                 }
@@ -2586,7 +2602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 );
             }
 
-            diag.emit();
+            self.set_tainted_by_errors(diag.emit());
         }
 
         // Find any late-bound regions declared in return type that do
@@ -2686,7 +2702,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 err.note("consider introducing a named lifetime parameter");
             }
 
-            err.emit();
+            self.set_tainted_by_errors(err.emit());
         }
     }
 
@@ -2725,7 +2741,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // error.
         let r = derived_region_bounds[0];
         if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-            tcx.dcx().emit_err(AmbiguousLifetimeBound { span });
+            self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span }));
         }
         Some(r)
     }
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index ea2f5f50b5c..f77f250cd28 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -116,7 +116,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
              for more information on them, visit \
              <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
             );
-            err.emit();
+            self.set_tainted_by_errors(err.emit());
         }
 
         if regular_traits.is_empty() && auto_traits.is_empty() {
@@ -127,6 +127,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .map(|trait_ref| tcx.def_span(trait_ref));
             let reported =
                 tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+            self.set_tainted_by_errors(reported);
             return Ty::new_error(tcx, reported);
         }
 
@@ -290,7 +291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
                 if references_self {
                     let def_id = i.bottom().0.def_id();
-                    struct_span_code_err!(
+                    let reported = struct_span_code_err!(
                         tcx.dcx(),
                         i.bottom().1,
                         E0038,
@@ -303,6 +304,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             .error_msg(),
                     )
                     .emit();
+                    self.set_tainted_by_errors(reported);
                 }
 
                 ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
@@ -389,6 +391,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         } else {
                             err.emit()
                         };
+                        self.set_tainted_by_errors(e);
                         ty::Region::new_error(tcx, e)
                     })
                 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index c9f89a0c3ef..e557f36037b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -35,6 +35,7 @@ use rustc_target::spec::abi;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use rustc_trait_selection::traits::ObligationCtxt;
+use std::cell::Cell;
 use std::iter;
 use std::ops::Bound;
 
@@ -119,6 +120,7 @@ pub fn provide(providers: &mut Providers) {
 pub struct ItemCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
     item_def_id: LocalDefId,
+    tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -343,7 +345,7 @@ fn bad_placeholder<'tcx>(
 
 impl<'tcx> ItemCtxt<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
-        ItemCtxt { tcx, item_def_id }
+        ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
     }
 
     pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
@@ -357,6 +359,13 @@ impl<'tcx> ItemCtxt<'tcx> {
     pub fn node(&self) -> hir::Node<'tcx> {
         self.tcx.hir_node(self.hir_id())
     }
+
+    fn check_tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> {
+        match self.tainted_by_errors.get() {
+            Some(err) => Err(err),
+            None => Ok(()),
+        }
+    }
 }
 
 impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
@@ -492,8 +501,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         ty.ty_adt_def()
     }
 
-    fn set_tainted_by_errors(&self, _: ErrorGuaranteed) {
-        // There's no obvious place to track this, so just let it go.
+    fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
+        self.tainted_by_errors.set(Some(err));
     }
 
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 3ceea3dc7ae..b936b0c0805 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -513,7 +513,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             bug!("unexpected sort of node in type_of(): {:?}", x);
         }
     };
-    ty::EarlyBinder::bind(output)
+    if let Err(e) = icx.check_tainted_by_errors() {
+        ty::EarlyBinder::bind(Ty::new_error(tcx, e))
+    } else {
+        ty::EarlyBinder::bind(output)
+    }
 }
 
 pub(super) fn type_of_opaque(
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 7edb5912dd5..b6b33299315 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -802,7 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .explicit_item_bounds(def_id)
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
-            ty::Error(_) => return None,
+            ty::Error(_) => return Some(ret_ty),
             _ => span_bug!(
                 closure_span,
                 "async fn coroutine return type not an inference variable: {ret_ty}"
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_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 9ca7ce09ba6..98b53945b91 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -76,8 +76,17 @@ fn decodable_body(
                 ty_name,
                 variants.len()
             );
+            let tag = if variants.len() < u8::MAX as usize {
+                quote! {
+                    ::rustc_serialize::Decoder::read_u8(__decoder) as usize
+                }
+            } else {
+                quote! {
+                    ::rustc_serialize::Decoder::read_usize(__decoder)
+                }
+            };
             quote! {
-                match ::rustc_serialize::Decoder::read_usize(__decoder) {
+                match #tag {
                     #match_inner
                     n => panic!(#message, n),
                 }
@@ -206,11 +215,20 @@ fn encodable_body(
                     variant_idx += 1;
                     result
                 });
-                quote! {
-                    let disc = match *self {
-                        #encode_inner
-                    };
-                    ::rustc_serialize::Encoder::emit_usize(__encoder, disc);
+                if variant_idx < u8::MAX as usize {
+                    quote! {
+                        let disc = match *self {
+                            #encode_inner
+                        };
+                        ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
+                    }
+                } else {
+                    quote! {
+                        let disc = match *self {
+                            #encode_inner
+                        };
+                        ::rustc_serialize::Encoder::emit_usize(__encoder, disc);
+                    }
                 }
             };
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 43c5b3873b9..ce9043ec287 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -566,17 +566,28 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         body,
         &[
             &check_alignment::CheckAlignment,
-            &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
+            // Before inlining: trim down MIR with passes to reduce inlining work.
+
+            // Has to be done before inlining, otherwise actual call will be almost always inlined.
+            // Also simple, so can just do first
+            &lower_slice_len::LowerSliceLenCalls,
+            // Perform inlining, which may add a lot of code.
             &inline::Inline,
-            // Substitutions during inlining may introduce switch on enums with uninhabited branches.
+            // Code from other crates may have storage markers, so this needs to happen after inlining.
+            &remove_storage_markers::RemoveStorageMarkers,
+            // Inlining and substitution may introduce ZST and useless drops.
+            &remove_zsts::RemoveZsts,
+            &remove_unneeded_drops::RemoveUnneededDrops,
+            // Type substitution may create uninhabited enums.
             &uninhabited_enum_branching::UninhabitedEnumBranching,
             &unreachable_prop::UnreachablePropagation,
             &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching),
-            &remove_storage_markers::RemoveStorageMarkers,
-            &remove_zsts::RemoveZsts,
-            &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
+            // Inlining may have introduced a lot of redundant code and a large move pattern.
+            // Now, we need to shrink the generated MIR.
+
+            // Has to run after `slice::len` lowering
+            &normalize_array_len::NormalizeArrayLen,
             &const_goto::ConstGoto,
-            &remove_unneeded_drops::RemoveUnneededDrops,
             &ref_prop::ReferencePropagation,
             &sroa::ScalarReplacementOfAggregates,
             &match_branches::MatchBranchSimplification,
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index e27875853df..94b553a07a7 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -20,6 +20,9 @@ monomorphize_recursion_limit =
     reached the recursion limit while instantiating `{$shrunk}`
     .note = `{$def_path_str}` defined here
 
+monomorphize_start_not_found = using `fn main` requires the standard library
+    .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]`
+
 monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
 
 monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 44beafa0873..92f001cc321 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -194,7 +194,7 @@ use rustc_target::abi::Size;
 use std::path::PathBuf;
 
 use crate::errors::{
-    EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit,
+    self, EncounteredErrorWhileInstantiating, LargeAssignmentsLint, NoOptimizedMir, RecursionLimit,
     TypeLengthLimit,
 };
 
@@ -1272,7 +1272,9 @@ impl<'v> RootCollector<'_, 'v> {
             return;
         };
 
-        let start_def_id = self.tcx.require_lang_item(LangItem::Start, None);
+        let Some(start_def_id) = self.tcx.lang_items().start_fn() else {
+            self.tcx.dcx().emit_fatal(errors::StartNotFound);
+        };
         let main_ret_ty = self.tcx.fn_sig(main_def_id).no_bound_vars().unwrap().output();
 
         // Given that `main()` has no arguments,
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 2ca14673a58..bd89874b5cc 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -95,6 +95,11 @@ pub struct EncounteredErrorWhileInstantiating {
 }
 
 #[derive(Diagnostic)]
+#[diag(monomorphize_start_not_found)]
+#[help]
+pub struct StartNotFound;
+
+#[derive(Diagnostic)]
 #[diag(monomorphize_unknown_cgu_collection_mode)]
 pub struct UnknownCguCollectionMode<'a> {
     pub mode: &'a str,
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/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index be50aad1303..d41cc724408 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -575,6 +575,11 @@ passes_outside_loop =
 
 passes_outside_loop_suggestion = consider labeling this block to be able to break within it
 
+passes_panic_unwind_without_std =
+    unwinding panics are not supported without std
+    .note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
+    .help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
+
 passes_params_not_allowed =
     referencing function parameters is not allowed in naked functions
     .help = follow the calling convention in asm block to use parameters
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index d934e959a41..cf3c7cc4ace 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -813,6 +813,12 @@ pub struct UnknownExternLangItem {
 pub struct MissingPanicHandler;
 
 #[derive(Diagnostic)]
+#[diag(passes_panic_unwind_without_std)]
+#[help]
+#[note]
+pub struct PanicUnwindWithoutStd;
+
+#[derive(Diagnostic)]
 #[diag(passes_missing_lang_item)]
 #[note]
 #[help]
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index db3d442676e..4eb0c6c275e 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -9,7 +9,9 @@ use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
-use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem};
+use crate::errors::{
+    MissingLangItem, MissingPanicHandler, PanicUnwindWithoutStd, UnknownExternLangItem,
+};
 
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
@@ -76,6 +78,8 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
         if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() {
             if item == LangItem::PanicImpl {
                 tcx.dcx().emit_err(MissingPanicHandler);
+            } else if item == LangItem::EhPersonality {
+                tcx.dcx().emit_err(PanicUnwindWithoutStd);
             } else {
                 tcx.dcx().emit_err(MissingLangItem { name: item.name() });
             }
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 63bd3457eb9..287e317b10f 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -70,14 +70,6 @@ pub trait Encoder {
     }
 
     fn emit_raw_bytes(&mut self, s: &[u8]);
-
-    fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
-    where
-        F: FnOnce(&mut Self),
-    {
-        self.emit_usize(v_id);
-        f(self);
-    }
 }
 
 // Note: all the methods in this trait are infallible, which may be surprising.
@@ -132,10 +124,6 @@ pub trait Decoder {
 
     fn read_raw_bytes(&mut self, len: usize) -> &[u8];
 
-    // Although there is an `emit_enum_variant` method in `Encoder`, the code
-    // patterns in decoding are different enough to encoding that there is no
-    // need for a corresponding `read_enum_variant` method here.
-
     fn peek_byte(&self) -> u8;
     fn position(&self) -> usize;
 }
@@ -372,15 +360,18 @@ impl<'a, D: Decoder> Decodable<D> for Cow<'a, str> {
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
     fn encode(&self, s: &mut S) {
         match *self {
-            None => s.emit_enum_variant(0, |_| {}),
-            Some(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+            None => s.emit_u8(0),
+            Some(ref v) => {
+                s.emit_u8(1);
+                v.encode(s);
+            }
         }
     }
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
     fn decode(d: &mut D) -> Option<T> {
-        match d.read_usize() {
+        match d.read_u8() {
             0 => None,
             1 => Some(Decodable::decode(d)),
             _ => panic!("Encountered invalid discriminant while decoding `Option`."),
@@ -391,15 +382,21 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
 impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
     fn encode(&self, s: &mut S) {
         match *self {
-            Ok(ref v) => s.emit_enum_variant(0, |s| v.encode(s)),
-            Err(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+            Ok(ref v) => {
+                s.emit_u8(0);
+                v.encode(s);
+            }
+            Err(ref v) => {
+                s.emit_u8(1);
+                v.encode(s);
+            }
         }
     }
 }
 
 impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
     fn decode(d: &mut D) -> Result<T1, T2> {
-        match d.read_usize() {
+        match d.read_u8() {
             0 => Ok(T1::decode(d)),
             1 => Err(T2::decode(d)),
             _ => panic!("Encountered invalid discriminant while decoding `Result`."),
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 4235293823c..65702f76fda 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -203,18 +203,19 @@ impl Hash for RealFileName {
 impl<S: Encoder> Encodable<S> for RealFileName {
     fn encode(&self, encoder: &mut S) {
         match *self {
-            RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
+            RealFileName::LocalPath(ref local_path) => {
+                encoder.emit_u8(0);
                 local_path.encode(encoder);
-            }),
-
-            RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
-                .emit_enum_variant(1, |encoder| {
-                    // For privacy and build reproducibility, we must not embed host-dependant path
-                    // in artifacts if they have been remapped by --remap-path-prefix
-                    assert!(local_path.is_none());
-                    local_path.encode(encoder);
-                    virtual_name.encode(encoder);
-                }),
+            }
+
+            RealFileName::Remapped { ref local_path, ref virtual_name } => {
+                encoder.emit_u8(1);
+                // For privacy and build reproducibility, we must not embed host-dependant path
+                // in artifacts if they have been remapped by --remap-path-prefix
+                assert!(local_path.is_none());
+                local_path.encode(encoder);
+                virtual_name.encode(encoder);
+            }
         }
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8e26327196a..da8706ea715 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -3396,19 +3396,22 @@ impl Hash for TargetTriple {
 impl<S: Encoder> Encodable<S> for TargetTriple {
     fn encode(&self, s: &mut S) {
         match self {
-            TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)),
-            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s
-                .emit_enum_variant(1, |s| {
-                    s.emit_str(triple);
-                    s.emit_str(contents)
-                }),
+            TargetTriple::TargetTriple(triple) => {
+                s.emit_u8(0);
+                s.emit_str(triple);
+            }
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
+                s.emit_u8(1);
+                s.emit_str(triple);
+                s.emit_str(contents);
+            }
         }
     }
 }
 
 impl<D: Decoder> Decodable<D> for TargetTriple {
     fn decode(d: &mut D) -> Self {
-        match d.read_usize() {
+        match d.read_u8() {
             0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
             1 => TargetTriple::TargetJson {
                 path_for_rustdoc: PathBuf::new(),