diff --git a/Cargo.lock b/Cargo.lock
index 52c9269fa87f0..818743b135b51 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -186,6 +186,48 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
+[[package]]
+name = "askama"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543"
+dependencies = [
+ "askama_derive",
+ "itoa",
+ "percent-encoding",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6"
+dependencies = [
+ "askama_parser",
+ "basic-toml",
+ "memchr",
+ "proc-macro2",
+ "quote",
+ "rustc-hash 2.1.1",
+ "serde",
+ "serde_derive",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "askama_parser"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
+dependencies = [
+ "memchr",
+ "serde",
+ "serde_derive",
+ "winnow 0.7.4",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.4.0"
@@ -1345,8 +1387,8 @@ name = "generate-copyright"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "askama",
  "cargo_metadata 0.18.1",
- "rinja",
  "serde",
  "serde_json",
  "thiserror 1.0.69",
@@ -3069,9 +3111,7 @@ version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
 dependencies = [
- "humansize",
  "itoa",
- "percent-encoding",
  "rinja_derive",
 ]
 
@@ -4628,6 +4668,7 @@ name = "rustdoc"
 version = "0.0.0"
 dependencies = [
  "arrayvec",
+ "askama",
  "base64",
  "expect-test",
  "indexmap",
@@ -4636,7 +4677,6 @@ dependencies = [
  "pulldown-cmark 0.9.6",
  "pulldown-cmark-escape",
  "regex",
- "rinja",
  "rustdoc-json-types",
  "serde",
  "serde_json",
@@ -5426,7 +5466,7 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "winnow",
+ "winnow 0.5.40",
 ]
 
 [[package]]
@@ -6437,6 +6477,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "winnow"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "winsplit"
 version = "0.1.0"
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 2a98821f22529..0927f648635ce 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -28,7 +28,7 @@
 #  - A new option
 #  - A change in the default values
 #
-# If the change-id does not match the version currently in use, x.py will 
+# If the change-id does not match the version currently in use, x.py will
 # display the changes made to the bootstrap.
 # To suppress these warnings, you can set change-id = "ignore".
 #change-id = <latest change id in src/bootstrap/src/utils/change_tracker.rs>
@@ -442,6 +442,9 @@
 # What custom diff tool to use for displaying compiletest tests.
 #compiletest-diff-tool = <none>
 
+# Whether to use the precompiled stage0 libtest with compiletest.
+#compiletest-use-stage0-libtest = true
+
 # Indicates whether ccache is used when building certain artifacts (e.g. LLVM).
 # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use
 # a specific version.
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index aa968a1e40f3e..e12441182186b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -406,8 +406,8 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
             // started MIR borrowchecking with, so the region
             // constraints have already been taken. Use the data from
             // our `mbcx` instead.
-            |vid| mbcx.regioncx.var_infos[vid].origin,
-            |vid| mbcx.regioncx.var_infos[vid].universe,
+            |vid| RegionVariableOrigin::Nll(mbcx.regioncx.definitions[vid].origin),
+            |vid| mbcx.regioncx.definitions[vid].universe,
         )
     }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 899e145c2c049..07555956f994c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::{self as hir, CoroutineKind, LangItem};
 use rustc_index::IndexSlice;
-use rustc_infer::infer::{
-    BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
-};
+use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};
 use rustc_infer::traits::SelectionError;
 use rustc_middle::bug;
 use rustc_middle::mir::{
@@ -633,9 +631,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     ) {
         let predicate_span = path.iter().find_map(|constraint| {
             let outlived = constraint.sub;
-            if let Some(origin) = self.regioncx.var_infos.get(outlived)
-                && let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
-                    origin.origin
+            if let Some(origin) = self.regioncx.definitions.get(outlived)
+                && let NllRegionVariableOrigin::Placeholder(_) = origin.origin
                 && let ConstraintCategory::Predicate(span) = constraint.category
             {
                 Some(span)
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index aa64a7c4e2a68..6f3b599d26f1b 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -334,7 +334,7 @@ fn emit_mermaid_nll_regions<'tcx>(
     writeln!(out, "flowchart TD")?;
 
     // Emit the region nodes.
-    for region in regioncx.var_infos.indices() {
+    for region in regioncx.definitions.indices() {
         write!(out, "{}[\"", region.as_usize())?;
         render_region(region, regioncx, out)?;
         writeln!(out, "\"]")?;
@@ -387,7 +387,7 @@ fn emit_mermaid_nll_sccs<'tcx>(
     // Gather and emit the SCC nodes.
     let mut nodes_per_scc: IndexVec<_, _> =
         regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
-    for region in regioncx.var_infos.indices() {
+    for region in regioncx.definitions.indices() {
         let scc = regioncx.constraint_sccs().scc(region);
         nodes_per_scc[scc].push(region);
     }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 5756a5e7c7c5e..41bbf74f18802 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -139,13 +139,11 @@ impl RegionTracker {
 }
 
 pub struct RegionInferenceContext<'tcx> {
-    pub var_infos: VarInfos,
-
     /// Contains the definition for every region variable. Region
     /// variables are identified by their index (`RegionVid`). The
     /// definition contains information about where the region came
     /// from as well as its final inferred value.
-    definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
+    pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
 
     /// The liveness constraints added to each region. For most
     /// regions, these start out empty and steadily grow, though for
@@ -453,7 +451,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r)));
 
         let mut result = Self {
-            var_infos,
             definitions,
             liveness_constraints,
             constraints,
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 7e355b6406aed..eade9e52de95a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::{bug, span_bug};
+use rustc_session::config::OptLevel;
 use tracing::{debug, instrument};
 
 use super::place::{PlaceRef, PlaceValue};
@@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                     _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
                 };
 
+                // Layout ensures that we only get here for cases where the discriminant
+                // value and the variant index match, since that's all `Niche` can encode.
+                // But for emphasis and debugging, let's double-check one anyway.
+                debug_assert_eq!(
+                    self.layout
+                        .ty
+                        .discriminant_for_variant(bx.tcx(), untagged_variant)
+                        .unwrap()
+                        .val,
+                    u128::from(untagged_variant.as_u32()),
+                );
+
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
 
                 // We have a subrange `niche_start..=niche_end` inside `range`.
@@ -537,6 +550,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                         relative_discr,
                         bx.cx().const_uint(tag_llty, relative_max as u64),
                     );
+
+                    // Thanks to parameter attributes and load metadata, LLVM already knows
+                    // the general valid range of the tag. It's possible, though, for there
+                    // to be an impossible value *in the middle*, which those ranges don't
+                    // communicate, so it's worth an `assume` to let the optimizer know.
+                    if niche_variants.contains(&untagged_variant)
+                        && bx.cx().sess().opts.optimize != OptLevel::No
+                    {
+                        let impossible =
+                            u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32());
+                        let impossible = bx.cx().const_uint(tag_llty, impossible);
+                        let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible);
+                        bx.assume(ne);
+                    }
+
                     (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
                 };
 
@@ -553,7 +581,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 );
 
                 // In principle we could insert assumes on the possible range of `discr`, but
-                // currently in LLVM this seems to be a pessimization.
+                // currently in LLVM this isn't worth it because the original `tag` will
+                // have either a `range` parameter attribute or `!range` metadata,
+                // or come from a `transmute` that already `assume`d it.
 
                 discr
             }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f5f7618285e1f..75bb0e8e7b43f 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -589,7 +589,8 @@ struct DiagCtxtInner {
     /// add more information). All stashed diagnostics must be emitted with
     /// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped,
     /// otherwise an assertion failure will occur.
-    stashed_diagnostics: FxIndexMap<(Span, StashKey), (DiagInner, Option<ErrorGuaranteed>)>,
+    stashed_diagnostics:
+        FxIndexMap<StashKey, FxIndexMap<Span, (DiagInner, Option<ErrorGuaranteed>)>>,
 
     future_breakage_diagnostics: Vec<DiagInner>,
 
@@ -912,8 +913,12 @@ impl<'a> DiagCtxtHandle<'a> {
         // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
         // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
         // See the PR for a discussion.
-        let key = (span.with_parent(None), key);
-        self.inner.borrow_mut().stashed_diagnostics.insert(key, (diag, guar));
+        self.inner
+            .borrow_mut()
+            .stashed_diagnostics
+            .entry(key)
+            .or_default()
+            .insert(span.with_parent(None), (diag, guar));
 
         guar
     }
@@ -922,9 +927,10 @@ impl<'a> DiagCtxtHandle<'a> {
     /// and [`StashKey`] as the key. Panics if the found diagnostic is an
     /// error.
     pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
-        let key = (span.with_parent(None), key);
         // FIXME(#120456) - is `swap_remove` correct?
-        let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?;
+        let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
+            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
+        )?;
         assert!(!diag.is_error());
         assert!(guar.is_none());
         Some(Diag::new_diagnostic(self, diag))
@@ -943,9 +949,10 @@ impl<'a> DiagCtxtHandle<'a> {
     where
         F: FnMut(&mut Diag<'_>),
     {
-        let key = (span.with_parent(None), key);
         // FIXME(#120456) - is `swap_remove` correct?
-        let err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key);
+        let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
+            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
+        );
         err.map(|(err, guar)| {
             // The use of `::<ErrorGuaranteed>` is safe because level is `Level::Error`.
             assert_eq!(err.level, Error);
@@ -966,9 +973,10 @@ impl<'a> DiagCtxtHandle<'a> {
         key: StashKey,
         new_err: Diag<'_>,
     ) -> ErrorGuaranteed {
-        let key = (span.with_parent(None), key);
         // FIXME(#120456) - is `swap_remove` correct?
-        let old_err = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key);
+        let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
+            |stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
+        );
         match old_err {
             Some((old_err, guar)) => {
                 assert_eq!(old_err.level, Error);
@@ -983,7 +991,14 @@ impl<'a> DiagCtxtHandle<'a> {
     }
 
     pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
-        self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
+        let inner = self.inner.borrow();
+        if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
+            && !stashed_diagnostics.is_empty()
+        {
+            stashed_diagnostics.contains_key(&span.with_parent(None))
+        } else {
+            false
+        }
     }
 
     /// Emit all stashed diagnostics.
@@ -997,7 +1012,11 @@ impl<'a> DiagCtxtHandle<'a> {
         let inner = self.inner.borrow();
         inner.err_guars.len()
             + inner.lint_err_guars.len()
-            + inner.stashed_diagnostics.values().filter(|(_diag, guar)| guar.is_some()).count()
+            + inner
+                .stashed_diagnostics
+                .values()
+                .map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
+                .sum::<usize>()
     }
 
     /// This excludes lint errors and delayed bugs. Unless absolutely
@@ -1486,16 +1505,18 @@ impl DiagCtxtInner {
     fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
         let mut guar = None;
         let has_errors = !self.err_guars.is_empty();
-        for (_, (diag, _guar)) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
-            if !diag.is_error() {
-                // Unless they're forced, don't flush stashed warnings when
-                // there are errors, to avoid causing warning overload. The
-                // stash would've been stolen already if it were important.
-                if !diag.is_force_warn() && has_errors {
-                    continue;
+        for (_, stashed_diagnostics) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
+            for (_, (diag, _guar)) in stashed_diagnostics {
+                if !diag.is_error() {
+                    // Unless they're forced, don't flush stashed warnings when
+                    // there are errors, to avoid causing warning overload. The
+                    // stash would've been stolen already if it were important.
+                    if !diag.is_force_warn() && has_errors {
+                        continue;
+                    }
                 }
+                guar = guar.or(self.emit_diagnostic(diag, None));
             }
-            guar = guar.or(self.emit_diagnostic(diag, None));
         }
         guar
     }
@@ -1688,6 +1709,7 @@ impl DiagCtxtInner {
             if let Some((_diag, guar)) = self
                 .stashed_diagnostics
                 .values()
+                .flat_map(|stashed_diagnostics| stashed_diagnostics.values())
                 .find(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
             {
                 *guar
@@ -1700,13 +1722,9 @@ impl DiagCtxtInner {
     fn has_errors(&self) -> Option<ErrorGuaranteed> {
         self.err_guars.get(0).copied().or_else(|| self.lint_err_guars.get(0).copied()).or_else(
             || {
-                if let Some((_diag, guar)) =
-                    self.stashed_diagnostics.values().find(|(_diag, guar)| guar.is_some())
-                {
-                    *guar
-                } else {
-                    None
-                }
+                self.stashed_diagnostics.values().find_map(|stashed_diagnostics| {
+                    stashed_diagnostics.values().find_map(|(_, guar)| *guar)
+                })
             },
         )
     }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 194f2cd04e468..2f7c3cb3c7d80 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -486,6 +486,9 @@ hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
 
+hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases
+    .label = `Self` is only available in impls, traits, and concrete type definitions
+
 hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>`
     .label = `Self` type parameter is implicitly captured by this `impl Trait`
     .note = currently, all type parameters are required to be mentioned in the precise captures list
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index f2560f22874bc..e6090a128b1c8 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1707,3 +1707,11 @@ pub(crate) enum SupertraitItemShadowee {
         traits: DiagSymbolList,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_in_type_alias, code = E0411)]
+pub(crate) struct SelfInTypeAlias {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index aeebe45f881ff..e64cd8ec302c7 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -16,6 +16,7 @@ use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
 use super::HirTyLowerer;
+use crate::errors::SelfInTypeAlias;
 use crate::hir_ty_lowering::{
     GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
 };
@@ -125,6 +126,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // ```
         let mut projection_bounds = FxIndexMap::default();
         for (proj, proj_span) in elaborated_projection_bounds {
+            let proj = proj.map_bound(|mut b| {
+                if let Some(term_ty) = &b.term.as_type() {
+                    let references_self = term_ty.walk().any(|arg| arg == dummy_self.into());
+                    if references_self {
+                        // With trait alias and type alias combined, type resolver
+                        // may not be able to catch all illegal `Self` usages (issue 139082)
+                        let guar = tcx.dcx().emit_err(SelfInTypeAlias { span });
+                        b.term = replace_dummy_self_with_error(tcx, b.term, guar);
+                    }
+                }
+                b
+            });
+
             let key = (
                 proj.skip_binder().projection_term.def_id,
                 tcx.anonymize_bound_vars(
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index c01b81563dcf7..64c1a78bd1c8b 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypingMode, fold_regions};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions};
 use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use tracing::debug;
@@ -77,6 +77,15 @@ fn diagnostic_hir_wf_check<'tcx>(
             let tcx_ty = fold_regions(self.tcx, tcx_ty, |r, _| {
                 if r.is_bound() { self.tcx.lifetimes.re_erased } else { r }
             });
+
+            // We may be checking the WFness of a type in an opaque with a non-lifetime bound.
+            // Perhaps we could rebind all the escaping bound vars, but they're coming from
+            // arbitrary debruijn indices and aren't particularly important anyways, since they
+            // are only coming from `feature(non_lifetime_binders)` anyways.
+            if tcx_ty.has_escaping_bound_vars() {
+                return;
+            }
+
             let cause = traits::ObligationCause::new(
                 ty.span,
                 self.def_id,
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index a0faa5e8429e5..780c27d45954d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -24,8 +24,8 @@ pub(super) fn infer_predicates(
 
     // If new predicates were added then we need to re-calculate
     // all crates since there could be new implied predicates.
-    loop {
-        let mut predicates_added = false;
+    for i in 0.. {
+        let mut predicates_added = vec![];
 
         // Visit all the crates and infer predicates
         for id in tcx.hir_free_items() {
@@ -83,14 +83,27 @@ pub(super) fn infer_predicates(
                 .get(&item_did.to_def_id())
                 .map_or(0, |p| p.as_ref().skip_binder().len());
             if item_required_predicates.len() > item_predicates_len {
-                predicates_added = true;
+                predicates_added.push(item_did);
                 global_inferred_outlives
                     .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates));
             }
         }
 
-        if !predicates_added {
+        if predicates_added.is_empty() {
+            // We've reached a fixed point.
             break;
+        } else if !tcx.recursion_limit().value_within_limit(i) {
+            let msg = if let &[id] = &predicates_added[..] {
+                format!("overflow computing implied lifetime bounds for `{}`", tcx.def_path_str(id),)
+            } else {
+                "overflow computing implied lifetime bounds".to_string()
+            };
+            tcx.dcx()
+                .struct_span_fatal(
+                    predicates_added.iter().map(|id| tcx.def_span(*id)).collect::<Vec<_>>(),
+                    msg,
+                )
+                .emit();
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 952a2e231e405..3475d15e94832 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2205,8 +2205,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap();
                 self.dcx()
                     .struct_span_err(
-                        span.shrink_to_hi(),
-                        format!("missing mandatory field{s} {fields}"),
+                        span.shrink_to_lo(),
+                        format!("missing field{s} {fields} in initializer"),
+                    )
+                    .with_span_label(
+                        span.shrink_to_lo(),
+                        "fields that do not have a defaulted value must be provided explicitly",
                     )
                     .emit();
                 return;
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 88d45ead29530..7c12f69f14c1a 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,5 +1,6 @@
 use std::fmt;
 use std::iter::once;
+use std::ops::ControlFlow;
 
 use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
 use rustc_arena::DroplessArena;
@@ -11,7 +12,8 @@ use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
+    self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, VariantDef,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -135,11 +137,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Returns the hidden type corresponding to this key if the body under analysis is allowed to
     /// know it.
     fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
-        self.typeck_results
-            .concrete_opaque_types
-            .get(&key.def_id)
-            .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
+        if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) {
+            let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args);
+            if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() {
+                Some(ty)
+            } else {
+                // HACK: We skip revealing opaque types which recursively expand
+                // to themselves. This is because we may infer hidden types like
+                // `Opaque<T> = Opaque<Opaque<T>>` or `Opaque<T> = Opaque<(T,)>`
+                // in hir typeck.
+                None
+            }
+        } else {
+            None
+        }
     }
+
     // This can take a non-revealed `Ty` because it reveals opaques itself.
     pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
         !ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
@@ -1105,3 +1118,20 @@ pub fn analyze_match<'p, 'tcx>(
 
     Ok(report)
 }
+
+struct RecursiveOpaque {
+    def_id: DefId,
+}
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveOpaque {
+    type Result = ControlFlow<()>;
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        if let ty::Alias(ty::Opaque, alias_ty) = t.kind() {
+            if alias_ty.def_id == self.def_id {
+                return ControlFlow::Break(());
+            }
+        }
+
+        if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2cb7d2d893135..9d5eb551fe6f7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1090,26 +1090,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             {
                 // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
-                let iter = data_a
-                    .principal()
-                    .filter(|_| {
-                        // optionally drop the principal, if we're unsizing to no principal
-                        data_b.principal().is_some()
-                    })
-                    .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
-                    .into_iter()
-                    .chain(
+                let existential_predicates = if data_b.principal().is_some() {
+                    tcx.mk_poly_existential_predicates_from_iter(
                         data_a
-                            .projection_bounds()
-                            .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+                            .principal()
+                            .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
+                            .into_iter()
+                            .chain(
+                                data_a
+                                    .projection_bounds()
+                                    .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+                            )
+                            .chain(
+                                data_b
+                                    .auto_traits()
+                                    .map(ty::ExistentialPredicate::AutoTrait)
+                                    .map(ty::Binder::dummy),
+                            ),
                     )
-                    .chain(
+                } else {
+                    // If we're unsizing to a dyn type that has no principal, then drop
+                    // the principal and projections from the type. We use the auto traits
+                    // from the RHS type since as we noted that we've checked for auto
+                    // trait compatibility during unsizing.
+                    tcx.mk_poly_existential_predicates_from_iter(
                         data_b
                             .auto_traits()
                             .map(ty::ExistentialPredicate::AutoTrait)
                             .map(ty::Binder::dummy),
-                    );
-                let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
+                    )
+                };
                 let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a);
 
                 // Require that the traits involved in this upcast are **equal**;
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 633ef717e04dc..e6867febf6c64 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2803,6 +2803,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// want to use the [`Default`] trait to generate values, you can
     /// pass [`Default::default`] as the second argument.
     ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
+    ///
     /// # Examples
     ///
     /// ```
@@ -3010,6 +3014,10 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// [`Clone`]), use [`Vec::resize_with`].
     /// If you only need to resize to a smaller size, use [`Vec::truncate`].
     ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 7fa57df9928c3..933b5aec70c63 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -5,15 +5,11 @@
 //!
 //! # Const intrinsics
 //!
-//! Note: any changes to the constness of intrinsics should be discussed with the language team.
-//! This includes changes in the stability of the constness.
-//!
-//! //FIXME(#132735) "old" style intrinsics support has been removed
-//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new"
-//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the
-//! implementation from <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to
+//! In order to make an intrinsic unstable usable at compile-time, copy the implementation from
+//! <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to
 //! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>
-//! and make the intrinsic declaration a `const fn`.
+//! and make the intrinsic declaration below a `const fn`. This should be done in coordination with
+//! wg-const-eval.
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
 //! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires
diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml
index 7b381b416ca8a..f2cbe512b5e4a 100644
--- a/src/bootstrap/defaults/bootstrap.dist.toml
+++ b/src/bootstrap/defaults/bootstrap.dist.toml
@@ -7,6 +7,8 @@ test-stage = 2
 doc-stage = 2
 # When compiling from source, you usually want all tools.
 extended = true
+# Use libtest built from the source tree instead of the precompiled one from stage 0.
+compiletest-use-stage0-libtest = false
 
 # Most users installing from source want to build all parts of the project from source.
 [llvm]
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index e67bc62a60352..b191d0f6b306b 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -369,6 +369,69 @@ impl Step for RustAnalyzer {
     }
 }
 
+/// Compiletest is implicitly "checked" when it gets built in order to run tests,
+/// so this is mainly for people working on compiletest to run locally.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Compiletest {
+    pub target: TargetSelection,
+}
+
+impl Step for Compiletest {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/compiletest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Compiletest { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let mode = if builder.config.compiletest_use_stage0_libtest {
+            Mode::ToolBootstrap
+        } else {
+            Mode::ToolStd
+        };
+
+        let compiler = builder.compiler(
+            if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage },
+            builder.config.build,
+        );
+
+        if mode != Mode::ToolBootstrap {
+            builder.ensure(Rustc::new(self.target, builder));
+        }
+
+        let mut cargo = prepare_tool_cargo(
+            builder,
+            compiler,
+            mode,
+            self.target,
+            builder.kind,
+            "src/tools/compiletest",
+            SourceType::InTree,
+            &[],
+        );
+
+        cargo.allow_features("test");
+
+        // For ./x.py clippy, don't run with --all-targets because
+        // linting tests and benchmarks can produce very noisy results
+        if builder.kind != Kind::Clippy {
+            cargo.arg("--all-targets");
+        }
+
+        let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target))
+            .with_prefix("compiletest-check");
+
+        let _guard = builder.msg_check("compiletest artifacts", self.target);
+        run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
+    }
+}
+
 macro_rules! tool_check_step {
     (
         $name:ident {
@@ -464,7 +527,3 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
 // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
 // check to make it easier to work on.
 tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
-
-// Compiletest is implicitly "checked" when it gets built in order to run tests,
-// so this is mainly for people working on compiletest to run locally.
-tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 18b5d4426b1ee..dab58fccf5e68 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2398,7 +2398,9 @@ pub fn run_cargo(
     // Ok now we need to actually find all the files listed in `toplevel`. We've
     // got a list of prefix/extensions and we basically just need to find the
     // most recent file in the `deps` folder corresponding to each one.
-    let contents = t!(target_deps_dir.read_dir())
+    let contents = target_deps_dir
+        .read_dir()
+        .unwrap_or_else(|e| panic!("Couldn't read {}: {}", target_deps_dir.display(), e))
         .map(|e| t!(e))
         .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata())))
         .collect::<Vec<_>>();
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index cd57e06ae04a3..b58d279359e30 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -425,11 +425,14 @@ macro_rules! bootstrap_tool {
                     }
                 )*
 
+                let is_unstable = false $(|| $unstable)*;
+                let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest;
+
                 builder.ensure(ToolBuild {
                     compiler: self.compiler,
                     target: self.target,
                     tool: $tool_name,
-                    mode: if false $(|| $unstable)* {
+                    mode: if is_unstable && !compiletest_wants_stage0 {
                         // use in-tree libraries for unstable features
                         Mode::ToolStd
                     } else {
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index a9058f888d38d..f002903996b23 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -101,13 +101,13 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     /// Primary function to implement `Step` logic.
     ///
     /// This function can be triggered in two ways:
-    ///     1. Directly from [`Builder::execute_cli`].
-    ///     2. Indirectly by being called from other `Step`s using [`Builder::ensure`].
+    /// 1. Directly from [`Builder::execute_cli`].
+    /// 2. Indirectly by being called from other `Step`s using [`Builder::ensure`].
     ///
-    /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function executed twice:
-    ///     - First in "dry-run" mode to validate certain things (like cyclic Step invocations,
-    ///         directory creation, etc) super quickly.
-    ///     - Then it's called again to run the actual, very expensive process.
+    /// When called with [`Builder::execute_cli`] (as done by `Build::build`), this function is executed twice:
+    /// - First in "dry-run" mode to validate certain things (like cyclic Step invocations,
+    ///   directory creation, etc) super quickly.
+    /// - Then it's called again to run the actual, very expensive process.
     ///
     /// When triggered indirectly from other `Step`s, it may still run twice (as dry-run and real mode)
     /// depending on the `Step::run` implementation of the caller.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 1712be7f947fa..d83731e0f0898 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -417,6 +417,9 @@ pub struct Config {
     /// Command for visual diff display, e.g. `diff-tool --color=always`.
     pub compiletest_diff_tool: Option<String>,
 
+    /// Whether to use the precompiled stage0 libtest with compiletest.
+    pub compiletest_use_stage0_libtest: bool,
+
     pub is_running_on_ci: bool,
 }
 
@@ -983,6 +986,7 @@ define_config! {
         optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
         jobs: Option<u32> = "jobs",
         compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
+        compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
         ccache: Option<StringOrBool> = "ccache",
         exclude: Option<Vec<PathBuf>> = "exclude",
     }
@@ -1682,6 +1686,7 @@ impl Config {
             optimized_compiler_builtins,
             jobs,
             compiletest_diff_tool,
+            compiletest_use_stage0_libtest,
             mut ccache,
             exclude,
         } = toml.build.unwrap_or_default();
@@ -2415,6 +2420,7 @@ impl Config {
         config.optimized_compiler_builtins =
             optimized_compiler_builtins.unwrap_or(config.channel != "dev");
         config.compiletest_diff_tool = compiletest_diff_tool;
+        config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true);
 
         let download_rustc = config.download_rustc_commit.is_some();
         config.explicit_stage_from_cli = flags.stage.is_some();
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 244391739f38a..48b6f77e8a587 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -391,4 +391,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "You can now use `change-id = \"ignore\"` to suppress `change-id ` warnings in the console.",
     },
+    ChangeInfo {
+        change_id: 139386,
+        severity: ChangeSeverity::Info,
+        summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index dbfd6f47dc67f..aa564b4a04513 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -5,6 +5,7 @@ pub static CRATES: &[&str] = &[
     // tidy-alphabetical-start
     "annotate-snippets",
     "anstyle",
+    "askama_parser",
     "basic-toml",
     "block-buffer",
     "bumpalo",
@@ -64,6 +65,7 @@ pub static CRATES: &[&str] = &[
     "wasm-bindgen-backend",
     "wasm-bindgen-macro-support",
     "wasm-bindgen-shared",
+    "winnow",
     "yoke",
     "zerofrom",
     "zerovec",
diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs
index 7fbfad467c641..208a494183c02 100644
--- a/src/ci/citool/src/analysis.rs
+++ b/src/ci/citool/src/analysis.rs
@@ -7,6 +7,7 @@ use build_helper::metrics::{
     format_build_steps,
 };
 
+use crate::github::JobInfoResolver;
 use crate::metrics;
 use crate::metrics::{JobMetrics, JobName, get_test_suites};
 use crate::utils::{output_details, pluralize};
@@ -185,13 +186,19 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
 }
 
 /// Outputs a report of test differences between the `parent` and `current` commits.
-pub fn output_test_diffs(job_metrics: &HashMap<JobName, JobMetrics>) {
+pub fn output_test_diffs(
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
-    report_test_diffs(aggregated_test_diffs);
+    report_test_diffs(aggregated_test_diffs, job_metrics, job_info_resolver);
 }
 
 /// Prints the ten largest differences in bootstrap durations.
-pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics>) {
+pub fn output_largest_duration_changes(
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     struct Entry<'a> {
         job: &'a JobName,
         before: Duration,
@@ -225,14 +232,14 @@ pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics
             });
         }
     }
-    changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse());
+    changes.sort_by(|e1, e2| e1.change.abs().partial_cmp(&e2.change.abs()).unwrap().reverse());
 
     println!("# Job duration changes");
     for (index, entry) in changes.into_iter().take(10).enumerate() {
         println!(
-            "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)",
+            "{}. {}: {:.1}s -> {:.1}s ({:.1}%)",
             index + 1,
-            entry.job,
+            format_job_link(job_info_resolver, job_metrics, entry.job),
             entry.before.as_secs_f64(),
             entry.after.as_secs_f64(),
             entry.change
@@ -400,7 +407,11 @@ fn generate_test_name(name: &str) -> String {
 }
 
 /// Prints test changes in Markdown format to stdout.
-fn report_test_diffs(diff: AggregatedTestDiffs) {
+fn report_test_diffs(
+    diff: AggregatedTestDiffs,
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_info_resolver: &mut JobInfoResolver,
+) {
     println!("# Test differences");
     if diff.diffs.is_empty() {
         println!("No test diffs found");
@@ -521,9 +532,26 @@ fn report_test_diffs(diff: AggregatedTestDiffs) {
                 println!(
                     "- {}: {}",
                     format_job_group(group as u64),
-                    jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
+                    jobs.iter()
+                        .map(|j| format_job_link(job_info_resolver, job_metrics, j))
+                        .collect::<Vec<_>>()
+                        .join(", ")
                 );
             }
         },
     );
 }
+
+/// Tries to get a GitHub Actions job summary URL from the resolver.
+/// If it is not available, just wraps the job name in backticks.
+fn format_job_link(
+    job_info_resolver: &mut JobInfoResolver,
+    job_metrics: &HashMap<JobName, JobMetrics>,
+    job_name: &str,
+) -> String {
+    job_metrics
+        .get(job_name)
+        .and_then(|metrics| job_info_resolver.get_job_summary_link(job_name, &metrics.current))
+        .map(|summary_url| format!("[{job_name}]({summary_url})"))
+        .unwrap_or_else(|| format!("`{job_name}`"))
+}
diff --git a/src/ci/citool/src/github.rs b/src/ci/citool/src/github.rs
new file mode 100644
index 0000000000000..35e4c3f9599d6
--- /dev/null
+++ b/src/ci/citool/src/github.rs
@@ -0,0 +1,109 @@
+use std::collections::HashMap;
+
+use anyhow::Context;
+use build_helper::metrics::{CiMetadata, JsonRoot};
+
+pub struct GitHubClient;
+
+impl GitHubClient {
+    fn get_workflow_run_jobs(
+        &self,
+        repo: &str,
+        workflow_run_id: u64,
+    ) -> anyhow::Result<Vec<GitHubJob>> {
+        let req = ureq::get(format!(
+            "https://api.github.com/repos/{repo}/actions/runs/{workflow_run_id}/jobs?per_page=100"
+        ))
+        .header("User-Agent", "rust-lang/rust/citool")
+        .header("Accept", "application/vnd.github+json")
+        .header("X-GitHub-Api-Version", "2022-11-28")
+        .call()
+        .context("cannot get workflow job list")?;
+
+        let status = req.status();
+        let mut body = req.into_body();
+        if status.is_success() {
+            // This API response is actually paged, but we assume for now that there are at
+            // most 100 jobs per workflow.
+            let response = body
+                .read_json::<WorkflowRunJobsResponse>()
+                .context("cannot deserialize workflow run jobs response")?;
+            // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to
+            // normalize the job name.
+            Ok(response
+                .jobs
+                .into_iter()
+                .map(|mut job| {
+                    job.name = job
+                        .name
+                        .split_once(" - ")
+                        .map(|res| res.1.to_string())
+                        .unwrap_or_else(|| job.name);
+                    job
+                })
+                .collect())
+        } else {
+            Err(anyhow::anyhow!(
+                "Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}",
+                body.read_to_string()?
+            ))
+        }
+    }
+}
+
+#[derive(serde::Deserialize)]
+struct WorkflowRunJobsResponse {
+    jobs: Vec<GitHubJob>,
+}
+
+#[derive(serde::Deserialize)]
+struct GitHubJob {
+    name: String,
+    id: u64,
+}
+
+/// Can be used to resolve information about GitHub Actions jobs.
+/// Caches results internally to avoid too unnecessary GitHub API calls.
+pub struct JobInfoResolver {
+    client: GitHubClient,
+    // Workflow run ID -> jobs
+    workflow_job_cache: HashMap<u64, Vec<GitHubJob>>,
+}
+
+impl JobInfoResolver {
+    pub fn new() -> Self {
+        Self { client: GitHubClient, workflow_job_cache: Default::default() }
+    }
+
+    /// Get a link to a job summary for the given job name and bootstrap execution.
+    pub fn get_job_summary_link(&mut self, job_name: &str, metrics: &JsonRoot) -> Option<String> {
+        metrics.ci_metadata.as_ref().and_then(|metadata| {
+            self.get_job_id(metadata, job_name).map(|job_id| {
+                format!(
+                    "https://github.com/{}/actions/runs/{}#summary-{job_id}",
+                    metadata.repository, metadata.workflow_run_id
+                )
+            })
+        })
+    }
+
+    fn get_job_id(&mut self, ci_metadata: &CiMetadata, job_name: &str) -> Option<u64> {
+        if let Some(job) = self
+            .workflow_job_cache
+            .get(&ci_metadata.workflow_run_id)
+            .and_then(|jobs| jobs.iter().find(|j| j.name == job_name))
+        {
+            return Some(job.id);
+        }
+
+        let jobs = self
+            .client
+            .get_workflow_run_jobs(&ci_metadata.repository, ci_metadata.workflow_run_id)
+            .inspect_err(|e| eprintln!("Cannot download workflow jobs: {e:?}"))
+            .ok()?;
+        let job_id = jobs.iter().find(|j| j.name == job_name).map(|j| j.id);
+        // Save the cache even if the job name was not found, it could be useful for further lookups
+        self.workflow_job_cache.insert(ci_metadata.workflow_run_id, jobs);
+        job_id
+    }
+}
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index 6db5eab458cca..a1956da352f5c 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -1,6 +1,7 @@
 mod analysis;
 mod cpu_usage;
 mod datadog;
+mod github;
 mod jobs;
 mod metrics;
 mod utils;
@@ -18,6 +19,7 @@ use serde_yaml::Value;
 use crate::analysis::{output_largest_duration_changes, output_test_diffs};
 use crate::cpu_usage::load_cpu_usage;
 use crate::datadog::upload_datadog_metric;
+use crate::github::JobInfoResolver;
 use crate::jobs::RunType;
 use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
 use crate::utils::load_env_var;
@@ -145,6 +147,7 @@ fn postprocess_metrics(
 ) -> anyhow::Result<()> {
     let metrics = load_metrics(&metrics_path)?;
 
+    let mut job_info_resolver = JobInfoResolver::new();
     if let (Some(parent), Some(job_name)) = (parent, job_name) {
         // This command is executed also on PR builds, which might not have parent metrics
         // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
@@ -160,7 +163,7 @@ fn postprocess_metrics(
                     job_name,
                     JobMetrics { parent: Some(parent_metrics), current: metrics },
                 )]);
-                output_test_diffs(&job_metrics);
+                output_test_diffs(&job_metrics, &mut job_info_resolver);
                 return Ok(());
             }
             Err(error) => {
@@ -180,8 +183,10 @@ fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow
     let metrics = download_auto_job_metrics(&db, &parent, &current)?;
 
     println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
-    output_test_diffs(&metrics);
-    output_largest_duration_changes(&metrics);
+
+    let mut job_info_resolver = JobInfoResolver::new();
+    output_test_diffs(&metrics, &mut job_info_resolver);
+    output_largest_duration_changes(&metrics, &mut job_info_resolver);
 
     Ok(())
 }
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index 3593b3f7df633..d81be88b70872 100644
--- a/src/ci/citool/tests/test-jobs.yml
+++ b/src/ci/citool/tests/test-jobs.yml
@@ -27,7 +27,7 @@ runners:
     <<: *base-job
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
     RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
     RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
     # Ensure that host tooling is tested on our minimum supported macOS version.
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 8bb7116c3ec58..418408e9242ae 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -47,6 +47,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 ENV SCRIPT \
            python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
            /scripts/check-default-config-profiles.sh && \
+           python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
            python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \
            python3 ../x.py clippy ci && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index 89806634c6c26..05c90af780732 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -101,4 +101,5 @@ COPY scripts/shared.sh /scripts/
 # the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
   npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
+  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 68e680a1b1b79..fbda749b6a2a8 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -58,7 +58,7 @@ runners:
     <<: *base-job
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
     RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
     RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
     # Ensure that host tooling is tested on our minimum supported macOS version.
diff --git a/src/doc/reference b/src/doc/reference
index e95ebdfee0251..46435cd4eba11 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit e95ebdfee02514d93f79ec92ae310a804e87f01f
+Subproject commit 46435cd4eba11b66acaa42c01da5c80ad88aee4b
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 6f69823c28ae8..0d7964d5b22cf 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 6f69823c28ae8d929d6c815181c73d3e99ef16d3
+Subproject commit 0d7964d5b22cf920237ef1282d869564b4883b88
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index a0e38f340f581..9e59dd889985c 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -53,7 +53,8 @@ Various intrinsics have native MIR operations that they correspond to. Instead o
 backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
 will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
 at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`.
-The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
+The body is never used as the lowering pass implements support for all backends, so we never have to
+use the fallback logic.
 
 ## Intrinsics without fallback logic
 
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 909b81a723b48..27ae0553c60de 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -9,7 +9,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-rinja = { version = "0.3", default-features = false, features = ["config"] }
+askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
diff --git a/src/librustdoc/rinja.toml b/src/librustdoc/askama.toml
similarity index 100%
rename from src/librustdoc/rinja.toml
rename to src/librustdoc/askama.toml
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index df70df062fe0b..44b3be23914c2 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,7 +1,7 @@
 use std::fmt::{self, Display};
 use std::path::PathBuf;
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::FxIndexMap;
 
 use super::static_files::{STATIC_FILES, StaticFiles};
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5f69e79f3ab1f..e2d1f58a37ecb 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -5,7 +5,7 @@ use std::io;
 use std::path::{Path, PathBuf};
 use std::sync::mpsc::{Receiver, channel};
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 2237e0f987bc5..3512dff0865c5 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -43,7 +43,7 @@ use std::iter::Peekable;
 use std::path::PathBuf;
 use std::{fs, str};
 
-use rinja::Template;
+use askama::Template;
 use rustc_attr_parsing::{
     ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
 };
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 3c5c2ce19767d..96847f13f655c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
 use std::fmt::{self, Display, Write as _};
 use std::iter;
 
-use rinja::Template;
+use askama::Template;
 use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_hir as hir;
@@ -37,7 +37,7 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
 
-/// Generates a Rinja template struct for rendering items with common methods.
+/// Generates an Askama template struct for rendering items with common methods.
 ///
 /// Usage:
 /// ```ignore (illustrative)
@@ -301,7 +301,7 @@ fn toggle_close(mut w: impl fmt::Write) {
     w.write_str("</details>").unwrap();
 }
 
-trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
+trait ItemTemplate<'a, 'cx: 'a>: askama::Template + Display {
     fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
 }
 
@@ -1867,7 +1867,7 @@ fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) ->
                     }
                 }
             }
-            Ok(())
+            fmt::Result::Ok(())
         })?;
         write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
     })
@@ -1944,7 +1944,7 @@ fn item_constant(
                     }
                 }
             }
-            Ok(())
+            Ok::<(), fmt::Error>(())
         })?;
 
         write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 89ff61ecb03e4..cd0c9775f5c97 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 use std::cmp::Ordering;
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefIdMap, DefIdSet};
@@ -123,10 +123,10 @@ impl<'a> Link<'a> {
 pub(crate) mod filters {
     use std::fmt::{self, Display};
 
-    use rinja::filters::Safe;
+    use askama::filters::Safe;
 
     use crate::html::escape::EscapeBodyTextWithWbr;
-    pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
+    pub(crate) fn wrapped<T>(v: T) -> askama::Result<Safe<impl Display>>
     where
         T: Display,
     {
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index a1ee5c8c548b7..fb1f0271c2ad7 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use rinja::Template;
+use askama::Template;
 use rustc_abi::{Primitive, TagEncoding, Variants};
 use rustc_hir::def_id::DefId;
 use rustc_middle::span_bug;
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index cbbd4b01d83ed..095795c711d9c 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -3,7 +3,7 @@ use std::ffi::OsStr;
 use std::path::{Component, Path, PathBuf};
 use std::{fmt, fs};
 
-use rinja::Template;
+use askama::Template;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index 32bacb11475cf..12c2553cffdbb 100644
--- a/src/librustdoc/html/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
@@ -1,13 +1,13 @@
 # Style for Templates
 
-This directory has templates in the [Rinja templating language][rinjadoc], which is very
+This directory has templates in the [Askama templating language][askamadoc], which is very
 similar to [Jinja2][jinjadoc].
 
 [jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/
-[rinjadoc]: https://docs.rs/rinja/latest/rinja/
+[askamadoc]: https://docs.rs/askama/latest/askama/
 
 We want our rendered output to have as little unnecessary whitespace as
-possible, so that pages load quickly. To achieve that we use Rinja's
+possible, so that pages load quickly. To achieve that we use Askama's
 [whitespace control] features. By default, whitespace characters are removed
 around jinja tags (`{% %}` for example). At the end of most lines, we put an
 empty comment tag: `{# #}`. This causes all whitespace between the end of the
@@ -18,7 +18,7 @@ remove following whitespace but not preceding. We also use the whitespace
 control characters in most instances of tags with control flow, for example
 `{% if foo %}`.
 
-[whitespace control]: https://rinja.readthedocs.io/en/stable/configuration.html#whitespace-control
+[whitespace control]: https://askama.readthedocs.io/en/stable/configuration.html#whitespace-control
 
 We want our templates to be readable, so we use indentation and newlines
 liberally. We indent by four spaces after opening an HTML tag _or_ a Jinja
@@ -26,11 +26,11 @@ tag. In most cases an HTML tag should be followed by a newline, but if the
 tag has simple contents and fits with its close tag on a single line, the
 contents don't necessarily need a new line.
 
-Rinja templates support quite sophisticated control flow. To keep our templates
+Askama templates support quite sophisticated control flow. To keep our templates
 simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic][assignments] and [Rinja
+we avoid [assignments in the template logic][assignments] and [Askama
 macros][macros]. This also may make things easier if we switch to a different
 Jinja-style template system in the future.
 
-[assignments]: https://rinja.readthedocs.io/en/stable/template_syntax.html#assignments
-[macros]: https://rinja.readthedocs.io/en/stable/template_syntax.html#macros
+[assignments]: https://askama.readthedocs.io/en/stable/template_syntax.html#assignments
+[macros]: https://askama.readthedocs.io/en/stable/template_syntax.html#macros
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index b68f817146fd7..9b59e4968a3dc 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -3,7 +3,6 @@ use std::fs::File;
 use std::io::BufReader;
 use std::io::prelude::*;
 use std::path::Path;
-use std::str::FromStr;
 use std::sync::OnceLock;
 
 use regex::Regex;
@@ -18,30 +17,39 @@ pub enum ErrorKind {
     Warning,
 }
 
-impl FromStr for ErrorKind {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let s = s.to_uppercase();
-        let part0: &str = s.split(':').next().unwrap();
-        match part0 {
-            "HELP" => Ok(ErrorKind::Help),
-            "ERROR" => Ok(ErrorKind::Error),
-            "NOTE" => Ok(ErrorKind::Note),
-            "SUGGESTION" => Ok(ErrorKind::Suggestion),
-            "WARN" | "WARNING" => Ok(ErrorKind::Warning),
-            _ => Err(()),
+impl ErrorKind {
+    pub fn from_compiler_str(s: &str) -> ErrorKind {
+        match s {
+            "help" => ErrorKind::Help,
+            "error" | "error: internal compiler error" => ErrorKind::Error,
+            "note" | "failure-note" => ErrorKind::Note,
+            "warning" => ErrorKind::Warning,
+            _ => panic!("unexpected compiler diagnostic kind `{s}`"),
         }
     }
+
+    /// Either the canonical uppercase string, or some additional versions for compatibility.
+    /// FIXME: consider keeping only the canonical versions here.
+    fn from_user_str(s: &str) -> Option<ErrorKind> {
+        Some(match s {
+            "HELP" | "help" => ErrorKind::Help,
+            "ERROR" | "error" => ErrorKind::Error,
+            "NOTE" | "note" => ErrorKind::Note,
+            "SUGGESTION" => ErrorKind::Suggestion,
+            "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
+            _ => return None,
+        })
+    }
 }
 
 impl fmt::Display for ErrorKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ErrorKind::Help => write!(f, "help message"),
-            ErrorKind::Error => write!(f, "error"),
-            ErrorKind::Note => write!(f, "note"),
-            ErrorKind::Suggestion => write!(f, "suggestion"),
-            ErrorKind::Warning => write!(f, "warning"),
+            ErrorKind::Help => write!(f, "HELP"),
+            ErrorKind::Error => write!(f, "ERROR"),
+            ErrorKind::Note => write!(f, "NOTE"),
+            ErrorKind::Suggestion => write!(f, "SUGGESTION"),
+            ErrorKind::Warning => write!(f, "WARN"),
         }
     }
 }
@@ -53,6 +61,10 @@ pub struct Error {
     /// `None` if not specified or unknown message kind.
     pub kind: Option<ErrorKind>,
     pub msg: String,
+    /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
+    /// are not mandatory, even if they would otherwise be mandatory for primary errors.
+    /// Only makes sense for "actual" errors, not for "expected" errors.
+    pub require_annotation: bool,
 }
 
 impl Error {
@@ -60,7 +72,7 @@ impl Error {
         use colored::Colorize;
         format!(
             "{: <10}line {: >3}: {}",
-            self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
+            self.kind.map(|kind| kind.to_string()).unwrap_or_default(),
             self.line_num_str(),
             self.msg.cyan(),
         )
@@ -150,18 +162,12 @@ fn parse_expected(
     }
 
     // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
-    let whole_match = captures.get(0).unwrap();
-    let (_, mut msg) = line.split_at(whole_match.end());
-
-    let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
-
-    // If we find `//~ ERROR foo` or something like that, skip the first word.
-    let kind = first_word.parse::<ErrorKind>().ok();
-    if kind.is_some() {
-        msg = &msg.trim_start().split_at(first_word.len()).1;
-    }
-
-    let msg = msg.trim().to_owned();
+    let tag = captures.get(0).unwrap();
+    let rest = line[tag.end()..].trim_start();
+    let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
+    let kind = ErrorKind::from_user_str(kind_str);
+    let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest };
+    let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
 
     let line_num_adjust = &captures["adjust"];
     let (follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +183,12 @@ fn parse_expected(
     debug!(
         "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
         line_num,
-        whole_match.as_str(),
+        tag.as_str(),
         follow_prev,
         kind,
         msg
     );
-    Some((follow_prev, Error { line_num, kind, msg }))
+    Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
 }
 
 #[cfg(test)]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index a0178f4bcc576..fbf365d76bcfb 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -979,16 +979,13 @@ impl Config {
 
     fn parse_env(nv: String) -> (String, String) {
         // nv is either FOO or FOO=BAR
-        let mut strs: Vec<String> = nv.splitn(2, '=').map(str::to_owned).collect();
-
-        match strs.len() {
-            1 => (strs.pop().unwrap(), String::new()),
-            2 => {
-                let end = strs.pop().unwrap();
-                (strs.pop().unwrap(), end)
-            }
-            n => panic!("Expected 1 or 2 strings, not {}", n),
-        }
+        // FIXME(Zalathar): The form without `=` seems to be unused; should
+        // we drop support for it?
+        let (name, value) = nv.split_once('=').unwrap_or((&nv, ""));
+        // Trim whitespace from the name, so that `//@ exec-env: FOO=BAR`
+        // sees the name as `FOO` and not ` FOO`.
+        let name = name.trim();
+        (name.to_owned(), value.to_owned())
     }
 
     fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> {
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 9bc26fedf8f4c..62fe538ee32ea 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -1,7 +1,6 @@
 //! These structs are a subset of the ones found in `rustc_errors::json`.
 
 use std::path::{Path, PathBuf};
-use std::str::FromStr;
 use std::sync::OnceLock;
 
 use regex::Regex;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
 }
 
 pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
-    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
-}
-
-fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
-    // The compiler sometimes intermingles non-JSON stuff into the
-    // output.  This hack just skips over such lines. Yuck.
-    if line.starts_with('{') {
-        match serde_json::from_str::<Diagnostic>(line) {
-            Ok(diagnostic) => {
-                let mut expected_errors = vec![];
-                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
-                expected_errors
-            }
-            Err(error) => {
-                // Ignore the future compat report message - this is handled
-                // by `extract_rendered`
-                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
-                    vec![]
-                } else {
-                    proc_res.fatal(
+    let mut errors = Vec::new();
+    for line in output.lines() {
+        // The compiler sometimes intermingles non-JSON stuff into the
+        // output.  This hack just skips over such lines. Yuck.
+        if line.starts_with('{') {
+            match serde_json::from_str::<Diagnostic>(line) {
+                Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
+                Err(error) => {
+                    // Ignore the future compat report message - this is handled
+                    // by `extract_rendered`
+                    if serde_json::from_str::<FutureIncompatReport>(line).is_err() {
+                        proc_res.fatal(
                         Some(&format!(
-                            "failed to decode compiler output as json: \
-                         `{}`\nline: {}\noutput: {}",
+                            "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
                             error, line, output
                         )),
                         || (),
                     );
+                    }
                 }
             }
         }
-    } else {
-        vec![]
     }
+    errors
 }
 
-fn push_expected_errors(
-    expected_errors: &mut Vec<Error>,
+fn push_actual_errors(
+    errors: &mut Vec<Error>,
     diagnostic: &Diagnostic,
     default_spans: &[&DiagnosticSpan],
     file_name: &str,
@@ -236,44 +226,47 @@ fn push_expected_errors(
         }
     };
 
-    // Convert multi-line messages into multiple expected
-    // errors. We expect to replace these with something
-    // more structured shortly anyhow.
+    // Convert multi-line messages into multiple errors.
+    // We expect to replace these with something more structured anyhow.
     let mut message_lines = diagnostic.message.lines();
-    if let Some(first_line) = message_lines.next() {
-        let ignore = |s| {
-            static RE: OnceLock<Regex> = OnceLock::new();
-            RE.get_or_init(|| {
-                Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap()
-            })
-            .is_match(s)
-        };
-
-        if primary_spans.is_empty() && !ignore(first_line) {
-            let msg = with_code(None, first_line);
-            let kind = ErrorKind::from_str(&diagnostic.level).ok();
-            expected_errors.push(Error { line_num: None, kind, msg });
-        } else {
-            for span in primary_spans {
-                let msg = with_code(Some(span), first_line);
-                let kind = ErrorKind::from_str(&diagnostic.level).ok();
-                expected_errors.push(Error { line_num: Some(span.line_start), kind, msg });
-            }
+    let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level));
+    let first_line = message_lines.next().unwrap_or(&diagnostic.message);
+    if primary_spans.is_empty() {
+        static RE: OnceLock<Regex> = OnceLock::new();
+        let re_init =
+            || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
+        errors.push(Error {
+            line_num: None,
+            kind,
+            msg: with_code(None, first_line),
+            require_annotation: diagnostic.level != "failure-note"
+                && !RE.get_or_init(re_init).is_match(first_line),
+        });
+    } else {
+        for span in primary_spans {
+            errors.push(Error {
+                line_num: Some(span.line_start),
+                kind,
+                msg: with_code(Some(span), first_line),
+                require_annotation: true,
+            });
         }
     }
     for next_line in message_lines {
         if primary_spans.is_empty() {
-            expected_errors.push(Error {
+            errors.push(Error {
                 line_num: None,
-                kind: None,
+                kind,
                 msg: with_code(None, next_line),
+                require_annotation: false,
             });
         } else {
             for span in primary_spans {
-                expected_errors.push(Error {
+                errors.push(Error {
                     line_num: Some(span.line_start),
-                    kind: None,
+                    kind,
                     msg: with_code(Some(span), next_line),
+                    require_annotation: false,
                 });
             }
         }
@@ -283,10 +276,11 @@ fn push_expected_errors(
     for span in primary_spans {
         if let Some(ref suggested_replacement) = span.suggested_replacement {
             for (index, line) in suggested_replacement.lines().enumerate() {
-                expected_errors.push(Error {
+                errors.push(Error {
                     line_num: Some(span.line_start + index),
                     kind: Some(ErrorKind::Suggestion),
                     msg: line.to_string(),
+                    require_annotation: true,
                 });
             }
         }
@@ -295,39 +289,41 @@ fn push_expected_errors(
     // Add notes for the backtrace
     for span in primary_spans {
         if let Some(frame) = &span.expansion {
-            push_backtrace(expected_errors, frame, file_name);
+            push_backtrace(errors, frame, file_name);
         }
     }
 
     // Add notes for any labels that appear in the message.
     for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
-        expected_errors.push(Error {
+        errors.push(Error {
             line_num: Some(span.line_start),
             kind: Some(ErrorKind::Note),
             msg: span.label.clone().unwrap(),
+            require_annotation: true,
         });
     }
 
     // Flatten out the children.
     for child in &diagnostic.children {
-        push_expected_errors(expected_errors, child, primary_spans, file_name);
+        push_actual_errors(errors, child, primary_spans, file_name);
     }
 }
 
 fn push_backtrace(
-    expected_errors: &mut Vec<Error>,
+    errors: &mut Vec<Error>,
     expansion: &DiagnosticSpanMacroExpansion,
     file_name: &str,
 ) {
     if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
-        expected_errors.push(Error {
+        errors.push(Error {
             line_num: Some(expansion.span.line_start),
             kind: Some(ErrorKind::Note),
             msg: format!("in this expansion of {}", expansion.macro_decl_name),
+            require_annotation: true,
         });
     }
 
     if let Some(previous_expansion) = &expansion.span.expansion {
-        push_backtrace(expected_errors, previous_expansion, file_name);
+        push_backtrace(errors, previous_expansion, file_name);
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index c8a60b68da8b2..13f3479247a23 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -810,7 +810,7 @@ impl<'test> TestCx<'test> {
         expect_help: bool,
         expect_note: bool,
     ) -> bool {
-        !actual_error.msg.is_empty()
+        actual_error.require_annotation
             && match actual_error.kind {
                 Some(ErrorKind::Help) => expect_help,
                 Some(ErrorKind::Note) => expect_note,
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index 404101abd41bf..ab76d0fc01e78 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -8,8 +8,8 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
 
 [dependencies]
 anyhow = "1.0.65"
+askama = "0.13.0"
 cargo_metadata = "0.18.1"
-rinja = "0.3.0"
 serde = { version = "1.0.147", features = ["derive"] }
 serde_json = "1.0.85"
 thiserror = "1"
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 79e90d88f4446..d6ed7261b7c87 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
 use anyhow::Error;
-use rinja::Template;
+use askama::Template;
 
 mod cargo_metadata;
 
@@ -117,7 +117,7 @@ struct Metadata {
 }
 
 /// Describes one node in our metadata tree
-#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)]
+#[derive(serde::Deserialize, Template, Clone, Debug, PartialEq, Eq)]
 #[serde(rename_all = "kebab-case", tag = "type")]
 #[template(path = "Node.html")]
 pub(crate) enum Node {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index e4c50f2ebdb44..cc02b71f05c19 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -400,6 +400,7 @@ pub enum FnAbi {
     Rust,
     RustCall,
     RustCold,
+    RustIntrinsic,
     Stdcall,
     StdcallUnwind,
     System,
@@ -456,6 +457,7 @@ impl FnAbi {
             s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
             s if *s == sym::rust_dash_call => FnAbi::RustCall,
             s if *s == sym::rust_dash_cold => FnAbi::RustCold,
+            s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
             s if *s == sym::Rust => FnAbi::Rust,
             s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
             s if *s == sym::stdcall => FnAbi::Stdcall,
@@ -498,6 +500,7 @@ impl FnAbi {
             FnAbi::Rust => "Rust",
             FnAbi::RustCall => "rust-call",
             FnAbi::RustCold => "rust-cold",
+            FnAbi::RustIntrinsic => "rust-intrinsic",
             FnAbi::Stdcall => "stdcall",
             FnAbi::StdcallUnwind => "stdcall-unwind",
             FnAbi::System => "system",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 06ac5b1ffad90..f61ecabb7e41d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -59,7 +59,19 @@ impl Evaluator<'_> {
 
         let function_data = self.db.function_data(def);
         let attrs = self.db.attrs(def.into());
-        let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists();
+        let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
+            // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
+            || (match &function_data.abi {
+                Some(abi) => *abi == sym::rust_dash_intrinsic,
+                None => match def.lookup(self.db.upcast()).container {
+                    hir_def::ItemContainerId::ExternBlockId(block) => {
+                        let id = block.lookup(self.db.upcast()).id;
+                        id.item_tree(self.db.upcast())[id.value].abi.as_ref()
+                            == Some(&sym::rust_dash_intrinsic)
+                    }
+                    _ => false,
+                },
+            });
 
         if is_intrinsic {
             return self.exec_intrinsic(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 0cfd36d9166b8..89d89fe2230af 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -18,6 +18,7 @@ use hir_def::{
     TypeOrConstParamId,
 };
 use hir_expand::name::Name;
+use intern::sym;
 use rustc_abi::TargetDataLayout;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -302,13 +303,26 @@ pub fn is_fn_unsafe_to_call(
 
     let loc = func.lookup(db.upcast());
     match loc.container {
-        hir_def::ItemContainerId::ExternBlockId(_block) => {
-            // Function in an `extern` block are always unsafe to call, except when
-            // it is marked as `safe`.
-            if data.is_safe() {
-                Unsafety::Safe
+        hir_def::ItemContainerId::ExternBlockId(block) => {
+            let id = block.lookup(db.upcast()).id;
+            let is_intrinsic_block =
+                id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
+            if is_intrinsic_block {
+                // legacy intrinsics
+                // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
+                if db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() {
+                    Unsafety::Safe
+                } else {
+                    Unsafety::Unsafe
+                }
             } else {
-                Unsafety::Unsafe
+                // Function in an `extern` block are always unsafe to call, except when
+                // it is marked as `safe`.
+                if data.is_safe() {
+                    Unsafety::Safe
+                } else {
+                    Unsafety::Unsafe
+                }
             }
         }
         _ => Unsafety::Safe,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
index a3554114f4c36..7c2cc2a6c1d8f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
@@ -36,6 +36,7 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
     "wasm",
     "system",
     "system-unwind",
+    "rust-intrinsic",
     "rust-call",
     "unadjusted",
 ];
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index d4f334289f034..6b77c72cee897 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -125,6 +125,7 @@ define_symbols! {
     riscv_dash_interrupt_dash_s = "riscv-interrupt-s",
     rust_dash_call = "rust-call",
     rust_dash_cold = "rust-cold",
+    rust_dash_intrinsic = "rust-intrinsic",
     stdcall_dash_unwind = "stdcall-unwind",
     system_dash_unwind = "system-unwind",
     sysv64_dash_unwind = "sysv64-unwind",
diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs
index a24b98050d232..6e185cf89329c 100644
--- a/tests/codegen/enum/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
@@ -1,21 +1,26 @@
 //@ compile-flags: -Copt-level=1
-//@ only-x86_64
+//@ only-64bit
 
 #![crate_type = "lib"]
+#![feature(core_intrinsics)]
 
 // Check each of the 3 cases for `codegen_get_discr`.
 
+// FIXME: once our min-bar LLVM has `range` attributes, update the various
+// tests here to no longer have the `range`s and `nsw`s as optional.
+
 // Case 0: One tagged variant.
 pub enum Enum0 {
     A(bool),
     B,
 }
 
-// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0{{.*}}
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0)
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = icmp eq i8 %0, 2
-// CHECK-NEXT: %2 = and i8 %0, 1
-// CHECK-NEXT: %{{.+}} = select i1 %1, i8 13, i8 %2
+// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2
+// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1
+// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]]
+// CHECK-NEXT: ret i8 %[[R]]
 #[no_mangle]
 pub fn match0(e: Enum0) -> u8 {
     use Enum0::*;
@@ -32,13 +37,14 @@ pub enum Enum1 {
     C,
 }
 
-// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1{{.*}}
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0)
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = add{{( nsw)?}} i8 %0, -2
-// CHECK-NEXT: %2 = zext i8 %1 to i64
-// CHECK-NEXT: %3 = icmp ult i8 %1, 2
-// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
-// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
+// CHECK-NEXT: switch i64 %[[DISCR]]
 #[no_mangle]
 pub fn match1(e: Enum1) -> u8 {
     use Enum1::*;
@@ -92,14 +98,14 @@ pub enum Enum2 {
     E,
 }
 
-// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2{{.*}}
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0)
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = add i8 %0, 2
-// CHECK-NEXT: %2 = zext i8 %1 to i64
-// CHECK-NEXT: %3 = icmp ult i8 %1, 4
-// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
-// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0
-// CHECK-NEXT: switch i64 %_2, label {{.*}} [
+// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0
+// CHECK-NEXT: switch i64 %[[DISCR]]
 #[no_mangle]
 pub fn match2(e: Enum2) -> u8 {
     use Enum2::*;
@@ -111,3 +117,357 @@ pub fn match2(e: Enum2) -> u8 {
         E => 250,
     }
 }
+
+// And make sure it works even if the niched scalar is a pointer.
+// (For example, that we don't try to `sub` on pointers.)
+
+// CHECK-LABEL: define noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null
+// CHECK-NEXT: br i1 %[[IS_NULL]]
+#[no_mangle]
+pub fn match3(e: Option<&u8>) -> i16 {
+    match e {
+        Some(r) => *r as _,
+        None => -1,
+    }
+}
+
+// If the untagged variant is in the middle, there's an impossible value that's
+// not reflected in the `range` parameter attribute, so we assume it away.
+
+#[derive(PartialEq)]
+pub enum MiddleNiche {
+    A,
+    B,
+    C(bool),
+    D,
+    E,
+}
+
+// CHECK-LABEL: define noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2
+// CHECK-NEXT: switch i8 %[[DISCR]]
+#[no_mangle]
+pub fn match4(e: MiddleNiche) -> u8 {
+    use MiddleNiche::*;
+    match e {
+        A => 13,
+        B => 100,
+        C(b) => b as u8,
+        D => 200,
+        E => 250,
+    }
+}
+
+// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e)
+// CHECK-NEXT: start
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2
+// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: ret i1 %[[NOT_NICHE]]
+#[no_mangle]
+pub fn match4_is_c(e: MiddleNiche) -> bool {
+    // Before #139098, this couldn't optimize out the `select` because it looked
+    // like it was possible for a `2` to be produced on both sides.
+
+    std::intrinsics::discriminant_value(&e) == 2
+}
+
+// You have to do something pretty obnoxious to get a variant index that doesn't
+// fit in the tag size, but it's possible
+
+pub enum Never {}
+
+pub enum HugeVariantIndex {
+    V000(Never),
+    V001(Never),
+    V002(Never),
+    V003(Never),
+    V004(Never),
+    V005(Never),
+    V006(Never),
+    V007(Never),
+    V008(Never),
+    V009(Never),
+    V010(Never),
+    V011(Never),
+    V012(Never),
+    V013(Never),
+    V014(Never),
+    V015(Never),
+    V016(Never),
+    V017(Never),
+    V018(Never),
+    V019(Never),
+    V020(Never),
+    V021(Never),
+    V022(Never),
+    V023(Never),
+    V024(Never),
+    V025(Never),
+    V026(Never),
+    V027(Never),
+    V028(Never),
+    V029(Never),
+    V030(Never),
+    V031(Never),
+    V032(Never),
+    V033(Never),
+    V034(Never),
+    V035(Never),
+    V036(Never),
+    V037(Never),
+    V038(Never),
+    V039(Never),
+    V040(Never),
+    V041(Never),
+    V042(Never),
+    V043(Never),
+    V044(Never),
+    V045(Never),
+    V046(Never),
+    V047(Never),
+    V048(Never),
+    V049(Never),
+    V050(Never),
+    V051(Never),
+    V052(Never),
+    V053(Never),
+    V054(Never),
+    V055(Never),
+    V056(Never),
+    V057(Never),
+    V058(Never),
+    V059(Never),
+    V060(Never),
+    V061(Never),
+    V062(Never),
+    V063(Never),
+    V064(Never),
+    V065(Never),
+    V066(Never),
+    V067(Never),
+    V068(Never),
+    V069(Never),
+    V070(Never),
+    V071(Never),
+    V072(Never),
+    V073(Never),
+    V074(Never),
+    V075(Never),
+    V076(Never),
+    V077(Never),
+    V078(Never),
+    V079(Never),
+    V080(Never),
+    V081(Never),
+    V082(Never),
+    V083(Never),
+    V084(Never),
+    V085(Never),
+    V086(Never),
+    V087(Never),
+    V088(Never),
+    V089(Never),
+    V090(Never),
+    V091(Never),
+    V092(Never),
+    V093(Never),
+    V094(Never),
+    V095(Never),
+    V096(Never),
+    V097(Never),
+    V098(Never),
+    V099(Never),
+    V100(Never),
+    V101(Never),
+    V102(Never),
+    V103(Never),
+    V104(Never),
+    V105(Never),
+    V106(Never),
+    V107(Never),
+    V108(Never),
+    V109(Never),
+    V110(Never),
+    V111(Never),
+    V112(Never),
+    V113(Never),
+    V114(Never),
+    V115(Never),
+    V116(Never),
+    V117(Never),
+    V118(Never),
+    V119(Never),
+    V120(Never),
+    V121(Never),
+    V122(Never),
+    V123(Never),
+    V124(Never),
+    V125(Never),
+    V126(Never),
+    V127(Never),
+    V128(Never),
+    V129(Never),
+    V130(Never),
+    V131(Never),
+    V132(Never),
+    V133(Never),
+    V134(Never),
+    V135(Never),
+    V136(Never),
+    V137(Never),
+    V138(Never),
+    V139(Never),
+    V140(Never),
+    V141(Never),
+    V142(Never),
+    V143(Never),
+    V144(Never),
+    V145(Never),
+    V146(Never),
+    V147(Never),
+    V148(Never),
+    V149(Never),
+    V150(Never),
+    V151(Never),
+    V152(Never),
+    V153(Never),
+    V154(Never),
+    V155(Never),
+    V156(Never),
+    V157(Never),
+    V158(Never),
+    V159(Never),
+    V160(Never),
+    V161(Never),
+    V162(Never),
+    V163(Never),
+    V164(Never),
+    V165(Never),
+    V166(Never),
+    V167(Never),
+    V168(Never),
+    V169(Never),
+    V170(Never),
+    V171(Never),
+    V172(Never),
+    V173(Never),
+    V174(Never),
+    V175(Never),
+    V176(Never),
+    V177(Never),
+    V178(Never),
+    V179(Never),
+    V180(Never),
+    V181(Never),
+    V182(Never),
+    V183(Never),
+    V184(Never),
+    V185(Never),
+    V186(Never),
+    V187(Never),
+    V188(Never),
+    V189(Never),
+    V190(Never),
+    V191(Never),
+    V192(Never),
+    V193(Never),
+    V194(Never),
+    V195(Never),
+    V196(Never),
+    V197(Never),
+    V198(Never),
+    V199(Never),
+    V200(Never),
+    V201(Never),
+    V202(Never),
+    V203(Never),
+    V204(Never),
+    V205(Never),
+    V206(Never),
+    V207(Never),
+    V208(Never),
+    V209(Never),
+    V210(Never),
+    V211(Never),
+    V212(Never),
+    V213(Never),
+    V214(Never),
+    V215(Never),
+    V216(Never),
+    V217(Never),
+    V218(Never),
+    V219(Never),
+    V220(Never),
+    V221(Never),
+    V222(Never),
+    V223(Never),
+    V224(Never),
+    V225(Never),
+    V226(Never),
+    V227(Never),
+    V228(Never),
+    V229(Never),
+    V230(Never),
+    V231(Never),
+    V232(Never),
+    V233(Never),
+    V234(Never),
+    V235(Never),
+    V236(Never),
+    V237(Never),
+    V238(Never),
+    V239(Never),
+    V240(Never),
+    V241(Never),
+    V242(Never),
+    V243(Never),
+    V244(Never),
+    V245(Never),
+    V246(Never),
+    V247(Never),
+    V248(Never),
+    V249(Never),
+    V250(Never),
+    V251(Never),
+    V252(Never),
+    V253(Never),
+    V254(Never),
+    V255(Never),
+    V256(Never),
+
+    Possible257,
+    Bool258(bool),
+    Possible259,
+}
+
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
+// CHECK-NEXT: start:
+// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
+// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
+// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3
+// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1
+// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]])
+// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257
+// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258
+// CHECK-NEXT: switch i64 %[[DISCR]],
+// CHECK-NEXT:   i64 257,
+// CHECK-NEXT:   i64 258,
+// CHECK-NEXT:   i64 259,
+#[no_mangle]
+pub fn match5(e: HugeVariantIndex) -> u8 {
+    use HugeVariantIndex::*;
+    match e {
+        Possible257 => 13,
+        Bool258(b) => b as u8,
+        Possible259 => 100,
+    }
+}
diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs
index 21ae1f96bca7a..12d9edc4d6234 100644
--- a/tests/codegen/enum/enum-two-variants-match.rs
+++ b/tests/codegen/enum/enum-two-variants-match.rs
@@ -1,8 +1,12 @@
 //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
-//@ only-x86_64 (because these discriminants are isize)
+//@ only-64bit (because these discriminants are isize)
 
 #![crate_type = "lib"]
 
+// This directly tests what we emit for these matches, rather than what happens
+// after optimization, so it doesn't need to worry about extra flags on the
+// instructions and is less susceptible to being broken on LLVM updates.
+
 // CHECK-LABEL: @option_match
 #[no_mangle]
 pub fn option_match(x: Option<i32>) -> u16 {
@@ -51,3 +55,76 @@ pub fn result_match(x: Result<u64, i64>) -> u16 {
         Ok(_) => 42,
     }
 }
+
+// CHECK-LABEL: @option_bool_match(
+#[no_mangle]
+pub fn option_bool_match(x: Option<bool>) -> char {
+    // CHECK: %[[RAW:.+]] = load i8, ptr %x
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: %[[FIELD:.+]] = load i8, ptr %x
+    // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1
+    // CHECK: br i1 %[[FIELD_T]]
+    match x {
+        None => 'n',
+        Some(false) => 'f',
+        Some(true) => 't',
+    }
+}
+
+use std::cmp::Ordering::{self, *};
+// CHECK-LABEL: @option_ordering_match(
+#[no_mangle]
+pub fn option_ordering_match(x: Option<Ordering>) -> char {
+    // CHECK: %[[RAW:.+]] = load i8, ptr %x
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: %[[FIELD:.+]] = load i8, ptr %x
+    // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [
+    // CHECK-NEXT: i8 -1, label
+    // CHECK-NEXT: i8 0, label
+    // CHECK-NEXT: i8 1, label
+    // CHECK-NEXT: ]
+
+    // CHECK: [[UNREACHABLE]]:
+    // CHECK-NEXT: unreachable
+    match x {
+        None => '?',
+        Some(Less) => '<',
+        Some(Equal) => '=',
+        Some(Greater) => '>',
+    }
+}
+
+// CHECK-LABEL: @option_nonzero_match(
+#[no_mangle]
+pub fn option_nonzero_match(x: Option<std::num::NonZero<u16>>) -> u16 {
+    // CHECK: %[[OUT:.+]] = alloca [2 x i8]
+
+    // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0
+    // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1
+    // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1
+    // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]]
+
+    // CHECK: [[BB_SOME]]:
+    // CHECK: store i16 987, ptr %[[OUT]]
+
+    // CHECK: [[BB_NONE]]:
+    // CHECK: store i16 123, ptr %[[OUT]]
+
+    // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]]
+    // CHECK: ret i16 %[[RET]]
+
+    match x {
+        None => 123,
+        Some(_) => 987,
+    }
+}
diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs
index c7b5b931fbbec..bd3b109b62c75 100644
--- a/tests/incremental/circular-dependencies.rs
+++ b/tests/incremental/circular-dependencies.rs
@@ -15,6 +15,7 @@ pub struct Foo;
 
 pub fn consume_foo(_: Foo) {}
 //[cfail2]~^ NOTE function defined here
+//[cfail2]~| NOTE
 
 pub fn produce_foo() -> Foo {
     Foo
diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs
index 36295a84e7ad7..bc181de8d925d 100644
--- a/tests/ui/async-await/issue-70818.rs
+++ b/tests/ui/async-await/issue-70818.rs
@@ -2,7 +2,7 @@
 
 use std::future::Future;
 fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
-    //~^ Error future cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
     async { (ty, ty1) }
 }
 
diff --git a/tests/ui/async-await/issue-71137.rs b/tests/ui/async-await/issue-71137.rs
index 551cf85047cae..6fbf17ccf0d04 100644
--- a/tests/ui/async-await/issue-71137.rs
+++ b/tests/ui/async-await/issue-71137.rs
@@ -19,5 +19,5 @@ async fn wrong_mutex() {
 }
 
 fn main() {
-  fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely
+  fake_spawn(wrong_mutex()); //~ ERROR future cannot be sent between threads safely
 }
diff --git a/tests/ui/compiletest-self-test/env-trim-name.rs b/tests/ui/compiletest-self-test/env-trim-name.rs
new file mode 100644
index 0000000000000..f2da3db394110
--- /dev/null
+++ b/tests/ui/compiletest-self-test/env-trim-name.rs
@@ -0,0 +1,15 @@
+//@ edition: 2024
+//@ run-pass
+//@ rustc-env: MY_RUSTC_ENV = my-rustc-value
+//@ exec-env: MY_EXEC_ENV = my-exec-value
+
+// Check that compiletest trims whitespace from environment variable names
+// specified in `rustc-env` and `exec-env` directives, so that
+// `//@ exec-env: FOO=bar` sees the name as `FOO` and not ` FOO`.
+//
+// Values are currently not trimmed.
+
+fn main() {
+    assert_eq!(option_env!("MY_RUSTC_ENV"), Some(" my-rustc-value"));
+    assert_eq!(std::env::var("MY_EXEC_ENV").as_deref(), Ok(" my-exec-value"));
+}
diff --git a/tests/ui/const-generics/defaults/mismatch.rs b/tests/ui/const-generics/defaults/mismatch.rs
index ec131505ed755..3e35c2060b1e0 100644
--- a/tests/ui/const-generics/defaults/mismatch.rs
+++ b/tests/ui/const-generics/defaults/mismatch.rs
@@ -5,18 +5,18 @@ pub struct Example4<const N: usize = 13, const M: usize = 4>;
 
 fn main() {
     let e: Example<13> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example`
     let e: Example2<u32, 13> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example2`
     let e: Example3<13, u32> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example3`
     let e: Example3<7> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example3<7>`
     let e: Example4<7> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example4<7>`
 }
diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
index 6c4ee1af210ba..e7f050dae3671 100644
--- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
+++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
@@ -13,7 +13,7 @@ trait Foo {
         [Adt; std::mem::size_of::<Self::Assoc>()]: ,
     {
         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
-        //~^ Error: the trait bound
+        //~^ ERROR the trait bound
     }
 
     fn bar() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
index 7561ae2febbdf..33872ce7f0f26 100644
--- a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
+++ b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
@@ -15,15 +15,15 @@ where
 
     // errors are bad but seems to be pre-existing issue #86198
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     assert_impl::<HasCastInTraitImpl<14, 13>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
 }
 pub fn use_trait_impl_2<const N: usize>()
 where
@@ -33,15 +33,15 @@ where
 
     // errors are bad but seems to be pre-existing issue #86198
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     assert_impl::<HasCastInTraitImpl<14, 13>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
index c3208786708b5..ea65b6d3fdf26 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
@@ -9,8 +9,8 @@ pub trait True {}
 
 impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
     Condition<{ LHS <= RHS }>: True
-//[min]~^ Error generic parameters may not be used in const operations
-//[min]~| Error generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
 {
 }
 impl True for Condition<true> {}
@@ -21,8 +21,8 @@ where
     IsLessOrEqual<I, 8>: True,
     IsLessOrEqual<J, 8>: True,
     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-//[min]~^ Error generic parameters may not be used in const operations
-//[min]~| Error generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
     // Condition<{ 8 - I <= 8 - J }>: True,
 {
     fn print() {
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
index 2fa9a71fbb33c..f08b9ceffb966 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
@@ -14,7 +14,7 @@ trait Foo {
         [(); std::mem::size_of::<Self::Assoc>()]: ,
     {
         Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
-        //~^ Error: mismatched types
+        //~^ ERROR mismatched types
     }
 }
 
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index 39e5f732a8985..6478bf9c6ee1c 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -93,6 +93,7 @@ fn main() {
     //~| NOTE constant of non-structural type
 
     trait Trait: Sized { const ASSOC: Option<Self>; } //~ NOTE constant defined here
+                                                      //~^ NOTE
     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
     //~^ ERROR constant of non-structural type `NoDerive` in a pattern
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index fa16d0b06a7fe..bf54d3d76aed3 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -118,14 +118,14 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: constant of non-structural type `NoDerive` in a pattern
-  --> $DIR/reject_non_structural.rs:97:28
+  --> $DIR/reject_non_structural.rs:98:28
    |
 LL | struct NoDerive;
    | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
 ...
 LL |     trait Trait: Sized { const ASSOC: Option<Self>; }
    |     ------------------   ------------------------- constant defined here
-LL |     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
+...
 LL |     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
    |                            ^^^^^^^^^^^^^^^ constant of non-structural type
    |
@@ -136,7 +136,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: constant of non-structural type `NoDerive` in a pattern
-  --> $DIR/reject_non_structural.rs:102:28
+  --> $DIR/reject_non_structural.rs:103:28
    |
 LL | struct NoDerive;
    | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
@@ -153,7 +153,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: constant of non-structural type `NoDerive` in a pattern
-  --> $DIR/reject_non_structural.rs:107:29
+  --> $DIR/reject_non_structural.rs:108:29
    |
 LL | struct NoDerive;
    | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.rs b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs
new file mode 100644
index 0000000000000..0badb738809e9
--- /dev/null
+++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs
@@ -0,0 +1,12 @@
+#![feature(trait_alias)]
+trait B = Fn() -> Self;
+type D = &'static dyn B;
+//~^ ERROR E0411
+
+fn a() -> D {
+    unreachable!();
+}
+
+fn main() {
+    _ = a();
+}
diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr
new file mode 100644
index 0000000000000..dccee02e9cd18
--- /dev/null
+++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr
@@ -0,0 +1,9 @@
+error[E0411]: `Self` is not allowed in type aliases
+  --> $DIR/trait-alias-self-projection.rs:3:19
+   |
+LL | type D = &'static dyn B;
+   |                   ^^^^^ `Self` is only available in impls, traits, and concrete type definitions
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0411`.
diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs
index 2ab2bf95448a4..eebca29d6c933 100644
--- a/tests/ui/fn/param-mismatch-foreign.rs
+++ b/tests/ui/fn/param-mismatch-foreign.rs
@@ -1,6 +1,7 @@
 extern "C" {
     fn foo(x: i32, y: u32, z: i32);
     //~^ NOTE function defined here
+    //~| NOTE
 }
 
 fn main() {
diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr
index 835e0a3343e9a..fff3283cbb6ce 100644
--- a/tests/ui/fn/param-mismatch-foreign.stderr
+++ b/tests/ui/fn/param-mismatch-foreign.stderr
@@ -1,5 +1,5 @@
 error[E0061]: this function takes 3 arguments but 2 arguments were supplied
-  --> $DIR/param-mismatch-foreign.rs:7:5
+  --> $DIR/param-mismatch-foreign.rs:8:5
    |
 LL |     foo(1i32, 2i32);
    |     ^^^       ---- argument #2 of type `u32` is missing
diff --git a/tests/ui/impl-trait/impl-generic-mismatch.rs b/tests/ui/impl-trait/impl-generic-mismatch.rs
index fb8bde0d08131..f05e01716c312 100644
--- a/tests/ui/impl-trait/impl-generic-mismatch.rs
+++ b/tests/ui/impl-trait/impl-generic-mismatch.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for () {
     fn foo<U: Debug>(&self, _: &U) { }
-    //~^ Error method `foo` has incompatible signature for trait
+    //~^ ERROR method `foo` has incompatible signature for trait
 }
 
 trait Bar {
@@ -15,7 +15,7 @@ trait Bar {
 
 impl Bar for () {
     fn bar(&self, _: &impl Debug) { }
-    //~^ Error method `bar` has incompatible signature for trait
+    //~^ ERROR method `bar` has incompatible signature for trait
 }
 
 trait Baz {
@@ -24,7 +24,7 @@ trait Baz {
 
 impl Baz for () {
     fn baz<T: Debug>(&self, _: &impl Debug, _: &T) { }
-    //~^ Error method `baz` has incompatible signature for trait
+    //~^ ERROR method `baz` has incompatible signature for trait
 }
 
 // With non-local trait (#49841):
@@ -35,7 +35,7 @@ struct X;
 
 impl Hash for X {
     fn hash(&self, hasher: &mut impl Hasher) {}
-    //~^ Error method `hash` has incompatible signature for trait
+    //~^ ERROR method `hash` has incompatible signature for trait
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
new file mode 100644
index 0000000000000..42dbc7c91607f
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
@@ -0,0 +1,56 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive-in-exhaustiveness.rs:17:1
+   |
+LL | fn build<T>(x: T) -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     let (x,) = (build(x),);
+   |                 -------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+warning: function cannot return without recursing
+  --> $DIR/recursive-in-exhaustiveness.rs:27:1
+   |
+LL | fn build2<T>(x: T) -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |     let (x,) = (build2(x),);
+   |                 --------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-in-exhaustiveness.rs:27:23
+   |
+LL | fn build2<T>(x: T) -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+...
+LL |     (build2(x),)
+   |     ------------ returning here with type `(impl Sized,)`
+
+warning: function cannot return without recursing
+  --> $DIR/recursive-in-exhaustiveness.rs:40:1
+   |
+LL | fn build3<T>(x: T) -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     let (x,) = (build3((x,)),);
+   |                 ------------ recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error[E0792]: expected generic type parameter, found `(T,)`
+  --> $DIR/recursive-in-exhaustiveness.rs:49:5
+   |
+LL | fn build3<T>(x: T) -> impl Sized {
+   |           - this generic parameter must be used with a generic type parameter
+...
+LL |     build3(x)
+   |     ^^^^^^^^^
+
+error: aborting due to 2 previous errors; 3 warnings emitted
+
+Some errors have detailed explanations: E0720, E0792.
+For more information about an error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
new file mode 100644
index 0000000000000..4c3d5aa8fb8f0
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -0,0 +1,80 @@
+error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
+  --> $DIR/recursive-in-exhaustiveness.rs:19:17
+   |
+LL |     let (x,) = (build(x),);
+   |                 ^^^^^^^^ cannot satisfy `impl Sized == _`
+
+error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:31:6
+   |
+LL |     (build2(x),)
+   |      ^^^^^^^^^ types differ
+
+error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:31:5
+   |
+LL |     (build2(x),)
+   |     ^^^^^^^^^^^^ types differ
+
+error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
+  --> $DIR/recursive-in-exhaustiveness.rs:31:5
+   |
+LL |     (build2(x),)
+   |     ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(impl Sized,)`
+   = note: tuples must have a statically known size to be initialized
+
+error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+   |
+LL |     let (x,) = (build3((x,)),);
+   |                 ^^^^^^^^^^^^ types differ
+
+error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
+  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+   |
+LL |     let (x,) = (build3((x,)),);
+   |                ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(impl Sized,)`
+   = note: tuples must have a statically known size to be initialized
+
+error[E0308]: mismatched types
+  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+   |
+LL | fn build3<T>(x: T) -> impl Sized {
+   |                       ---------- the found opaque type
+LL |
+LL |     let (x,) = (build3((x,)),);
+   |                ^^^^^^^^^^^^^^^ types differ
+   |
+   = note: expected type `_`
+             found tuple `(impl Sized,)`
+
+error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+   |
+LL |     let (x,) = (build3((x,)),);
+   |                 ^^^^^^^^^^^^ types differ
+   |
+   = note: the return type of a function must have a statically known size
+
+error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+   |
+LL |     let (x,) = (build3((x,)),);
+   |                ^^^^^^^^^^^^^^^ types differ
+
+error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
+  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+   |
+LL |     let (x,) = (build3((x,)),);
+   |                 ^^^^^^^^^^^^ types differ
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0271, E0277, E0284, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
new file mode 100644
index 0000000000000..58944533686cc
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
@@ -0,0 +1,53 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Test several spicy non-trivial recursive opaque definitions inferred from HIR typeck
+// don't cause stack overflows in exhaustiveness code, which currently reveals opaques
+// manually in a way that is not overflow aware.
+//
+// These should eventually be outright rejected, but today (some) non-trivial recursive
+// opaque definitions are accepted, and changing that requires an FCP, so for now just
+// make sure we don't stack overflow :^)
+
+// Opaque<T> = Opaque<Opaque<T>>
+//
+// We unfortunately accept this today, and due to how opaque type relating is implemented
+// in the NLL type relation, this defines `Opaque<T> = T`.
+fn build<T>(x: T) -> impl Sized {
+    //[current]~^ WARN function cannot return without recursing
+    let (x,) = (build(x),);
+    //[next]~^ ERROR type annotations needed
+    build(x)
+}
+
+// Opaque<T> = (Opaque<T>,)
+//
+// Not allowed today. Detected as recursive.
+fn build2<T>(x: T) -> impl Sized {
+    //[current]~^ ERROR cannot resolve opaque type
+    //[current]~| WARN function cannot return without recursing
+    let (x,) = (build2(x),);
+    (build2(x),)
+    //[next]~^ ERROR type mismatch resolving
+    //[next]~| ERROR type mismatch resolving
+    //[next]~| ERROR the size for values of type
+}
+
+// Opaque<T> = Opaque<(T,)>
+//
+// Not allowed today. Detected as not defining.
+fn build3<T>(x: T) -> impl Sized {
+    //[current]~^ WARN function cannot return without recursing
+    let (x,) = (build3((x,)),);
+    //[next]~^ ERROR type mismatch resolving
+    //[next]~| ERROR type mismatch resolving
+    //[next]~| ERROR type mismatch resolving
+    //[next]~| ERROR type mismatch resolving
+    //[next]~| ERROR the size for values of type
+    //[next]~| ERROR mismatched types
+    build3(x)
+    //[current]~^ ERROR expected generic type parameter, found `(T,)`
+}
+
+fn main() {}
diff --git a/tests/ui/implied-bounds/overflow.rs b/tests/ui/implied-bounds/overflow.rs
new file mode 100644
index 0000000000000..7c36998dd4d3b
--- /dev/null
+++ b/tests/ui/implied-bounds/overflow.rs
@@ -0,0 +1,11 @@
+trait Tailed<'a>: 'a {
+    type Tail: Tailed<'a>;
+}
+
+struct List<'a, T: Tailed<'a>> {
+    //~^ ERROR overflow computing implied lifetime bounds for `List`
+    next: Box<List<'a, T::Tail>>,
+    node: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/implied-bounds/overflow.stderr b/tests/ui/implied-bounds/overflow.stderr
new file mode 100644
index 0000000000000..2e5a9ab141cf8
--- /dev/null
+++ b/tests/ui/implied-bounds/overflow.stderr
@@ -0,0 +1,8 @@
+error: overflow computing implied lifetime bounds for `List`
+  --> $DIR/overflow.rs:5:1
+   |
+LL | struct List<'a, T: Tailed<'a>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
index 21df464d5e450..04a379bbd0484 100644
--- a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
+++ b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
@@ -3,5 +3,5 @@ struct Foo;
 fn main() {
   let mut a = Foo;
   let ref b = Foo;
-  a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo`
+  a += *b; //~ ERROR binary assignment operation `+=` cannot be applied to type `Foo`
 }
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs
index a58fe68b86381..b20ca80ac0717 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.rs
+++ b/tests/ui/mismatched_types/similar_paths_primitive.rs
@@ -4,8 +4,9 @@ struct bool; //~ NOTE the other `bool` is defined in the current crate
 struct str; //~ NOTE the other `str` is defined in the current crate
 
 fn foo(_: bool) {} //~ NOTE function defined here
+                   //~^ NOTE
 fn bar(_: &str) {} //~ NOTE function defined here
-
+                   //~^ NOTE
 fn main() {
     foo(true);
     //~^ ERROR mismatched types [E0308]
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr
index cf26234dba857..9c1aa0d7105b6 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.stderr
+++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/similar_paths_primitive.rs:10:9
+  --> $DIR/similar_paths_primitive.rs:11:9
    |
 LL |     foo(true);
    |     --- ^^^^ expected `bool`, found a different `bool`
@@ -20,7 +20,7 @@ LL | fn foo(_: bool) {}
    |    ^^^ -------
 
 error[E0308]: mismatched types
-  --> $DIR/similar_paths_primitive.rs:16:9
+  --> $DIR/similar_paths_primitive.rs:17:9
    |
 LL |     bar("hello");
    |     --- ^^^^^^^ expected `str`, found a different `str`
@@ -35,7 +35,7 @@ note: the other `str` is defined in the current crate
 LL | struct str;
    | ^^^^^^^^^^
 note: function defined here
-  --> $DIR/similar_paths_primitive.rs:7:4
+  --> $DIR/similar_paths_primitive.rs:8:4
    |
 LL | fn bar(_: &str) {}
    |    ^^^ -------
diff --git a/tests/ui/modules/issue-107649.rs b/tests/ui/modules/issue-107649.rs
index af5758d798588..f93fb07e17af0 100644
--- a/tests/ui/modules/issue-107649.rs
+++ b/tests/ui/modules/issue-107649.rs
@@ -102,5 +102,5 @@ fn main() {
     ();
     ();
     ();
-    dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug`
+    dbg!(lib::Dummy); //~ ERROR `Dummy` doesn't implement `Debug`
 }
diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs
index 0235b291df540..87800d314ed50 100644
--- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs
+++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs
@@ -9,6 +9,8 @@ fn foo() {
     //~| NOTE inside of this loop
     //~| HELP consider moving the expression out of the loop
     //~| NOTE in this expansion of desugaring of `for` loop
+    //~| NOTE
+    //~| NOTE
         baz.push(foo);
         //~^ NOTE value moved here
         //~| HELP consider cloning the value
@@ -30,17 +32,19 @@ fn main() {
     for foo in foos {
     //~^ NOTE this reinitialization might get skipped
     //~| NOTE move occurs because `foo` has type `String`
+    //~| NOTE
         for bar in &bars {
         //~^ NOTE inside of this loop
         //~| HELP consider moving the expression out of the loop
         //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE
             if foo == *bar {
                 baz.push(foo);
                 //~^ NOTE value moved here
                 //~| HELP consider cloning the value
                 continue;
                 //~^ NOTE verify that your loop breaking logic is correct
-                //~| NOTE this `continue` advances the loop at line 33
+                //~| NOTE this `continue` advances the loop at line 36
             }
         }
         qux.push(foo);
diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr
index cf863ff8af148..6ef1a4193b1ae 100644
--- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr
+++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `foo`
-  --> $DIR/nested-loop-moved-value-wrong-continue.rs:19:14
+  --> $DIR/nested-loop-moved-value-wrong-continue.rs:21:14
    |
 LL |     for foo in foos { for bar in &bars { if foo == *bar {
    |         ---           ---------------- inside of this loop
@@ -14,13 +14,13 @@ LL |     qux.push(foo);
    |              ^^^ value used here after move
    |
 note: verify that your loop breaking logic is correct
-  --> $DIR/nested-loop-moved-value-wrong-continue.rs:15:9
+  --> $DIR/nested-loop-moved-value-wrong-continue.rs:17:9
    |
 LL |     for foo in foos { for bar in &bars { if foo == *bar {
    |     ---------------   ----------------
 ...
 LL |         continue;
-   |         ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 18:8
+   |         ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 20:8
 help: consider moving the expression out of the loop so it is only moved once
    |
 LL ~     for foo in foos { let mut value = baz.push(foo);
@@ -36,7 +36,7 @@ LL |         baz.push(foo.clone());
    |                     ++++++++
 
 error[E0382]: use of moved value: `foo`
-  --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18
+  --> $DIR/nested-loop-moved-value-wrong-continue.rs:50:18
    |
 LL |     for foo in foos {
    |         ---
@@ -54,7 +54,7 @@ LL |         qux.push(foo);
    |                  ^^^ value used here after move
    |
 note: verify that your loop breaking logic is correct
-  --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17
+  --> $DIR/nested-loop-moved-value-wrong-continue.rs:45:17
    |
 LL |     for foo in foos {
    |     ---------------
@@ -63,7 +63,7 @@ LL |         for bar in &bars {
    |         ----------------
 ...
 LL |                 continue;
-   |                 ^^^^^^^^ this `continue` advances the loop at line 33
+   |                 ^^^^^^^^ this `continue` advances the loop at line 36
 help: consider moving the expression out of the loop so it is only moved once
    |
 LL ~         let mut value = baz.push(foo);
diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
index b23cb9ce917be..73d173022f6ac 100644
--- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
+++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
@@ -10,7 +10,7 @@ pub fn a() {
 
 #[export_name="fail"]
 pub fn b() {
-//~^ Error symbol `fail` is already defined
+//~^ ERROR symbol `fail` is already defined
 }
 
 fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
index e6235b1e8923f..c137e13633595 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
@@ -10,5 +10,6 @@ const async const fn test() {}
 //~| ERROR functions cannot be both `const` and `async`
 //~| NOTE `const` because of this
 //~| NOTE `async` because of this
+//~| NOTE
 
 fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
index 40f993eafbb1e..49a49d337c477 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
@@ -15,5 +15,6 @@ async unsafe const fn test() {}
 //~| ERROR functions cannot be both `const` and `async`
 //~| NOTE `const` because of this
 //~| NOTE `async` because of this
+//~| NOTE
 
 fn main() {}
diff --git a/tests/ui/proc-macro/issue-91800.rs b/tests/ui/proc-macro/issue-91800.rs
index bc78bcacfd0f7..8cecfad32b55b 100644
--- a/tests/ui/proc-macro/issue-91800.rs
+++ b/tests/ui/proc-macro/issue-91800.rs
@@ -6,11 +6,14 @@ extern crate issue_91800_macro;
 #[derive(MyTrait)]
 //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
 //~| ERROR proc-macro derive produced unparsable tokens
+//~| ERROR
 #[attribute_macro]
 //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
+//~| ERROR
 struct MyStruct;
 
 fn_macro! {}
 //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
+//~| ERROR
 
 fn main() {}
diff --git a/tests/ui/proc-macro/issue-91800.stderr b/tests/ui/proc-macro/issue-91800.stderr
index d831d62e919d2..63ebc0a552e33 100644
--- a/tests/ui/proc-macro/issue-91800.stderr
+++ b/tests/ui/proc-macro/issue-91800.stderr
@@ -21,7 +21,7 @@ LL | #[derive(MyTrait)]
    = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: macros that expand to items must be delimited with braces or followed by a semicolon
-  --> $DIR/issue-91800.rs:9:1
+  --> $DIR/issue-91800.rs:10:1
    |
 LL | #[attribute_macro]
    | ^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL | #[attribute_macro]
    = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: 
-  --> $DIR/issue-91800.rs:9:1
+  --> $DIR/issue-91800.rs:10:1
    |
 LL | #[attribute_macro]
    | ^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | #[attribute_macro]
    = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: macros that expand to items must be delimited with braces or followed by a semicolon
-  --> $DIR/issue-91800.rs:13:1
+  --> $DIR/issue-91800.rs:15:1
    |
 LL | fn_macro! {}
    | ^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | fn_macro! {}
    = note: this error originates in the macro `fn_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: 
-  --> $DIR/issue-91800.rs:13:1
+  --> $DIR/issue-91800.rs:15:1
    |
 LL | fn_macro! {}
    | ^^^^^^^^^^^^
diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
index ecd3f58811904..7216b0294dcec 100644
--- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
+++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
@@ -4,15 +4,15 @@ struct A {
 
 impl A {
     fn new(cofig: String) -> Self {
-        Self { config } //~ Error cannot find value `config` in this scope
+        Self { config } //~ ERROR cannot find value `config` in this scope
     }
 
     fn do_something(cofig: String) {
-        println!("{config}"); //~ Error cannot find value `config` in this scope
+        println!("{config}"); //~ ERROR cannot find value `config` in this scope
     }
 
     fn self_is_available(self, cofig: String) {
-        println!("{config}"); //~ Error cannot find value `config` in this scope
+        println!("{config}"); //~ ERROR cannot find value `config` in this scope
     }
 }
 
diff --git a/tests/ui/structs/default-field-values/failures.rs b/tests/ui/structs/default-field-values/failures.rs
index 1e94eecb4f870..4461302e841d0 100644
--- a/tests/ui/structs/default-field-values/failures.rs
+++ b/tests/ui/structs/default-field-values/failures.rs
@@ -1,4 +1,4 @@
-#![feature(default_field_values)]
+ #![feature(default_field_values)]
 
 #[derive(Debug)]
 pub struct S;
@@ -50,7 +50,8 @@ enum E {
 fn main () {
     let _ = Foo { .. }; // ok
     let _ = Foo::default(); // ok
-    let _ = Bar { .. }; //~ ERROR mandatory field
+    let _ = Bar { .. }; //~ ERROR missing field
+    let _ = Bar { baz: 0, .. }; //~ ERROR missing field
     let _ = Bar::default(); // silenced
     let _ = Bar { bar: S, .. }; // ok
     let _ = Qux::<4> { .. };
diff --git a/tests/ui/structs/default-field-values/failures.stderr b/tests/ui/structs/default-field-values/failures.stderr
index 58f7baee4b284..21c9bfb44b435 100644
--- a/tests/ui/structs/default-field-values/failures.stderr
+++ b/tests/ui/structs/default-field-values/failures.stderr
@@ -27,14 +27,20 @@ LL + #[derive(Default)]
 LL | pub struct S;
    |
 
-error: missing mandatory field `bar`
-  --> $DIR/failures.rs:53:21
+error: missing field `bar` in initializer
+  --> $DIR/failures.rs:53:19
    |
 LL |     let _ = Bar { .. };
-   |                     ^
+   |                   ^ fields that do not have a defaulted value must be provided explicitly
+
+error: missing field `bar` in initializer
+  --> $DIR/failures.rs:54:27
+   |
+LL |     let _ = Bar { baz: 0, .. };
+   |                           ^ fields that do not have a defaulted value must be provided explicitly
 
 error[E0308]: mismatched types
-  --> $DIR/failures.rs:57:17
+  --> $DIR/failures.rs:58:17
    |
 LL |     let _ = Rak(..);
    |             --- ^^ expected `i32`, found `RangeFull`
@@ -47,19 +53,19 @@ note: tuple struct defined here
 LL | pub struct Rak(i32 = 42);
    |            ^^^
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:57:17
+  --> $DIR/failures.rs:58:17
    |
 LL |     let _ = Rak(..);
    |                 ^^
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/failures.rs:59:13
+  --> $DIR/failures.rs:60:13
    |
 LL |     let _ = Rak(0, ..);
    |             ^^^    -- unexpected argument #2 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:59:20
+  --> $DIR/failures.rs:60:20
    |
 LL |     let _ = Rak(0, ..);
    |                    ^^
@@ -75,13 +81,13 @@ LL +     let _ = Rak(0);
    |
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/failures.rs:61:13
+  --> $DIR/failures.rs:62:13
    |
 LL |     let _ = Rak(.., 0);
    |             ^^^ -- unexpected argument #1 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:61:17
+  --> $DIR/failures.rs:62:17
    |
 LL |     let _ = Rak(.., 0);
    |                 ^^
@@ -96,7 +102,7 @@ LL -     let _ = Rak(.., 0);
 LL +     let _ = Rak(0);
    |
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0061, E0277, E0308.
 For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs
index f679640c5dc90..d8b06d663affc 100644
--- a/tests/ui/suggestions/issue-103646.rs
+++ b/tests/ui/suggestions/issue-103646.rs
@@ -5,7 +5,7 @@ trait Cat {
 fn uwu<T: Cat>(c: T) {
     c.nya();
     //~^ ERROR no method named `nya` found for type parameter `T` in the current scope
-    //~| Suggestion T::nya()
+    //~| SUGGESTION T::nya()
 }
 
 fn main() {}
diff --git a/tests/ui/traits/dyn-drop-principal-with-projections.rs b/tests/ui/traits/dyn-drop-principal-with-projections.rs
new file mode 100644
index 0000000000000..912061847c69f
--- /dev/null
+++ b/tests/ui/traits/dyn-drop-principal-with-projections.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+trait Tr {
+    type Assoc;
+}
+
+impl Tr for () {
+    type Assoc = ();
+}
+
+fn main() {
+    let x = &() as &(dyn Tr<Assoc = ()> + Send) as &dyn Send;
+}
diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs
new file mode 100644
index 0000000000000..74c23a59bee9e
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs
@@ -0,0 +1,18 @@
+// Make sure not to construct predicates with escaping bound vars in `diagnostic_hir_wf_check`.
+// Regression test for <https://github.com/rust-lang/rust/issues/139330>.
+
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+trait A<T: ?Sized> {}
+impl<T: ?Sized> A<T> for () {}
+
+trait B {}
+struct W<T: B>(T);
+
+fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
+//~^ ERROR the trait bound `(): B` is not satisfied
+//~| ERROR the trait bound `(): B` is not satisfied
+//~| ERROR the trait bound `(): B` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr
new file mode 100644
index 0000000000000..df99f4a67abb2
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr
@@ -0,0 +1,65 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/diagnostic-hir-wf-check.rs:4:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `(): B` is not satisfied
+  --> $DIR/diagnostic-hir-wf-check.rs:13:12
+   |
+LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
+   |            ^^^^^ the trait `B` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+   |
+LL | trait B {}
+   | ^^^^^^^
+note: required by a bound in `W`
+  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+   |
+LL | struct W<T: B>(T);
+   |             ^ required by this bound in `W`
+
+error[E0277]: the trait bound `(): B` is not satisfied
+  --> $DIR/diagnostic-hir-wf-check.rs:13:42
+   |
+LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
+   |                                        - ^^ the trait `B` is not implemented for `()`
+   |                                        |
+   |                                        required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+   |
+LL | trait B {}
+   | ^^^^^^^
+note: required by a bound in `W`
+  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+   |
+LL | struct W<T: B>(T);
+   |             ^ required by this bound in `W`
+
+error[E0277]: the trait bound `(): B` is not satisfied
+  --> $DIR/diagnostic-hir-wf-check.rs:13:40
+   |
+LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
+   |                                        ^^^^^ the trait `B` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+   |
+LL | trait B {}
+   | ^^^^^^^
+note: required by a bound in `W`
+  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+   |
+LL | struct W<T: B>(T);
+   |             ^ required by this bound in `W`
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/issue-53598.rs b/tests/ui/type-alias-impl-trait/issue-53598.rs
index 3262c69cf5a4e..d8eee3218ed39 100644
--- a/tests/ui/type-alias-impl-trait/issue-53598.rs
+++ b/tests/ui/type-alias-impl-trait/issue-53598.rs
@@ -17,7 +17,7 @@ impl Foo for S2 {
     type Item = impl Debug;
 
     fn foo<T: Debug>(_: T) -> Self::Item {
-        //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
         S::<T>(Default::default())
     }
 }