about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml9
-rw-r--r--compiler/rustc_abi/src/layout.rs82
-rw-r--r--compiler/rustc_abi/src/lib.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs2
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_lint/src/unused.rs4
-rw-r--r--compiler/rustc_metadata/src/creader.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs29
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs11
-rw-r--r--compiler/rustc_resolve/src/lib.rs12
-rw-r--r--compiler/rustc_span/src/lib.rs82
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--library/core/src/panic/location.rs42
-rw-r--r--library/core/src/str/pattern.rs19
-rw-r--r--library/coretests/tests/panic/location.rs43
-rw-r--r--library/coretests/tests/panic/location/file_a.rs15
-rw-r--r--library/coretests/tests/panic/location/file_b.rs15
-rw-r--r--library/coretests/tests/panic/location/file_c.rs11
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile4
-rw-r--r--src/ci/github-actions/jobs.yml13
-rwxr-xr-xsrc/ci/scripts/free-disk-space-linux.sh265
-rw-r--r--src/ci/scripts/free-disk-space-windows.ps135
-rwxr-xr-xsrc/ci/scripts/free-disk-space.sh268
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md13
-rw-r--r--src/doc/rustdoc/src/unstable-features.md6
-rw-r--r--src/librustdoc/doctest.rs84
-rw-r--r--src/librustdoc/doctest/runner.rs11
-rw-r--r--src/librustdoc/formats/cache.rs30
-rw-r--r--src/tools/compiletest/src/directives.rs478
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs41
-rw-r--r--src/tools/compiletest/src/directives/directive_names.rs289
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs8
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/tidy/src/deps.rs51
-rw-r--r--src/tools/tidy/src/style.rs7
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs61
-rw-r--r--tests/assembly-llvm/nvptx-safe-naming.rs6
-rw-r--r--tests/assembly-llvm/x86-return-float.rs6
-rw-r--r--tests/codegen-llvm/abi-efiapi.rs10
-rw-r--r--tests/codegen-llvm/cast-target-abi.rs2
-rw-r--r--tests/codegen-llvm/cf-protection.rs2
-rw-r--r--tests/codegen-llvm/codemodels.rs2
-rw-r--r--tests/codegen-llvm/diverging-function-call-debuginfo.rs38
-rw-r--r--tests/codegen-llvm/ehcontguard_disabled.rs2
-rw-r--r--tests/codegen-llvm/enum/enum-discriminant-eq.rs14
-rw-r--r--tests/codegen-llvm/naked-fn/naked-functions.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs6
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs2
-rw-r--r--tests/codegen-llvm/sanitizer/memory-track-origins.rs2
-rw-r--r--tests/codegen-llvm/ub-checks.rs2
-rw-r--r--tests/debuginfo/unsized.rs1
-rw-r--r--tests/run-make/link-cfg/rmake.rs1
-rw-r--r--tests/run-make/mismatching-target-triples/rmake.rs1
-rw-r--r--tests/run-make/musl-default-linking/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-target-spec-json-path/rmake.rs1
-rw-r--r--tests/run-make/target-specs/rmake.rs1
-rw-r--r--tests/rustdoc-ui/2024-doctests-checks.rs2
-rw-r--r--tests/rustdoc-ui/2024-doctests-checks.stdout5
-rw-r--r--tests/rustdoc-ui/2024-doctests-crate-attribute.rs2
-rw-r--r--tests/rustdoc-ui/2024-doctests-crate-attribute.stdout5
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.rs2
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.stdout11
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-items.rs2
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-items.stdout83
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-module-2.rs2
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-module-2.stdout13
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-module.rs2
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-module.stdout11
-rw-r--r--tests/rustdoc-ui/doctest/doctest-output-include-fail.rs2
-rw-r--r--tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout1
-rw-r--r--tests/rustdoc-ui/doctest/edition-2024-error-output.rs2
-rw-r--r--tests/rustdoc-ui/doctest/edition-2024-error-output.stdout7
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs2
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout9
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout8
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout9
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs2
-rw-r--r--tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout8
-rw-r--r--tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout1
-rw-r--r--tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs2
-rw-r--r--tests/rustdoc-ui/doctest/stdout-and-stderr.rs2
-rw-r--r--tests/rustdoc-ui/doctest/stdout-and-stderr.stdout19
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.rs2
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.stdout15
-rw-r--r--tests/rustdoc/extern/extern-html-alias.rs9
-rw-r--r--tests/rustdoc/extern/extern-html-fallback.rs14
-rw-r--r--tests/ui/README.md4
-rw-r--r--tests/ui/borrowck/liberated-region-from-outer-closure.rs12
-rw-r--r--tests/ui/borrowck/liberated-region-from-outer-closure.stderr17
-rw-r--r--tests/ui/enum-discriminant/wrapping_niche.rs24
-rw-r--r--tests/ui/enum-discriminant/wrapping_niche.stderr238
-rw-r--r--tests/ui/errors/remap-path-prefix-sysroot.rs2
-rw-r--r--tests/ui/errors/wrong-target-spec.rs1
-rw-r--r--tests/ui/linkage-attr/unstable-flavor.rs4
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.stderr3
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr6
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr5
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr6
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr5
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr6
-rw-r--r--tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr2
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr4
-rw-r--r--tests/ui/target_modifiers/defaults_check.rs2
-rw-r--r--tests/ui/target_modifiers/incompatible_fixedx18.rs2
-rw-r--r--tests/ui/target_modifiers/incompatible_regparm.rs2
-rw-r--r--tests/ui/target_modifiers/no_value_bool.rs2
-rw-r--r--tests/ui/transmutability/enums/niche_optimization.rs12
-rw-r--r--tests/ui/warnings/hello-world.rs (renamed from tests/ui/hello_world/main.rs)0
-rw-r--r--triagebot.toml15
125 files changed, 1958 insertions, 930 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e92afc14c20..e91ef4abb12 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -117,7 +117,7 @@ jobs:
         with:
           fetch-depth: 2
 
-      # Free up disk space on Linux by removing preinstalled components that
+      # Free up disk space on Linux and Windows by removing preinstalled components that
       # we do not need. We do this to enable some of the less resource
       # intensive jobs to run on free runners, which however also have
       # less disk space.
@@ -125,6 +125,13 @@ jobs:
         run: src/ci/scripts/free-disk-space.sh
         if: matrix.free_disk
 
+      # If we don't need to free up disk space then just report how much space we have
+      - name: print disk usage
+        run: |
+          echo "disk usage:"
+          df -h
+        if: matrix.free_disk == false
+
       # Rust Log Analyzer can't currently detect the PR number of a GitHub
       # Actions build on its own, so a hint in the log message is needed to
       # point it in the right direction.
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 716bb716cdb..c2405553756 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeSet;
 use std::fmt::{self, Write};
 use std::ops::{Bound, Deref};
 use std::{cmp, iter};
@@ -5,7 +6,7 @@ use std::{cmp, iter};
 use rustc_hashes::Hash64;
 use rustc_index::Idx;
 use rustc_index::bit_set::BitMatrix;
-use tracing::debug;
+use tracing::{debug, trace};
 
 use crate::{
     AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
@@ -766,30 +767,63 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
 
         let niche_filling_layout = calculate_niche_filling_layout();
 
-        let (mut min, mut max) = (i128::MAX, i128::MIN);
         let discr_type = repr.discr_type();
-        let bits = Integer::from_attr(dl, discr_type).size().bits();
-        for (i, mut val) in discriminants {
-            if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
-                continue;
-            }
-            if discr_type.is_signed() {
-                // sign extend the raw representation to be an i128
-                val = (val << (128 - bits)) >> (128 - bits);
-            }
-            if val < min {
-                min = val;
-            }
-            if val > max {
-                max = val;
-            }
-        }
-        // We might have no inhabited variants, so pretend there's at least one.
-        if (min, max) == (i128::MAX, i128::MIN) {
-            min = 0;
-            max = 0;
-        }
-        assert!(min <= max, "discriminant range is {min}...{max}");
+        let discr_int = Integer::from_attr(dl, discr_type);
+        // Because we can only represent one range of valid values, we'll look for the
+        // largest range of invalid values and pick everything else as the range of valid
+        // values.
+
+        // First we need to sort the possible discriminant values so that we can look for the largest gap:
+        let valid_discriminants: BTreeSet<i128> = discriminants
+            .filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited()))
+            .map(|(_, val)| {
+                if discr_type.is_signed() {
+                    // sign extend the raw representation to be an i128
+                    // FIXME: do this at the discriminant iterator creation sites
+                    discr_int.size().sign_extend(val as u128)
+                } else {
+                    val
+                }
+            })
+            .collect();
+        trace!(?valid_discriminants);
+        let discriminants = valid_discriminants.iter().copied();
+        //let next_discriminants = discriminants.clone().cycle().skip(1);
+        let next_discriminants =
+            discriminants.clone().chain(valid_discriminants.first().copied()).skip(1);
+        // Iterate over pairs of each discriminant together with the next one.
+        // Since they were sorted, we can now compute the niche sizes and pick the largest.
+        let discriminants = discriminants.zip(next_discriminants);
+        let largest_niche = discriminants.max_by_key(|&(start, end)| {
+            trace!(?start, ?end);
+            // If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between
+            // the two end points is actually the size of the valid discriminants.
+            let dist = if start > end {
+                // Overflow can happen for 128 bit discriminants if `end` is negative.
+                // But in that case casting to `u128` still gets us the right value,
+                // as the distance must be positive if the lhs of the subtraction is larger than the rhs.
+                let dist = start.wrapping_sub(end);
+                if discr_type.is_signed() {
+                    discr_int.signed_max().wrapping_sub(dist) as u128
+                } else {
+                    discr_int.size().unsigned_int_max() - dist as u128
+                }
+            } else {
+                // Overflow can happen for 128 bit discriminants if `start` is negative.
+                // But in that case casting to `u128` still gets us the right value,
+                // as the distance must be positive if the lhs of the subtraction is larger than the rhs.
+                end.wrapping_sub(start) as u128
+            };
+            trace!(?dist);
+            dist
+        });
+        trace!(?largest_niche);
+
+        // `max` is the last valid discriminant before the largest niche
+        // `min` is the first valid discriminant after the largest niche
+        let (max, min) = largest_niche
+            // We might have no inhabited variants, so pretend there's at least one.
+            .unwrap_or((0, 0));
         let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
 
         let mut align = dl.aggregate_align;
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 8e346706877..14e256b8045 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1205,6 +1205,19 @@ impl Integer {
         }
     }
 
+    /// Returns the smallest signed value that can be represented by this Integer.
+    #[inline]
+    pub fn signed_min(self) -> i128 {
+        use Integer::*;
+        match self {
+            I8 => i8::MIN as i128,
+            I16 => i16::MIN as i128,
+            I32 => i32::MIN as i128,
+            I64 => i64::MIN as i128,
+            I128 => i128::MIN,
+        }
+    }
+
     /// Finds the smallest Integer type which can represent the signed value.
     #[inline]
     pub fn fit_signed(x: i128) -> Integer {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index a10da08ddf3..fdca6b56540 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                                 }
                             }
                         } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
-                            let sp = info.span.find_oldest_ancestor_in_same_ctxt();
+                            let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span);
                             if info.tail_result_is_ignored {
                                 // #85581: If the first mutable borrow's scope contains
                                 // the second borrow, this suggestion isn't helpful.
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index f138f265320..240c9a5223b 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>(
     mir_def_id: LocalDefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if !tcx.def_kind(mir_def_id).is_fn_like() {
-        return;
-    }
+    let bound_vars = match tcx.def_kind(mir_def_id) {
+        DefKind::Fn | DefKind::AssocFn => {
+            tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id))
+        }
+        // We extract the bound vars from the deduced closure signature, since we may have
+        // only deduced that a param in the closure signature is late-bound from a constraint
+        // that we discover during typeck.
+        DefKind::Closure => {
+            let ty = tcx.type_of(mir_def_id).instantiate_identity();
+            match *ty.kind() {
+                ty::Closure(_, args) => args.as_closure().sig().bound_vars(),
+                ty::CoroutineClosure(_, args) => {
+                    args.as_coroutine_closure().coroutine_closure_sig().bound_vars()
+                }
+                ty::Coroutine(_, _) | ty::Error(_) => return,
+                _ => unreachable!("unexpected type for closure: {ty}"),
+            }
+        }
+        _ => return,
+    };
 
-    for (idx, bound_var) in
-        tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate()
-    {
+    for (idx, bound_var) in bound_vars.iter().enumerate() {
         if let ty::BoundVariableKind::Region(kind) = bound_var {
             let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
             let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 33ae4f6c45c..2345cdab208 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1302,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 None => ".clone()".to_string(),
             };
 
-            let span = expr.span.find_oldest_ancestor_in_same_ctxt().shrink_to_hi();
+            let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi();
 
             diag.span_suggestion_verbose(
                 span,
@@ -1395,7 +1395,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .macro_backtrace()
                 .any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
         {
-            let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+            let span = expr
+                .span
+                .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
+                .unwrap_or(expr.span);
 
             let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
                 vec![(span.shrink_to_hi(), ".into()".to_owned())]
@@ -2062,7 +2065,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => sugg.to_string(),
         };
 
-        let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+        let span = expr
+            .span
+            .find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
+            .unwrap_or(expr.span);
         err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
         true
     }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 11df071f068..00e40b515a3 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         let mut op_warned = false;
 
         if let Some(must_use_op) = must_use_op {
-            let span = expr.span.find_oldest_ancestor_in_same_ctxt();
+            let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
             cx.emit_span_lint(
                 UNUSED_MUST_USE,
                 expr.span,
@@ -511,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     );
                 }
                 MustUsePath::Def(span, def_id, reason) => {
-                    let span = span.find_oldest_ancestor_in_same_ctxt();
+                    let span = span.find_ancestor_not_from_macro().unwrap_or(*span);
                     cx.emit_span_lint(
                         UNUSED_MUST_USE,
                         span,
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 438eff33054..6bfb3769f24 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
+use rustc_data_structures::unord::UnordMap;
 use rustc_expand::base::SyntaxExtension;
 use rustc_fs_util::try_canonicalize;
 use rustc_hir as hir;
@@ -69,6 +70,9 @@ pub struct CStore {
     /// This crate has a `#[alloc_error_handler]` item.
     has_alloc_error_handler: bool,
 
+    /// Names that were used to load the crates via `extern crate` or paths.
+    resolved_externs: UnordMap<Symbol, CrateNum>,
+
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
 
@@ -249,6 +253,22 @@ impl CStore {
         self.metas[cnum] = Some(Box::new(data));
     }
 
+    /// Save the name used to resolve the extern crate in the local crate
+    ///
+    /// The name isn't always the crate's own name, because `sess.opts.externs` can assign it another name.
+    /// It's also not always the same as the `DefId`'s symbol due to renames `extern crate resolved_name as defid_name`.
+    pub(crate) fn set_resolved_extern_crate_name(&mut self, name: Symbol, extern_crate: CrateNum) {
+        self.resolved_externs.insert(name, extern_crate);
+    }
+
+    /// Crate resolved and loaded via the given extern name
+    /// (corresponds to names in `sess.opts.externs`)
+    ///
+    /// May be `None` if the crate wasn't used
+    pub fn resolved_extern_crate(&self, externs_name: Symbol) -> Option<CrateNum> {
+        self.resolved_externs.get(&externs_name).copied()
+    }
+
     pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
         self.metas
             .iter_enumerated()
@@ -475,6 +495,7 @@ impl CStore {
             alloc_error_handler_kind: None,
             has_global_allocator: false,
             has_alloc_error_handler: false,
+            resolved_externs: UnordMap::default(),
             unused_externs: Vec::new(),
             used_extern_options: Default::default(),
         }
@@ -511,7 +532,7 @@ impl CStore {
             // We're also sure to compare *paths*, not actual byte slices. The
             // `source` stores paths which are normalized which may be different
             // from the strings on the command line.
-            let source = self.get_crate_data(cnum).cdata.source();
+            let source = data.source();
             if let Some(entry) = externs.get(name.as_str()) {
                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
                 if let Some(mut files) = entry.files() {
@@ -1308,6 +1329,7 @@ impl CStore {
                 let path_len = definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
                     cnum,
+                    name,
                     ExternCrate {
                         src: ExternCrateSource::Extern(def_id.to_def_id()),
                         span: item.span,
@@ -1332,6 +1354,7 @@ impl CStore {
 
         self.update_extern_crate(
             cnum,
+            name,
             ExternCrate {
                 src: ExternCrateSource::Path,
                 span,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e6aedc61338..00c97a2f738 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1937,9 +1937,13 @@ impl CrateMetadata {
         self.root.decode_target_modifiers(&self.blob).collect()
     }
 
-    pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
+    /// Keep `new_extern_crate` if it looks better in diagnostics
+    pub(crate) fn update_extern_crate_diagnostics(
+        &mut self,
+        new_extern_crate: ExternCrate,
+    ) -> bool {
         let update =
-            Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
+            self.extern_crate.as_ref().is_none_or(|old| old.rank() < new_extern_crate.rank());
         if update {
             self.extern_crate = Some(new_extern_crate);
         }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 57a672c45f7..9415e420eed 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -627,14 +627,37 @@ impl CStore {
         }
     }
 
-    pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) {
+    /// Track how an extern crate has been loaded. Called after resolving an import in the local crate.
+    ///
+    /// * the `name` is for [`Self::set_resolved_extern_crate_name`] saving `--extern name=`
+    /// * `extern_crate` is for diagnostics
+    pub(crate) fn update_extern_crate(
+        &mut self,
+        cnum: CrateNum,
+        name: Symbol,
+        extern_crate: ExternCrate,
+    ) {
+        debug_assert_eq!(
+            extern_crate.dependency_of, LOCAL_CRATE,
+            "this function should not be called on transitive dependencies"
+        );
+        self.set_resolved_extern_crate_name(name, cnum);
+        self.update_transitive_extern_crate_diagnostics(cnum, extern_crate);
+    }
+
+    /// `CrateMetadata` uses `ExternCrate` only for diagnostics
+    fn update_transitive_extern_crate_diagnostics(
+        &mut self,
+        cnum: CrateNum,
+        extern_crate: ExternCrate,
+    ) {
         let cmeta = self.get_crate_data_mut(cnum);
-        if cmeta.update_extern_crate(extern_crate) {
+        if cmeta.update_extern_crate_diagnostics(extern_crate) {
             // Propagate the extern crate info to dependencies if it was updated.
             let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
             let dependencies = mem::take(&mut cmeta.dependencies);
             for &dep_cnum in &dependencies {
-                self.update_extern_crate(dep_cnum, extern_crate);
+                self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate);
             }
             self.get_crate_data_mut(cnum).dependencies = dependencies;
         }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index a5123576fc6..aed94f9aa04 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -107,8 +107,8 @@ impl abi::Integer {
             abi::Integer::I8
         };
 
-        // If there are no negative values, we can use the unsigned fit.
-        if min >= 0 {
+        // Pick the smallest fit.
+        if unsigned_fit <= signed_fit {
             (cmp::max(unsigned_fit, at_least), false)
         } else {
             (cmp::max(signed_fit, at_least), true)
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 174892c6f4d..a7d07adf78f 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -32,7 +32,7 @@ use crate::ty::{
 
 #[derive(Copy, Clone, Debug)]
 pub struct Discr<'tcx> {
-    /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
+    /// Bit representation of the discriminant (e.g., `-1i8` is `0xFF_u128`).
     pub val: u128,
     pub ty: Ty<'tcx>,
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index b15b478a6be..7912345ec56 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -984,18 +984,17 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 // more details: https://github.com/rust-lang/rust/pull/111761
                 return;
             }
-            let entry = self
-                .r
-                .extern_prelude
-                .entry(ident)
-                .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true });
+            let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry {
+                binding: Cell::new(None),
+                introduced_by_item: true,
+            });
             if orig_name.is_some() {
                 entry.introduced_by_item = true;
             }
             // Binding from `extern crate` item in source code can replace
             // a binding from `--extern` on command line here.
             if !entry.is_import() {
-                entry.binding = Some(imported_binding)
+                entry.binding.set(Some(imported_binding));
             } else if ident.name != kw::Underscore {
                 self.r.dcx().span_delayed_bug(
                     item.span,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 8115b87dcae..88dfb50b47d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1009,13 +1009,13 @@ impl<'ra> NameBindingData<'ra> {
 
 #[derive(Default, Clone)]
 struct ExternPreludeEntry<'ra> {
-    binding: Option<NameBinding<'ra>>,
+    binding: Cell<Option<NameBinding<'ra>>>,
     introduced_by_item: bool,
 }
 
 impl ExternPreludeEntry<'_> {
     fn is_import(&self) -> bool {
-        self.binding.is_some_and(|binding| binding.is_import())
+        self.binding.get().is_some_and(|binding| binding.is_import())
     }
 }
 
@@ -2006,7 +2006,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // but not introduce it, as used if they are accessed from lexical scope.
             if used == Used::Scope {
                 if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
-                    if !entry.introduced_by_item && entry.binding == Some(used_binding) {
+                    if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) {
                         return;
                     }
                 }
@@ -2170,7 +2170,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         let norm_ident = ident.normalize_to_macros_2_0();
         let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
-            Some(if let Some(binding) = entry.binding {
+            Some(if let Some(binding) = entry.binding.get() {
                 if finalize {
                     if !entry.is_import() {
                         self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
@@ -2195,8 +2195,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             })
         });
 
-        if let Some(entry) = self.extern_prelude.get_mut(&norm_ident) {
-            entry.binding = binding;
+        if let Some(entry) = self.extern_prelude.get(&norm_ident) {
+            entry.binding.set(binding);
         }
 
         binding
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index dbc67da37b5..3f72ccd9f89 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -716,12 +716,17 @@ impl Span {
         (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
     }
 
-    /// Walk down the expansion ancestors to find a span that's contained within `outer`.
+    /// Find the first ancestor span that's contained within `outer`.
     ///
-    /// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
+    /// This method traverses the macro expansion ancestors until it finds the first span
+    /// that's contained within `outer`.
+    ///
+    /// The span returned by this method may have a different [`SyntaxContext`] than `outer`.
     /// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
     /// because joining spans with different syntax contexts can create unexpected results.
     ///
+    /// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
+    ///
     /// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
     pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
         while !outer.contains(self) {
@@ -730,8 +735,10 @@ impl Span {
         Some(self)
     }
 
-    /// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
-    /// `other`.
+    /// Find the first ancestor span with the same [`SyntaxContext`] as `other`.
+    ///
+    /// This method traverses the macro expansion ancestors until it finds a span
+    /// that has the same [`SyntaxContext`] as `other`.
     ///
     /// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
     /// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -747,9 +754,12 @@ impl Span {
         Some(self)
     }
 
-    /// Walk down the expansion ancestors to find a span that's contained within `outer` and
+    /// Find the first ancestor span that's contained within `outer` and
     /// has the same [`SyntaxContext`] as `outer`.
     ///
+    /// This method traverses the macro expansion ancestors until it finds a span
+    /// that is both contained within `outer` and has the same [`SyntaxContext`] as `outer`.
+    ///
     /// This method is the combination of [`find_ancestor_inside`] and
     /// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
     /// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -763,43 +773,43 @@ impl Span {
         Some(self)
     }
 
-    /// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
-    /// [`SyntaxContext`] the initial span.
+    /// Find the first ancestor span that does not come from an external macro.
     ///
-    /// This method is suitable for peeling through *local* macro expansions to find the "innermost"
-    /// span that is still local and shares the same [`SyntaxContext`]. For example, given
+    /// This method traverses the macro expansion ancestors until it finds a span
+    /// that is either from user-written code or from a local macro (defined in the current crate).
     ///
-    /// ```ignore (illustrative example, contains type error)
-    ///  macro_rules! outer {
-    ///      ($x: expr) => {
-    ///          inner!($x)
-    ///      }
-    ///  }
+    /// External macros are those defined in dependencies or the standard library.
+    /// This method is useful for reporting errors in user-controllable code and avoiding
+    /// diagnostics inside external macros.
     ///
-    ///  macro_rules! inner {
-    ///      ($x: expr) => {
-    ///          format!("error: {}", $x)
-    ///          //~^ ERROR mismatched types
-    ///      }
-    ///  }
+    /// # See also
     ///
-    ///  fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
-    ///      Err(outer!(x))
-    ///  }
-    /// ```
+    /// - [`Self::find_ancestor_not_from_macro`]
+    /// - [`Self::in_external_macro`]
+    pub fn find_ancestor_not_from_extern_macro(mut self, sm: &SourceMap) -> Option<Span> {
+        while self.in_external_macro(sm) {
+            self = self.parent_callsite()?;
+        }
+        Some(self)
+    }
+
+    /// Find the first ancestor span that does not come from any macro expansion.
     ///
-    /// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
-    /// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
-    /// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
-    /// initial span.
-    pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
-        let mut cur = self;
-        while cur.eq_ctxt(self)
-            && let Some(parent_callsite) = cur.parent_callsite()
-        {
-            cur = parent_callsite;
+    /// This method traverses the macro expansion ancestors until it finds a span
+    /// that originates from user-written code rather than any macro-generated code.
+    ///
+    /// This method is useful for reporting errors at the exact location users wrote code
+    /// and providing suggestions at directly editable locations.
+    ///
+    /// # See also
+    ///
+    /// - [`Self::find_ancestor_not_from_extern_macro`]
+    /// - [`Span::from_expansion`]
+    pub fn find_ancestor_not_from_macro(mut self) -> Option<Span> {
+        while self.from_expansion() {
+            self = self.parent_callsite()?;
         }
-        cur
+        Some(self)
     }
 
     /// Edition of the crate from which this span came.
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index c64cd9a51b7..033590e01a6 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -3598,6 +3598,7 @@ impl Target {
             ),
             "x86" => (Architecture::I386, None),
             "s390x" => (Architecture::S390x, None),
+            "m68k" => (Architecture::M68k, None),
             "mips" | "mips32r6" => (Architecture::Mips, None),
             "mips64" | "mips64r6" => (
                 // While there are currently no builtin targets
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index 97227020885..6ef7d5a22a3 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -1,5 +1,7 @@
+use crate::cmp::Ordering;
 use crate::ffi::CStr;
 use crate::fmt;
+use crate::hash::{Hash, Hasher};
 use crate::marker::PhantomData;
 use crate::ptr::NonNull;
 
@@ -32,7 +34,7 @@ use crate::ptr::NonNull;
 /// Files are compared as strings, not `Path`, which could be unexpected.
 /// See [`Location::file`]'s documentation for more discussion.
 #[lang = "panic_location"]
-#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Copy, Clone)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
     // A raw pointer is used rather than a reference because the pointer is valid for one more byte
@@ -45,6 +47,44 @@ pub struct Location<'a> {
 }
 
 #[stable(feature = "panic_hooks", since = "1.10.0")]
+impl PartialEq for Location<'_> {
+    fn eq(&self, other: &Self) -> bool {
+        // Compare col / line first as they're cheaper to compare and more likely to differ,
+        // while not impacting the result.
+        self.col == other.col && self.line == other.line && self.file() == other.file()
+    }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Eq for Location<'_> {}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Ord for Location<'_> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.file()
+            .cmp(other.file())
+            .then_with(|| self.line.cmp(&other.line))
+            .then_with(|| self.col.cmp(&other.col))
+    }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl PartialOrd for Location<'_> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl Hash for Location<'_> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.file().hash(state);
+        self.line.hash(state);
+        self.col.hash(state);
+    }
+}
+
+#[stable(feature = "panic_hooks", since = "1.10.0")]
 impl fmt::Debug for Location<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Location")
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index bcbbb11c83b..e116b138383 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -996,7 +996,10 @@ impl<'b> Pattern for &'b str {
                     return haystack.as_bytes().contains(&self.as_bytes()[0]);
                 }
 
-                #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
+                #[cfg(any(
+                    all(target_arch = "x86_64", target_feature = "sse2"),
+                    all(target_arch = "loongarch64", target_feature = "lsx")
+                ))]
                 if self.len() <= 32 {
                     if let Some(result) = simd_contains(self, haystack) {
                         return result;
@@ -1770,11 +1773,18 @@ impl TwoWayStrategy for RejectAndMatch {
 /// If we ever ship std with for x86-64-v3 or adapt this for other platforms then wider vectors
 /// should be evaluated.
 ///
+/// Similarly, on LoongArch the 128-bit LSX vector extension is the baseline,
+/// so we also use `u8x16` there. Wider vector widths may be considered
+/// for future LoongArch extensions (e.g., LASX).
+///
 /// For haystacks smaller than vector-size + needle length it falls back to
 /// a naive O(n*m) search so this implementation should not be called on larger needles.
 ///
 /// [0]: http://0x80.pl/articles/simd-strfind.html#sse-avx2
-#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
+#[cfg(any(
+    all(target_arch = "x86_64", target_feature = "sse2"),
+    all(target_arch = "loongarch64", target_feature = "lsx")
+))]
 #[inline]
 fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
     let needle = needle.as_bytes();
@@ -1906,7 +1916,10 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
 /// # Safety
 ///
 /// Both slices must have the same length.
-#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] // only called on x86
+#[cfg(any(
+    all(target_arch = "x86_64", target_feature = "sse2"),
+    all(target_arch = "loongarch64", target_feature = "lsx")
+))]
 #[inline]
 unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
     debug_assert_eq!(x.len(), y.len());
diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs
index 5ce0b06e90e..910001bcc1c 100644
--- a/library/coretests/tests/panic/location.rs
+++ b/library/coretests/tests/panic/location.rs
@@ -3,6 +3,23 @@ use core::panic::Location;
 // Note: Some of the following tests depend on the source location,
 // so please be careful when editing this file.
 
+mod file_a;
+mod file_b;
+mod file_c;
+
+// A small shuffled set of locations for testing, along with their true order.
+const LOCATIONS: [(usize, &'static Location<'_>); 9] = [
+    (7, file_c::two()),
+    (0, file_a::one()),
+    (3, file_b::one()),
+    (5, file_b::three()),
+    (8, file_c::three()),
+    (6, file_c::one()),
+    (2, file_a::three()),
+    (4, file_b::two()),
+    (1, file_a::two()),
+];
+
 #[test]
 fn location_const_caller() {
     const _CALLER_REFERENCE: &Location<'static> = Location::caller();
@@ -20,7 +37,7 @@ fn location_const_file() {
 fn location_const_line() {
     const CALLER: &Location<'static> = Location::caller();
     const LINE: u32 = CALLER.line();
-    assert_eq!(LINE, 21);
+    assert_eq!(LINE, 38);
 }
 
 #[test]
@@ -34,6 +51,28 @@ fn location_const_column() {
 fn location_debug() {
     let f = format!("{:?}", Location::caller());
     assert!(f.contains(&format!("{:?}", file!())));
-    assert!(f.contains("35"));
+    assert!(f.contains("52"));
     assert!(f.contains("29"));
 }
+
+#[test]
+fn location_eq() {
+    for (i, a) in LOCATIONS {
+        for (j, b) in LOCATIONS {
+            if i == j {
+                assert_eq!(a, b);
+            } else {
+                assert_ne!(a, b);
+            }
+        }
+    }
+}
+
+#[test]
+fn location_ord() {
+    let mut locations = LOCATIONS.clone();
+    locations.sort_by_key(|(_o, l)| **l);
+    for (correct, (order, _l)) in locations.iter().enumerate() {
+        assert_eq!(correct, *order);
+    }
+}
diff --git a/library/coretests/tests/panic/location/file_a.rs b/library/coretests/tests/panic/location/file_a.rs
new file mode 100644
index 00000000000..1ceb225ee9c
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_a.rs
@@ -0,0 +1,15 @@
+use core::panic::Location;
+
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+pub const fn one() -> &'static Location<'static> {
+    Location::caller()
+}
+
+pub const fn two() -> &'static Location<'static> {
+    Location::caller()
+}
+
+pub const fn three() -> &'static Location<'static> {
+    Location::caller()
+}
diff --git a/library/coretests/tests/panic/location/file_b.rs b/library/coretests/tests/panic/location/file_b.rs
new file mode 100644
index 00000000000..1ceb225ee9c
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_b.rs
@@ -0,0 +1,15 @@
+use core::panic::Location;
+
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+pub const fn one() -> &'static Location<'static> {
+    Location::caller()
+}
+
+pub const fn two() -> &'static Location<'static> {
+    Location::caller()
+}
+
+pub const fn three() -> &'static Location<'static> {
+    Location::caller()
+}
diff --git a/library/coretests/tests/panic/location/file_c.rs b/library/coretests/tests/panic/location/file_c.rs
new file mode 100644
index 00000000000..2ac416c19cf
--- /dev/null
+++ b/library/coretests/tests/panic/location/file_c.rs
@@ -0,0 +1,11 @@
+// Used for test super::location_{ord, eq}. Must be in a dedicated file.
+
+// This is used for testing column ordering of Location, hence this ugly one-liner.
+// We must fmt skip the entire containing module or else tidy will still complain.
+#[rustfmt::skip]
+mod no_fmt {
+    use core::panic::Location;
+    pub const fn one() -> &'static Location<'static> { Location::caller() }    pub const fn two() -> &'static Location<'static> { Location::caller() }    pub const fn three() -> &'static Location<'static> { Location::caller() }
+}
+
+pub use no_fmt::*;
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index e1d83d36087..0855ea222a3 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -81,9 +81,9 @@ RUN /tmp/build-fuchsia-toolchain.sh
 COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz | \
   tar -xz
-ENV WASI_SDK_PATH=/tmp/wasi-sdk-25.0-x86_64-linux
+ENV WASI_SDK_PATH=/tmp/wasi-sdk-27.0-x86_64-linux
 
 COPY scripts/freebsd-toolchain.sh /tmp/
 RUN /tmp/freebsd-toolchain.sh i686
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 662a26400ce..82a820c859d 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -40,9 +40,9 @@ WORKDIR /
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz | \
+RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz | \
   tar -xz
-ENV WASI_SDK_PATH=/wasi-sdk-25.0-x86_64-linux
+ENV WASI_SDK_PATH=/wasi-sdk-27.0-x86_64-linux
 
 ENV RUST_CONFIGURE_ARGS \
   --musl-root-x86_64=/usr/local/x86_64-linux-musl \
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 0e1edfe21de..48c570bfa11 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -31,20 +31,11 @@ runners:
     <<: *base-job
 
   - &job-windows
-    os: windows-2022
-    <<: *base-job
-
-  # NOTE: windows-2025 has less disk space available than windows-2022,
-  # because the D drive is missing.
-  - &job-windows-25
     os: windows-2025
+    free_disk: true
     <<: *base-job
 
   - &job-windows-8c
-    os: windows-2022-8core-32gb
-    <<: *base-job
-
-  - &job-windows-25-8c
     os: windows-2025-8core-32gb
     <<: *base-job
 
@@ -668,7 +659,7 @@ auto:
       SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-windows-25-8c
+    <<: *job-windows-8c
 
   - name: dist-i686-msvc
     env:
diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh
new file mode 100755
index 00000000000..32649fe0d9b
--- /dev/null
+++ b/src/ci/scripts/free-disk-space-linux.sh
@@ -0,0 +1,265 @@
+#!/bin/bash
+set -euo pipefail
+
+# Free disk space on Linux GitHub action runners
+# Script inspired by https://github.com/jlumbroso/free-disk-space
+
+isX86() {
+    local arch
+    arch=$(uname -m)
+    if [ "$arch" = "x86_64" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+# Check if we're on a GitHub hosted runner.
+# In aws codebuild, the variable RUNNER_ENVIRONMENT is "self-hosted".
+isGitHubRunner() {
+    # `:-` means "use the value of RUNNER_ENVIRONMENT if it exists, otherwise use an empty string".
+    if [[ "${RUNNER_ENVIRONMENT:-}" == "github-hosted" ]]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+# print a line of the specified character
+printSeparationLine() {
+    for ((i = 0; i < 80; i++)); do
+        printf "%s" "$1"
+    done
+    printf "\n"
+}
+
+# compute available space
+# REF: https://unix.stackexchange.com/a/42049/60849
+# REF: https://stackoverflow.com/a/450821/408734
+getAvailableSpace() {
+    df -a | awk 'NR > 1 {avail+=$4} END {print avail}'
+}
+
+# make Kb human readable (assume the input is Kb)
+# REF: https://unix.stackexchange.com/a/44087/60849
+formatByteCount() {
+    numfmt --to=iec-i --suffix=B --padding=7 "${1}000"
+}
+
+# macro to output saved space
+printSavedSpace() {
+    # Disk space before the operation
+    local before=${1}
+    local title=${2:-}
+
+    local after
+    after=$(getAvailableSpace)
+    local saved=$((after - before))
+
+    if [ "$saved" -lt 0 ]; then
+        echo "::warning::Saved space is negative: $saved. Using '0' as saved space."
+        saved=0
+    fi
+
+    echo ""
+    printSeparationLine "*"
+    if [ -n "${title}" ]; then
+        echo "=> ${title}: Saved $(formatByteCount "$saved")"
+    else
+        echo "=> Saved $(formatByteCount "$saved")"
+    fi
+    printSeparationLine "*"
+    echo ""
+}
+
+# macro to print output of df with caption
+printDF() {
+    local caption=${1}
+
+    printSeparationLine "="
+    echo "${caption}"
+    echo ""
+    echo "$ df -h"
+    echo ""
+    df -h
+    printSeparationLine "="
+}
+
+removeUnusedFilesAndDirs() {
+    local to_remove=(
+        "/usr/share/java"
+    )
+
+    if isGitHubRunner; then
+        to_remove+=(
+            "/usr/local/aws-sam-cli"
+            "/usr/local/doc/cmake"
+            "/usr/local/julia"*
+            "/usr/local/lib/android"
+            "/usr/local/share/chromedriver-"*
+            "/usr/local/share/chromium"
+            "/usr/local/share/cmake-"*
+            "/usr/local/share/edge_driver"
+            "/usr/local/share/emacs"
+            "/usr/local/share/gecko_driver"
+            "/usr/local/share/icons"
+            "/usr/local/share/powershell"
+            "/usr/local/share/vcpkg"
+            "/usr/local/share/vim"
+            "/usr/share/apache-maven-"*
+            "/usr/share/gradle-"*
+            "/usr/share/kotlinc"
+            "/usr/share/miniconda"
+            "/usr/share/php"
+            "/usr/share/ri"
+            "/usr/share/swift"
+
+            # binaries
+            "/usr/local/bin/azcopy"
+            "/usr/local/bin/bicep"
+            "/usr/local/bin/ccmake"
+            "/usr/local/bin/cmake-"*
+            "/usr/local/bin/cmake"
+            "/usr/local/bin/cpack"
+            "/usr/local/bin/ctest"
+            "/usr/local/bin/helm"
+            "/usr/local/bin/kind"
+            "/usr/local/bin/kustomize"
+            "/usr/local/bin/minikube"
+            "/usr/local/bin/packer"
+            "/usr/local/bin/phpunit"
+            "/usr/local/bin/pulumi-"*
+            "/usr/local/bin/pulumi"
+            "/usr/local/bin/stack"
+
+            # Haskell runtime
+            "/usr/local/.ghcup"
+
+            # Azure
+            "/opt/az"
+            "/usr/share/az_"*
+        )
+
+        if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then
+            # Environment variable set by GitHub Actions
+            to_remove+=(
+                "${AGENT_TOOLSDIRECTORY}"
+            )
+        else
+            echo "::warning::AGENT_TOOLSDIRECTORY is not set. Skipping removal."
+        fi
+    else
+        # Remove folders and files present in AWS CodeBuild
+        to_remove+=(
+            # binaries
+            "/usr/local/bin/ecs-cli"
+            "/usr/local/bin/eksctl"
+            "/usr/local/bin/kubectl"
+
+            "${HOME}/.gradle"
+            "${HOME}/.dotnet"
+            "${HOME}/.goenv"
+            "${HOME}/.phpenv"
+
+        )
+    fi
+
+    for element in "${to_remove[@]}"; do
+        if [ ! -e "$element" ]; then
+            # The file or directory doesn't exist.
+            # Maybe it was removed in a newer version of the runner or it's not present in a
+            # specific architecture (e.g. ARM).
+            echo "::warning::Directory or file $element does not exist, skipping."
+        fi
+    done
+
+    # Remove all files and directories at once to save time.
+    sudo rm -rf "${to_remove[@]}"
+}
+
+execAndMeasureSpaceChange() {
+    local operation=${1} # Function to execute
+    local title=${2}
+
+    local before
+    before=$(getAvailableSpace)
+    $operation
+
+    printSavedSpace "$before" "$title"
+}
+
+# Remove large packages
+# REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh
+cleanPackages() {
+    local packages=(
+        '^aspnetcore-.*'
+        '^dotnet-.*'
+        '^llvm-.*'
+        '^mongodb-.*'
+        'firefox'
+        'libgl1-mesa-dri'
+        'mono-devel'
+        'php.*'
+    )
+
+    if isGitHubRunner; then
+        packages+=(
+            azure-cli
+        )
+
+        if isX86; then
+            packages+=(
+                'google-chrome-stable'
+                'google-cloud-cli'
+                'google-cloud-sdk'
+                'powershell'
+            )
+        fi
+    else
+        packages+=(
+            'google-chrome-stable'
+        )
+    fi
+
+    sudo apt-get -qq remove -y --fix-missing "${packages[@]}"
+
+    sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed"
+    sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed"
+}
+
+# Remove Docker images.
+# Ubuntu 22 runners have docker images already installed.
+# They aren't present in ubuntu 24 runners.
+cleanDocker() {
+    echo "=> Removing the following docker images:"
+    sudo docker image ls
+    echo "=> Removing docker images..."
+    sudo docker image prune --all --force || true
+}
+
+# Remove Swap storage
+cleanSwap() {
+    sudo swapoff -a || true
+    sudo rm -rf /mnt/swapfile || true
+    free -h
+}
+
+# Display initial disk space stats
+
+AVAILABLE_INITIAL=$(getAvailableSpace)
+
+printDF "BEFORE CLEAN-UP:"
+echo ""
+execAndMeasureSpaceChange cleanPackages "Unused packages"
+execAndMeasureSpaceChange cleanDocker "Docker images"
+execAndMeasureSpaceChange cleanSwap "Swap storage"
+execAndMeasureSpaceChange removeUnusedFilesAndDirs "Unused files and directories"
+
+# Output saved space statistic
+echo ""
+printDF "AFTER CLEAN-UP:"
+
+echo ""
+echo ""
+
+printSavedSpace "$AVAILABLE_INITIAL" "Total saved"
diff --git a/src/ci/scripts/free-disk-space-windows.ps1 b/src/ci/scripts/free-disk-space-windows.ps1
new file mode 100644
index 00000000000..8a4677bd2ab
--- /dev/null
+++ b/src/ci/scripts/free-disk-space-windows.ps1
@@ -0,0 +1,35 @@
+# Free disk space on Windows GitHub action runners.
+
+$ErrorActionPreference = 'Stop'
+
+Get-Volume | Out-String | Write-Output
+
+$available = $(Get-Volume C).SizeRemaining
+
+$dirs = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm',
+'C:\rtools45', 'C:\ghcup', 'C:\Program Files (x86)\Android',
+'C:\Program Files\Google\Chrome', 'C:\Program Files (x86)\Microsoft\Edge',
+'C:\Program Files\Mozilla Firefox', 'C:\Program Files\MySQL', 'C:\Julia',
+'C:\Program Files\MongoDB', 'C:\Program Files\Azure Cosmos DB Emulator',
+'C:\Program Files\PostgreSQL', 'C:\Program Files\Unity Hub',
+'C:\Strawberry', 'C:\hostedtoolcache\windows\Java_Temurin-Hotspot_jdk'
+
+foreach ($dir in $dirs) {
+    Start-ThreadJob -InputObject $dir {
+        Remove-Item -Recurse -Force -LiteralPath $input
+    } | Out-Null
+}
+
+foreach ($job in Get-Job) {
+    Wait-Job $job  | Out-Null
+    if ($job.Error) {
+        Write-Output "::warning file=$PSCommandPath::$($job.Error)"
+    }
+    Remove-Job $job
+}
+
+Get-Volume | Out-String | Write-Output
+
+$saved = ($(Get-Volume C).SizeRemaining - $available) / 1gb
+$savedRounded = [math]::Round($saved, 3)
+Write-Output "total space saved: $savedRounded GB"
diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh
index 173f64858b3..062ad801cd8 100755
--- a/src/ci/scripts/free-disk-space.sh
+++ b/src/ci/scripts/free-disk-space.sh
@@ -1,266 +1,10 @@
 #!/bin/bash
 set -euo pipefail
 
-# Free disk space on Linux GitHub action runners
-# Script inspired by https://github.com/jlumbroso/free-disk-space
+script_dir=$(dirname "$0")
 
-isX86() {
-    local arch
-    arch=$(uname -m)
-    if [ "$arch" = "x86_64" ]; then
-        return 0
-    else
-        return 1
-    fi
-}
-
-# Check if we're on a GitHub hosted runner.
-# In aws codebuild, the variable RUNNER_ENVIRONMENT is "self-hosted".
-isGitHubRunner() {
-    # `:-` means "use the value of RUNNER_ENVIRONMENT if it exists, otherwise use an empty string".
-    if [[ "${RUNNER_ENVIRONMENT:-}" == "github-hosted" ]]; then
-        return 0
-    else
-        return 1
-    fi
-}
-
-# print a line of the specified character
-printSeparationLine() {
-    for ((i = 0; i < 80; i++)); do
-        printf "%s" "$1"
-    done
-    printf "\n"
-}
-
-# compute available space
-# REF: https://unix.stackexchange.com/a/42049/60849
-# REF: https://stackoverflow.com/a/450821/408734
-getAvailableSpace() {
-    df -a | awk 'NR > 1 {avail+=$4} END {print avail}'
-}
-
-# make Kb human readable (assume the input is Kb)
-# REF: https://unix.stackexchange.com/a/44087/60849
-formatByteCount() {
-    numfmt --to=iec-i --suffix=B --padding=7 "${1}000"
-}
-
-# macro to output saved space
-printSavedSpace() {
-    # Disk space before the operation
-    local before=${1}
-    local title=${2:-}
-
-    local after
-    after=$(getAvailableSpace)
-    local saved=$((after - before))
-
-    if [ "$saved" -lt 0 ]; then
-        echo "::warning::Saved space is negative: $saved. Using '0' as saved space."
-        saved=0
-    fi
-
-    echo ""
-    printSeparationLine "*"
-    if [ -n "${title}" ]; then
-        echo "=> ${title}: Saved $(formatByteCount "$saved")"
-    else
-        echo "=> Saved $(formatByteCount "$saved")"
-    fi
-    printSeparationLine "*"
-    echo ""
-}
-
-# macro to print output of df with caption
-printDF() {
-    local caption=${1}
-
-    printSeparationLine "="
-    echo "${caption}"
-    echo ""
-    echo "$ df -h"
-    echo ""
-    df -h
-    printSeparationLine "="
-}
-
-removeUnusedFilesAndDirs() {
-    local to_remove=(
-        "/usr/share/java"
-    )
-
-    if isGitHubRunner; then
-        to_remove+=(
-            "/usr/local/aws-sam-cli"
-            "/usr/local/doc/cmake"
-            "/usr/local/julia"*
-            "/usr/local/lib/android"
-            "/usr/local/share/chromedriver-"*
-            "/usr/local/share/chromium"
-            "/usr/local/share/cmake-"*
-            "/usr/local/share/edge_driver"
-            "/usr/local/share/emacs"
-            "/usr/local/share/gecko_driver"
-            "/usr/local/share/icons"
-            "/usr/local/share/powershell"
-            "/usr/local/share/vcpkg"
-            "/usr/local/share/vim"
-            "/usr/share/apache-maven-"*
-            "/usr/share/gradle-"*
-            "/usr/share/kotlinc"
-            "/usr/share/miniconda"
-            "/usr/share/php"
-            "/usr/share/ri"
-            "/usr/share/swift"
-
-            # binaries
-            "/usr/local/bin/azcopy"
-            "/usr/local/bin/bicep"
-            "/usr/local/bin/ccmake"
-            "/usr/local/bin/cmake-"*
-            "/usr/local/bin/cmake"
-            "/usr/local/bin/cpack"
-            "/usr/local/bin/ctest"
-            "/usr/local/bin/helm"
-            "/usr/local/bin/kind"
-            "/usr/local/bin/kustomize"
-            "/usr/local/bin/minikube"
-            "/usr/local/bin/packer"
-            "/usr/local/bin/phpunit"
-            "/usr/local/bin/pulumi-"*
-            "/usr/local/bin/pulumi"
-            "/usr/local/bin/stack"
-
-            # Haskell runtime
-            "/usr/local/.ghcup"
-
-            # Azure
-            "/opt/az"
-            "/usr/share/az_"*
-        )
-
-        if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then
-            # Environment variable set by GitHub Actions
-            to_remove+=(
-                "${AGENT_TOOLSDIRECTORY}"
-            )
-        else
-            echo "::warning::AGENT_TOOLSDIRECTORY is not set. Skipping removal."
-        fi
-    else
-        # Remove folders and files present in AWS CodeBuild
-        to_remove+=(
-            # binaries
-            "/usr/local/bin/ecs-cli"
-            "/usr/local/bin/eksctl"
-            "/usr/local/bin/kubectl"
-
-            "${HOME}/.gradle"
-            "${HOME}/.dotnet"
-            "${HOME}/.goenv"
-            "${HOME}/.phpenv"
-
-        )
-    fi
-
-    for element in "${to_remove[@]}"; do
-        if [ ! -e "$element" ]; then
-            # The file or directory doesn't exist.
-            # Maybe it was removed in a newer version of the runner or it's not present in a
-            # specific architecture (e.g. ARM).
-            echo "::warning::Directory or file $element does not exist, skipping."
-        fi
-    done
-
-    # Remove all files and directories at once to save time.
-    sudo rm -rf "${to_remove[@]}"
-}
-
-execAndMeasureSpaceChange() {
-    local operation=${1} # Function to execute
-    local title=${2}
-
-    local before
-    before=$(getAvailableSpace)
-    $operation
-
-    printSavedSpace "$before" "$title"
-}
-
-# Remove large packages
-# REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh
-cleanPackages() {
-    local packages=(
-        '^aspnetcore-.*'
-        '^dotnet-.*'
-        '^llvm-.*'
-        '^mongodb-.*'
-        'firefox'
-        'libgl1-mesa-dri'
-        'mono-devel'
-        'php.*'
-    )
-
-    if isGitHubRunner; then
-        packages+=(
-            azure-cli
-        )
-
-        if isX86; then
-            packages+=(
-                'google-chrome-stable'
-                'google-cloud-cli'
-                'google-cloud-sdk'
-                'powershell'
-            )
-        fi
-    else
-        packages+=(
-            'google-chrome-stable'
-        )
-    fi
-
-    sudo apt-get -qq remove -y --fix-missing "${packages[@]}"
-
-    sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed"
-    sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed"
-}
-
-# Remove Docker images.
-# Ubuntu 22 runners have docker images already installed.
-# They aren't present in ubuntu 24 runners.
-cleanDocker() {
-    echo "=> Removing the following docker images:"
-    sudo docker image ls
-    echo "=> Removing docker images..."
-    sudo docker image prune --all --force || true
-}
-
-# Remove Swap storage
-cleanSwap() {
-    sudo swapoff -a || true
-    sudo rm -rf /mnt/swapfile || true
-    free -h
-}
-
-# Display initial disk space stats
-
-AVAILABLE_INITIAL=$(getAvailableSpace)
-
-printDF "BEFORE CLEAN-UP:"
-echo ""
-
-execAndMeasureSpaceChange cleanPackages "Unused packages"
-execAndMeasureSpaceChange cleanDocker "Docker images"
-execAndMeasureSpaceChange cleanSwap "Swap storage"
-execAndMeasureSpaceChange removeUnusedFilesAndDirs "Unused files and directories"
-
-# Output saved space statistic
-echo ""
-printDF "AFTER CLEAN-UP:"
-
-echo ""
-echo ""
-
-printSavedSpace "$AVAILABLE_INITIAL" "Total saved"
+if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
+    pwsh $script_dir/free-disk-space-windows.ps1
+else
+    $script_dir/free-disk-space-linux.sh
+fi
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 5c3ae359ba0..89e4d3e9b58 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -293,8 +293,6 @@ See [Pretty-printer](compiletest.md#pretty-printer-tests).
 
 - `no-auto-check-cfg` — disable auto check-cfg (only for `--check-cfg` tests)
 - [`revisions`](compiletest.md#revisions) — compile multiple times
-- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) -
-      suppress tidy checks for mentioning unknown revision names
 -[`forbid-output`](compiletest.md#incremental-tests) — incremental cfail rejects
       output pattern
 - [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should
@@ -315,6 +313,17 @@ test suites that use those tools:
 - `llvm-cov-flags` adds extra flags when running LLVM's `llvm-cov` tool.
   - Used by [coverage tests](compiletest.md#coverage-tests) in `coverage-run` mode.
 
+### Tidy specific directives
+
+The following directives control how the [tidy script](../conventions.md#formatting)
+verifies tests.
+
+- `ignore-tidy-target-specific-tests` disables checking that the appropriate
+  LLVM component is required (via a `needs-llvm-components` directive) when a
+  test is compiled for a specific target (via the `--target` flag in a
+  `compile-flag` directive).
+- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) -
+      suppress tidy checks for mentioning unknown revision names.
 
 ## Substitutions
 
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 27910ad0ab7..7bd2970eee7 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -395,6 +395,12 @@ flags to control that behavior. When the `--extern-html-root-url` flag is given
 one of your dependencies, rustdoc use that URL for those docs. Keep in mind that if those docs exist
 in the output directory, those local docs will still override this flag.
 
+The names in this flag are first matched against the names given in the `--extern name=` flags,
+which allows selecting between multiple crates with the same name (e.g. multiple versions of
+the same crate). For transitive dependencies that haven't been loaded via an `--extern` flag, matching
+falls backs to using crate names only, without ability to distinguish between multiple crates with
+the same name.
+
 ## `-Z force-unstable-if-unmarked`
 
 Using this flag looks like this:
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index a32c2f7fb18..0bef091468f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -11,7 +11,8 @@ use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex};
-use std::{panic, str};
+use std::time::{Duration, Instant};
+use std::{fmt, panic, str};
 
 pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder};
 pub(crate) use markdown::test as test_markdown;
@@ -36,6 +37,50 @@ use crate::config::{Options as RustdocOptions, OutputFormat};
 use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine};
 use crate::lint::init_lints;
 
+/// Type used to display times (compilation and total) information for merged doctests.
+struct MergedDoctestTimes {
+    total_time: Instant,
+    /// Total time spent compiling all merged doctests.
+    compilation_time: Duration,
+    /// This field is used to keep track of how many merged doctests we (tried to) compile.
+    added_compilation_times: usize,
+}
+
+impl MergedDoctestTimes {
+    fn new() -> Self {
+        Self {
+            total_time: Instant::now(),
+            compilation_time: Duration::default(),
+            added_compilation_times: 0,
+        }
+    }
+
+    fn add_compilation_time(&mut self, duration: Duration) {
+        self.compilation_time += duration;
+        self.added_compilation_times += 1;
+    }
+
+    fn display_times(&self) {
+        // If no merged doctest was compiled, then there is nothing to display since the numbers
+        // displayed by `libtest` for standalone tests are already accurate (they include both
+        // compilation and runtime).
+        if self.added_compilation_times > 0 {
+            println!("{self}");
+        }
+    }
+}
+
+impl fmt::Display for MergedDoctestTimes {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "all doctests ran in {:.2}s; merged doctests compilation took {:.2}s",
+            self.total_time.elapsed().as_secs_f64(),
+            self.compilation_time.as_secs_f64(),
+        )
+    }
+}
+
 /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
 #[derive(Clone)]
 pub(crate) struct GlobalTestOptions {
@@ -295,6 +340,7 @@ pub(crate) fn run_tests(
 
     let mut nb_errors = 0;
     let mut ran_edition_tests = 0;
+    let mut times = MergedDoctestTimes::new();
     let target_str = rustdoc_options.target.to_string();
 
     for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
@@ -314,13 +360,15 @@ pub(crate) fn run_tests(
         for (doctest, scraped_test) in &doctests {
             tests_runner.add_test(doctest, scraped_test, &target_str);
         }
-        if let Ok(success) = tests_runner.run_merged_tests(
+        let (duration, ret) = tests_runner.run_merged_tests(
             rustdoc_test_options,
             edition,
             &opts,
             &test_args,
             rustdoc_options,
-        ) {
+        );
+        times.add_compilation_time(duration);
+        if let Ok(success) = ret {
             ran_edition_tests += 1;
             if !success {
                 nb_errors += 1;
@@ -354,11 +402,13 @@ pub(crate) fn run_tests(
         test::test_main_with_exit_callback(&test_args, standalone_tests, None, || {
             // We ensure temp dir destructor is called.
             std::mem::drop(temp_dir.take());
+            times.display_times();
         });
     }
     if nb_errors != 0 {
         // We ensure temp dir destructor is called.
         std::mem::drop(temp_dir);
+        times.display_times();
         // libtest::ERROR_EXIT_CODE is not public but it's the same value.
         std::process::exit(101);
     }
@@ -496,16 +546,19 @@ impl RunnableDocTest {
 ///
 /// This is the function that calculates the compiler command line, invokes the compiler, then
 /// invokes the test or tests in a separate executable (if applicable).
+///
+/// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
 fn run_test(
     doctest: RunnableDocTest,
     rustdoc_options: &RustdocOptions,
     supports_color: bool,
     report_unused_externs: impl Fn(UnusedExterns),
-) -> Result<(), TestFailure> {
+) -> (Duration, Result<(), TestFailure>) {
     let langstr = &doctest.langstr;
     // Make sure we emit well-formed executable names for our target.
     let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
     let output_file = doctest.test_opts.outdir.path().join(rust_out);
+    let instant = Instant::now();
 
     // Common arguments used for compiling the doctest runner.
     // On merged doctests, the compiler is invoked twice: once for the test code itself,
@@ -589,7 +642,7 @@ fn run_test(
         if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
             // If we cannot write this file for any reason, we leave. All combined tests will be
             // tested as standalone tests.
-            return Err(TestFailure::CompileError);
+            return (Duration::default(), Err(TestFailure::CompileError));
         }
         if !rustdoc_options.nocapture {
             // If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -660,7 +713,7 @@ fn run_test(
         if std::fs::write(&runner_input_file, merged_test_code).is_err() {
             // If we cannot write this file for any reason, we leave. All combined tests will be
             // tested as standalone tests.
-            return Err(TestFailure::CompileError);
+            return (instant.elapsed(), Err(TestFailure::CompileError));
         }
         if !rustdoc_options.nocapture {
             // If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -713,7 +766,7 @@ fn run_test(
     let _bomb = Bomb(&out);
     match (output.status.success(), langstr.compile_fail) {
         (true, true) => {
-            return Err(TestFailure::UnexpectedCompilePass);
+            return (instant.elapsed(), Err(TestFailure::UnexpectedCompilePass));
         }
         (true, false) => {}
         (false, true) => {
@@ -729,17 +782,18 @@ fn run_test(
                     .collect();
 
                 if !missing_codes.is_empty() {
-                    return Err(TestFailure::MissingErrorCodes(missing_codes));
+                    return (instant.elapsed(), Err(TestFailure::MissingErrorCodes(missing_codes)));
                 }
             }
         }
         (false, false) => {
-            return Err(TestFailure::CompileError);
+            return (instant.elapsed(), Err(TestFailure::CompileError));
         }
     }
 
+    let duration = instant.elapsed();
     if doctest.no_run {
-        return Ok(());
+        return (duration, Ok(()));
     }
 
     // Run the code!
@@ -771,17 +825,17 @@ fn run_test(
         cmd.output()
     };
     match result {
-        Err(e) => return Err(TestFailure::ExecutionError(e)),
+        Err(e) => return (duration, Err(TestFailure::ExecutionError(e))),
         Ok(out) => {
             if langstr.should_panic && out.status.success() {
-                return Err(TestFailure::UnexpectedRunPass);
+                return (duration, Err(TestFailure::UnexpectedRunPass));
             } else if !langstr.should_panic && !out.status.success() {
-                return Err(TestFailure::ExecutionFailure(out));
+                return (duration, Err(TestFailure::ExecutionFailure(out)));
             }
         }
     }
 
-    Ok(())
+    (duration, Ok(()))
 }
 
 /// Converts a path intended to use as a command to absolute if it is
@@ -1071,7 +1125,7 @@ fn doctest_run_fn(
         no_run: scraped_test.no_run(&rustdoc_options),
         merged_test_code: None,
     };
-    let res =
+    let (_, res) =
         run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
 
     if let Err(err) = res {
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index f0914474c79..fcfa424968e 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -1,4 +1,5 @@
 use std::fmt::Write;
+use std::time::Duration;
 
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::edition::Edition;
@@ -67,6 +68,10 @@ impl DocTestRunner {
         self.nb_tests += 1;
     }
 
+    /// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
+    ///
+    /// If compilation failed, it will return `Err`, otherwise it will return `Ok` containing if
+    /// the test ran successfully.
     pub(crate) fn run_merged_tests(
         &mut self,
         test_options: IndividualTestOptions,
@@ -74,7 +79,7 @@ impl DocTestRunner {
         opts: &GlobalTestOptions,
         test_args: &[String],
         rustdoc_options: &RustdocOptions,
-    ) -> Result<bool, ()> {
+    ) -> (Duration, Result<bool, ()>) {
         let mut code = "\
 #![allow(unused_extern_crates)]
 #![allow(internal_features)]
@@ -204,9 +209,9 @@ std::process::Termination::report(test::test_main(test_args, tests, None))
             no_run: false,
             merged_test_code: Some(code),
         };
-        let ret =
+        let (duration, ret) =
             run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {});
-        if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) }
+        (duration, if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) })
     }
 }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 5191120ebdb..e28cc3a542e 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -4,6 +4,7 @@ use rustc_ast::join_path_syms;
 use rustc_attr_data_structures::StabilityLevel;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
+use rustc_metadata::creader::CStore;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 use tracing::debug;
@@ -158,18 +159,33 @@ impl Cache {
         assert!(cx.external_traits.is_empty());
         cx.cache.traits = mem::take(&mut krate.external_traits);
 
+        let render_options = &cx.render_options;
+        let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
+        let dst = &render_options.output;
+
+        // Make `--extern-html-root-url` support the same names as `--extern` whenever possible
+        let cstore = CStore::from_tcx(tcx);
+        for (name, extern_url) in &render_options.extern_html_root_urls {
+            if let Some(crate_num) = cstore.resolved_extern_crate(Symbol::intern(name)) {
+                let e = ExternalCrate { crate_num };
+                let location = e.location(Some(extern_url), extern_url_takes_precedence, dst, tcx);
+                cx.cache.extern_locations.insert(e.crate_num, location);
+            }
+        }
+
         // Cache where all our extern crates are located
-        // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
+        // This is also used in the JSON output.
         for &crate_num in tcx.crates(()) {
             let e = ExternalCrate { crate_num };
 
             let name = e.name(tcx);
-            let render_options = &cx.render_options;
-            let extern_url = render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u);
-            let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
-            let dst = &render_options.output;
-            let location = e.location(extern_url, extern_url_takes_precedence, dst, tcx);
-            cx.cache.extern_locations.insert(e.crate_num, location);
+            cx.cache.extern_locations.entry(e.crate_num).or_insert_with(|| {
+                // falls back to matching by crates' own names, because
+                // transitive dependencies and injected crates may be loaded without `--extern`
+                let extern_url =
+                    render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u);
+                e.location(extern_url, extern_url_takes_precedence, dst, tcx)
+            });
             cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module));
         }
 
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index a1f76a07556..54511f4fd08 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -12,6 +12,9 @@ use tracing::*;
 use crate::common::{CodegenBackend, Config, Debugger, FailMode, PassMode, RunFailMode, TestMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
 use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
+use crate::directives::directive_names::{
+    KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
+};
 use crate::directives::needs::CachedNeedsConditions;
 use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
@@ -20,6 +23,7 @@ use crate::util::static_regex;
 
 pub(crate) mod auxiliary;
 mod cfg;
+mod directive_names;
 mod needs;
 #[cfg(test)]
 mod tests;
@@ -59,9 +63,9 @@ impl EarlyProps {
             &mut poisoned,
             testfile,
             rdr,
-            &mut |DirectiveLine { raw_directive: ln, .. }| {
-                parse_and_update_aux(config, ln, &mut props.aux);
-                config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
+            &mut |DirectiveLine { line_number, raw_directive: ln, .. }| {
+                parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux);
+                config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions);
             },
         );
 
@@ -351,7 +355,7 @@ impl TestProps {
                 &mut poisoned,
                 testfile,
                 file,
-                &mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
+                &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
                     if !directive.applies_to_test_revision(test_revision) {
                         return;
                     }
@@ -361,17 +365,28 @@ impl TestProps {
                     config.push_name_value_directive(
                         ln,
                         ERROR_PATTERN,
+                        testfile,
+                        line_number,
                         &mut self.error_patterns,
                         |r| r,
                     );
                     config.push_name_value_directive(
                         ln,
                         REGEX_ERROR_PATTERN,
+                        testfile,
+                        line_number,
                         &mut self.regex_error_patterns,
                         |r| r,
                     );
 
-                    config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
+                    config.push_name_value_directive(
+                        ln,
+                        DOC_FLAGS,
+                        testfile,
+                        line_number,
+                        &mut self.doc_flags,
+                        |r| r,
+                    );
 
                     fn split_flags(flags: &str) -> Vec<String> {
                         // Individual flags can be single-quoted to preserve spaces; see
@@ -386,7 +401,9 @@ impl TestProps {
                             .collect::<Vec<_>>()
                     }
 
-                    if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
+                    if let Some(flags) =
+                        config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number)
+                    {
                         let flags = split_flags(&flags);
                         for flag in &flags {
                             if flag == "--edition" || flag.starts_with("--edition=") {
@@ -395,25 +412,40 @@ impl TestProps {
                         }
                         self.compile_flags.extend(flags);
                     }
-                    if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
+                    if config
+                        .parse_name_value_directive(
+                            ln,
+                            INCORRECT_COMPILER_FLAGS,
+                            testfile,
+                            line_number,
+                        )
+                        .is_some()
+                    {
                         panic!("`compiler-flags` directive should be spelled `compile-flags`");
                     }
 
-                    if let Some(edition) = config.parse_edition(ln) {
+                    if let Some(edition) = config.parse_edition(ln, testfile, line_number) {
                         // The edition is added at the start, since flags from //@compile-flags must
                         // be passed to rustc last.
                         self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
                         has_edition = true;
                     }
 
-                    config.parse_and_update_revisions(testfile, ln, &mut self.revisions);
+                    config.parse_and_update_revisions(
+                        testfile,
+                        line_number,
+                        ln,
+                        &mut self.revisions,
+                    );
 
-                    if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) {
+                    if let Some(flags) =
+                        config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number)
+                    {
                         self.run_flags.extend(split_flags(&flags));
                     }
 
                     if self.pp_exact.is_none() {
-                        self.pp_exact = config.parse_pp_exact(ln, testfile);
+                        self.pp_exact = config.parse_pp_exact(ln, testfile, line_number);
                     }
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
@@ -435,7 +467,9 @@ impl TestProps {
                     );
                     config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
 
-                    if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) {
+                    if let Some(m) =
+                        config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number)
+                    {
                         self.pretty_mode = m;
                     }
 
@@ -446,35 +480,45 @@ impl TestProps {
                     );
 
                     // Call a helper method to deal with aux-related directives.
-                    parse_and_update_aux(config, ln, &mut self.aux);
+                    parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux);
 
                     config.push_name_value_directive(
                         ln,
                         EXEC_ENV,
+                        testfile,
+                        line_number,
                         &mut self.exec_env,
                         Config::parse_env,
                     );
                     config.push_name_value_directive(
                         ln,
                         UNSET_EXEC_ENV,
+                        testfile,
+                        line_number,
                         &mut self.unset_exec_env,
                         |r| r.trim().to_owned(),
                     );
                     config.push_name_value_directive(
                         ln,
                         RUSTC_ENV,
+                        testfile,
+                        line_number,
                         &mut self.rustc_env,
                         Config::parse_env,
                     );
                     config.push_name_value_directive(
                         ln,
                         UNSET_RUSTC_ENV,
+                        testfile,
+                        line_number,
                         &mut self.unset_rustc_env,
                         |r| r.trim().to_owned(),
                     );
                     config.push_name_value_directive(
                         ln,
                         FORBID_OUTPUT,
+                        testfile,
+                        line_number,
                         &mut self.forbid_output,
                         |r| r,
                     );
@@ -510,7 +554,7 @@ impl TestProps {
                     }
 
                     if let Some(code) = config
-                        .parse_name_value_directive(ln, FAILURE_STATUS)
+                        .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number)
                         .and_then(|code| code.trim().parse::<i32>().ok())
                     {
                         self.failure_status = Some(code);
@@ -531,6 +575,8 @@ impl TestProps {
                     config.set_name_value_directive(
                         ln,
                         ASSEMBLY_OUTPUT,
+                        testfile,
+                        line_number,
                         &mut self.assembly_output,
                         |r| r.trim().to_string(),
                     );
@@ -543,7 +589,9 @@ impl TestProps {
 
                     // Unlike the other `name_value_directive`s this needs to be handled manually,
                     // because it sets a `bool` flag.
-                    if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) {
+                    if let Some(known_bug) =
+                        config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number)
+                    {
                         let known_bug = known_bug.trim();
                         if known_bug == "unknown"
                             || known_bug.split(',').all(|issue_ref| {
@@ -571,16 +619,25 @@ impl TestProps {
                     config.set_name_value_directive(
                         ln,
                         TEST_MIR_PASS,
+                        testfile,
+                        line_number,
                         &mut self.mir_unit_test,
                         |s| s.trim().to_string(),
                     );
                     config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
 
-                    if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) {
+                    if let Some(flags) =
+                        config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number)
+                    {
                         self.llvm_cov_flags.extend(split_flags(&flags));
                     }
 
-                    if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) {
+                    if let Some(flags) = config.parse_name_value_directive(
+                        ln,
+                        FILECHECK_FLAGS,
+                        testfile,
+                        line_number,
+                    ) {
                         self.filecheck_flags.extend(split_flags(&flags));
                     }
 
@@ -588,9 +645,12 @@ impl TestProps {
 
                     self.update_add_core_stubs(ln, config);
 
-                    if let Some(err_kind) =
-                        config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
-                    {
+                    if let Some(err_kind) = config.parse_name_value_directive(
+                        ln,
+                        DONT_REQUIRE_ANNOTATIONS,
+                        testfile,
+                        line_number,
+                    ) {
                         self.dont_require_annotations
                             .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
                     }
@@ -769,296 +829,6 @@ fn line_directive<'line>(
     Some(DirectiveLine { line_number, revision, raw_directive })
 }
 
-/// This was originally generated by collecting directives from ui tests and then extracting their
-/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
-const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
-    // tidy-alphabetical-start
-    "add-core-stubs",
-    "assembly-output",
-    "aux-bin",
-    "aux-build",
-    "aux-codegen-backend",
-    "aux-crate",
-    "build-aux-docs",
-    "build-fail",
-    "build-pass",
-    "check-fail",
-    "check-pass",
-    "check-run-results",
-    "check-stdout",
-    "check-test-line-numbers-match",
-    "compile-flags",
-    "doc-flags",
-    "dont-check-compiler-stderr",
-    "dont-check-compiler-stdout",
-    "dont-check-failure-status",
-    "dont-require-annotations",
-    "edition",
-    "error-pattern",
-    "exact-llvm-major-version",
-    "exec-env",
-    "failure-status",
-    "filecheck-flags",
-    "forbid-output",
-    "force-host",
-    "ignore-16bit",
-    "ignore-32bit",
-    "ignore-64bit",
-    "ignore-aarch64",
-    "ignore-aarch64-pc-windows-msvc",
-    "ignore-aarch64-unknown-linux-gnu",
-    "ignore-aix",
-    "ignore-android",
-    "ignore-apple",
-    "ignore-arm",
-    "ignore-arm-unknown-linux-gnueabi",
-    "ignore-arm-unknown-linux-gnueabihf",
-    "ignore-arm-unknown-linux-musleabi",
-    "ignore-arm-unknown-linux-musleabihf",
-    "ignore-auxiliary",
-    "ignore-avr",
-    "ignore-backends",
-    "ignore-beta",
-    "ignore-cdb",
-    "ignore-compare-mode-next-solver",
-    "ignore-compare-mode-polonius",
-    "ignore-coverage-map",
-    "ignore-coverage-run",
-    "ignore-cross-compile",
-    "ignore-eabi",
-    "ignore-elf",
-    "ignore-emscripten",
-    "ignore-endian-big",
-    "ignore-enzyme",
-    "ignore-freebsd",
-    "ignore-fuchsia",
-    "ignore-gdb",
-    "ignore-gdb-version",
-    "ignore-gnu",
-    "ignore-haiku",
-    "ignore-horizon",
-    "ignore-i686-pc-windows-gnu",
-    "ignore-i686-pc-windows-msvc",
-    "ignore-illumos",
-    "ignore-ios",
-    "ignore-linux",
-    "ignore-lldb",
-    "ignore-llvm-version",
-    "ignore-loongarch32",
-    "ignore-loongarch64",
-    "ignore-macabi",
-    "ignore-macos",
-    "ignore-msp430",
-    "ignore-msvc",
-    "ignore-musl",
-    "ignore-netbsd",
-    "ignore-nightly",
-    "ignore-none",
-    "ignore-nto",
-    "ignore-nvptx64",
-    "ignore-nvptx64-nvidia-cuda",
-    "ignore-openbsd",
-    "ignore-pass",
-    "ignore-powerpc",
-    "ignore-powerpc64",
-    "ignore-remote",
-    "ignore-riscv64",
-    "ignore-rustc-debug-assertions",
-    "ignore-rustc_abi-x86-sse2",
-    "ignore-s390x",
-    "ignore-sgx",
-    "ignore-sparc64",
-    "ignore-spirv",
-    "ignore-stable",
-    "ignore-stage1",
-    "ignore-stage2",
-    "ignore-std-debug-assertions",
-    "ignore-test",
-    "ignore-thumb",
-    "ignore-thumbv8m.base-none-eabi",
-    "ignore-thumbv8m.main-none-eabi",
-    "ignore-tvos",
-    "ignore-unix",
-    "ignore-unknown",
-    "ignore-uwp",
-    "ignore-visionos",
-    "ignore-vxworks",
-    "ignore-wasi",
-    "ignore-wasm",
-    "ignore-wasm32",
-    "ignore-wasm32-bare",
-    "ignore-wasm64",
-    "ignore-watchos",
-    "ignore-windows",
-    "ignore-windows-gnu",
-    "ignore-windows-msvc",
-    "ignore-x32",
-    "ignore-x86",
-    "ignore-x86_64",
-    "ignore-x86_64-apple-darwin",
-    "ignore-x86_64-pc-windows-gnu",
-    "ignore-x86_64-unknown-linux-gnu",
-    "incremental",
-    "known-bug",
-    "llvm-cov-flags",
-    "max-llvm-major-version",
-    "min-cdb-version",
-    "min-gdb-version",
-    "min-lldb-version",
-    "min-llvm-version",
-    "min-system-llvm-version",
-    "needs-asm-support",
-    "needs-backends",
-    "needs-crate-type",
-    "needs-deterministic-layouts",
-    "needs-dlltool",
-    "needs-dynamic-linking",
-    "needs-enzyme",
-    "needs-force-clang-based-tests",
-    "needs-git-hash",
-    "needs-llvm-components",
-    "needs-llvm-zstd",
-    "needs-profiler-runtime",
-    "needs-relocation-model-pic",
-    "needs-run-enabled",
-    "needs-rust-lld",
-    "needs-rustc-debug-assertions",
-    "needs-sanitizer-address",
-    "needs-sanitizer-cfi",
-    "needs-sanitizer-dataflow",
-    "needs-sanitizer-hwaddress",
-    "needs-sanitizer-kcfi",
-    "needs-sanitizer-leak",
-    "needs-sanitizer-memory",
-    "needs-sanitizer-memtag",
-    "needs-sanitizer-safestack",
-    "needs-sanitizer-shadow-call-stack",
-    "needs-sanitizer-support",
-    "needs-sanitizer-thread",
-    "needs-std-debug-assertions",
-    "needs-subprocess",
-    "needs-symlink",
-    "needs-target-has-atomic",
-    "needs-target-std",
-    "needs-threads",
-    "needs-unwind",
-    "needs-wasmtime",
-    "needs-xray",
-    "no-auto-check-cfg",
-    "no-prefer-dynamic",
-    "normalize-stderr",
-    "normalize-stderr-32bit",
-    "normalize-stderr-64bit",
-    "normalize-stdout",
-    "only-16bit",
-    "only-32bit",
-    "only-64bit",
-    "only-aarch64",
-    "only-aarch64-apple-darwin",
-    "only-aarch64-unknown-linux-gnu",
-    "only-apple",
-    "only-arm",
-    "only-avr",
-    "only-beta",
-    "only-bpf",
-    "only-cdb",
-    "only-dist",
-    "only-elf",
-    "only-emscripten",
-    "only-gnu",
-    "only-i686-pc-windows-gnu",
-    "only-i686-pc-windows-msvc",
-    "only-i686-unknown-linux-gnu",
-    "only-ios",
-    "only-linux",
-    "only-loongarch32",
-    "only-loongarch64",
-    "only-loongarch64-unknown-linux-gnu",
-    "only-macos",
-    "only-mips",
-    "only-mips64",
-    "only-msp430",
-    "only-msvc",
-    "only-musl",
-    "only-nightly",
-    "only-nvptx64",
-    "only-powerpc",
-    "only-riscv64",
-    "only-rustc_abi-x86-sse2",
-    "only-s390x",
-    "only-sparc",
-    "only-sparc64",
-    "only-stable",
-    "only-thumb",
-    "only-tvos",
-    "only-uefi",
-    "only-unix",
-    "only-visionos",
-    "only-wasm32",
-    "only-wasm32-bare",
-    "only-wasm32-wasip1",
-    "only-watchos",
-    "only-windows",
-    "only-windows-gnu",
-    "only-windows-msvc",
-    "only-x86",
-    "only-x86_64",
-    "only-x86_64-apple-darwin",
-    "only-x86_64-fortanix-unknown-sgx",
-    "only-x86_64-pc-windows-gnu",
-    "only-x86_64-pc-windows-msvc",
-    "only-x86_64-unknown-linux-gnu",
-    "pp-exact",
-    "pretty-compare-only",
-    "pretty-mode",
-    "proc-macro",
-    "reference",
-    "regex-error-pattern",
-    "remap-src-base",
-    "revisions",
-    "run-crash",
-    "run-fail",
-    "run-fail-or-crash",
-    "run-flags",
-    "run-pass",
-    "run-rustfix",
-    "rustc-env",
-    "rustfix-only-machine-applicable",
-    "should-fail",
-    "should-ice",
-    "stderr-per-bitwidth",
-    "test-mir-pass",
-    "unique-doc-out-dir",
-    "unset-exec-env",
-    "unset-rustc-env",
-    // Used by the tidy check `unknown_revision`.
-    "unused-revision-names",
-    // tidy-alphabetical-end
-];
-
-const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
-    "count",
-    "!count",
-    "files",
-    "!files",
-    "has",
-    "!has",
-    "has-dir",
-    "!has-dir",
-    "hasraw",
-    "!hasraw",
-    "matches",
-    "!matches",
-    "matchesraw",
-    "!matchesraw",
-    "snapshot",
-    "!snapshot",
-];
-
-const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
-    &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
-
 /// The (partly) broken-down contents of a line containing a test directive,
 /// which [`iter_directives`] passes to its callback function.
 ///
@@ -1206,6 +976,7 @@ impl Config {
     fn parse_and_update_revisions(
         &self,
         testfile: &Utf8Path,
+        line_number: usize,
         line: &str,
         existing: &mut Vec<String>,
     ) {
@@ -1219,7 +990,8 @@ impl Config {
         const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
             ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
 
-        if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
+        if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
+        {
             if self.mode == TestMode::RunMake {
                 panic!("`run-make` tests do not support revisions: {}", testfile);
             }
@@ -1264,8 +1036,13 @@ impl Config {
         (name.to_owned(), value.to_owned())
     }
 
-    fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
-        if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
+    fn parse_pp_exact(
+        &self,
+        line: &str,
+        testfile: &Utf8Path,
+        line_number: usize,
+    ) -> Option<Utf8PathBuf> {
+        if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) {
             Some(Utf8PathBuf::from(&s))
         } else if self.parse_name_directive(line, "pp-exact") {
             testfile.file_name().map(Utf8PathBuf::from)
@@ -1306,19 +1083,31 @@ impl Config {
         line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
     }
 
-    pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
+    pub fn parse_name_value_directive(
+        &self,
+        line: &str,
+        directive: &str,
+        testfile: &Utf8Path,
+        line_number: usize,
+    ) -> Option<String> {
         let colon = directive.len();
         if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
             let value = line[(colon + 1)..].to_owned();
             debug!("{}: {}", directive, value);
-            Some(expand_variables(value, self))
+            let value = expand_variables(value, self);
+            if value.is_empty() {
+                error!("{testfile}:{line_number}: empty value for directive `{directive}`");
+                help!("expected syntax is: `{directive}: value`");
+                panic!("empty directive value detected");
+            }
+            Some(value)
         } else {
             None
         }
     }
 
-    fn parse_edition(&self, line: &str) -> Option<String> {
-        self.parse_name_value_directive(line, "edition")
+    fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> {
+        self.parse_name_value_directive(line, "edition", testfile, line_number)
     }
 
     fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
@@ -1340,11 +1129,14 @@ impl Config {
         &self,
         line: &str,
         directive: &str,
+        testfile: &Utf8Path,
+        line_number: usize,
         value: &mut Option<T>,
         parse: impl FnOnce(String) -> T,
     ) {
         if value.is_none() {
-            *value = self.parse_name_value_directive(line, directive).map(parse);
+            *value =
+                self.parse_name_value_directive(line, directive, testfile, line_number).map(parse);
         }
     }
 
@@ -1352,10 +1144,14 @@ impl Config {
         &self,
         line: &str,
         directive: &str,
+        testfile: &Utf8Path,
+        line_number: usize,
         values: &mut Vec<T>,
         parse: impl FnOnce(String) -> T,
     ) {
-        if let Some(value) = self.parse_name_value_directive(line, directive).map(parse) {
+        if let Some(value) =
+            self.parse_name_value_directive(line, directive, testfile, line_number).map(parse)
+        {
             values.push(value);
         }
     }
@@ -1672,9 +1468,9 @@ pub(crate) fn make_test_description<R: Read>(
             decision!(cfg::handle_ignore(config, ln));
             decision!(cfg::handle_only(config, ln));
             decision!(needs::handle_needs(&cache.needs, config, ln));
-            decision!(ignore_llvm(config, path, ln));
-            decision!(ignore_backends(config, path, ln));
-            decision!(needs_backends(config, path, ln));
+            decision!(ignore_llvm(config, path, ln, line_number));
+            decision!(ignore_backends(config, path, ln, line_number));
+            decision!(needs_backends(config, path, ln, line_number));
             decision!(ignore_cdb(config, ln));
             decision!(ignore_gdb(config, ln));
             decision!(ignore_lldb(config, ln));
@@ -1801,8 +1597,15 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
-    if let Some(backends_to_ignore) = config.parse_name_value_directive(line, "ignore-backends") {
+fn ignore_backends(
+    config: &Config,
+    path: &Utf8Path,
+    line: &str,
+    line_number: usize,
+) -> IgnoreDecision {
+    if let Some(backends_to_ignore) =
+        config.parse_name_value_directive(line, "ignore-backends", path, line_number)
+    {
         for backend in backends_to_ignore.split_whitespace().map(|backend| {
             match CodegenBackend::try_from(backend) {
                 Ok(backend) => backend,
@@ -1821,8 +1624,15 @@ fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisi
     IgnoreDecision::Continue
 }
 
-fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
-    if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends") {
+fn needs_backends(
+    config: &Config,
+    path: &Utf8Path,
+    line: &str,
+    line_number: usize,
+) -> IgnoreDecision {
+    if let Some(needed_backends) =
+        config.parse_name_value_directive(line, "needs-backends", path, line_number)
+    {
         if !needed_backends
             .split_whitespace()
             .map(|backend| match CodegenBackend::try_from(backend) {
@@ -1844,9 +1654,9 @@ fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisio
     IgnoreDecision::Continue
 }
 
-fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision {
     if let Some(needed_components) =
-        config.parse_name_value_directive(line, "needs-llvm-components")
+        config.parse_name_value_directive(line, "needs-llvm-components", path, line_number)
     {
         let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
         if let Some(missing_component) = needed_components
@@ -1867,7 +1677,9 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
     if let Some(actual_version) = &config.llvm_version {
         // Note that these `min` versions will check for not just major versions.
 
-        if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") {
+        if let Some(version_string) =
+            config.parse_name_value_directive(line, "min-llvm-version", path, line_number)
+        {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if actual version is smaller than the minimum required version.
             if *actual_version < min_version {
@@ -1878,7 +1690,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "max-llvm-major-version")
+            config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number)
         {
             let max_version = extract_llvm_version(&version_string);
             // Ignore if actual major version is larger than the maximum required major version.
@@ -1892,7 +1704,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "min-system-llvm-version")
+            config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number)
         {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if using system LLVM and actual version
@@ -1905,7 +1717,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
                 };
             }
         } else if let Some(version_range) =
-            config.parse_name_value_directive(line, "ignore-llvm-version")
+            config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number)
         {
             // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
             let (v_min, v_max) =
@@ -1931,7 +1743,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
                 }
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "exact-llvm-major-version")
+            config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number)
         {
             // Syntax is "exact-llvm-major-version: <version>"
             let version = extract_llvm_version(&version_string);
diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index cdb75f6ffa9..7c1ed2e7006 100644
--- a/src/tools/compiletest/src/directives/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -3,6 +3,8 @@
 
 use std::iter;
 
+use camino::Utf8Path;
+
 use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
 
@@ -41,17 +43,42 @@ impl AuxProps {
 
 /// If the given test directive line contains an `aux-*` directive, parse it
 /// and update [`AuxProps`] accordingly.
-pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) {
+pub(super) fn parse_and_update_aux(
+    config: &Config,
+    ln: &str,
+    testfile: &Utf8Path,
+    line_number: usize,
+    aux: &mut AuxProps,
+) {
     if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
         return;
     }
 
-    config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string());
-    config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string());
-    config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate);
-    config
-        .push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string());
-    if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) {
+    config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| {
+        r.trim().to_string()
+    });
+    config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| {
+        r.trim().to_string()
+    });
+    config.push_name_value_directive(
+        ln,
+        AUX_CRATE,
+        testfile,
+        line_number,
+        &mut aux.crates,
+        parse_aux_crate,
+    );
+    config.push_name_value_directive(
+        ln,
+        PROC_MACRO,
+        testfile,
+        line_number,
+        &mut aux.proc_macros,
+        |r| r.trim().to_string(),
+    );
+    if let Some(r) =
+        config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number)
+    {
         aux.codegen_backend = Some(r.trim().to_owned());
     }
 }
diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs
new file mode 100644
index 00000000000..7fc76a42e0c
--- /dev/null
+++ b/src/tools/compiletest/src/directives/directive_names.rs
@@ -0,0 +1,289 @@
+/// This was originally generated by collecting directives from ui tests and then extracting their
+/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
+/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
+pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
+    // tidy-alphabetical-start
+    "add-core-stubs",
+    "assembly-output",
+    "aux-bin",
+    "aux-build",
+    "aux-codegen-backend",
+    "aux-crate",
+    "build-aux-docs",
+    "build-fail",
+    "build-pass",
+    "check-fail",
+    "check-pass",
+    "check-run-results",
+    "check-stdout",
+    "check-test-line-numbers-match",
+    "compile-flags",
+    "doc-flags",
+    "dont-check-compiler-stderr",
+    "dont-check-compiler-stdout",
+    "dont-check-failure-status",
+    "dont-require-annotations",
+    "edition",
+    "error-pattern",
+    "exact-llvm-major-version",
+    "exec-env",
+    "failure-status",
+    "filecheck-flags",
+    "forbid-output",
+    "force-host",
+    "ignore-16bit",
+    "ignore-32bit",
+    "ignore-64bit",
+    "ignore-aarch64",
+    "ignore-aarch64-pc-windows-msvc",
+    "ignore-aarch64-unknown-linux-gnu",
+    "ignore-aix",
+    "ignore-android",
+    "ignore-apple",
+    "ignore-arm",
+    "ignore-arm-unknown-linux-gnueabi",
+    "ignore-arm-unknown-linux-gnueabihf",
+    "ignore-arm-unknown-linux-musleabi",
+    "ignore-arm-unknown-linux-musleabihf",
+    "ignore-auxiliary",
+    "ignore-avr",
+    "ignore-backends",
+    "ignore-beta",
+    "ignore-cdb",
+    "ignore-compare-mode-next-solver",
+    "ignore-compare-mode-polonius",
+    "ignore-coverage-map",
+    "ignore-coverage-run",
+    "ignore-cross-compile",
+    "ignore-eabi",
+    "ignore-elf",
+    "ignore-emscripten",
+    "ignore-endian-big",
+    "ignore-enzyme",
+    "ignore-freebsd",
+    "ignore-fuchsia",
+    "ignore-gdb",
+    "ignore-gdb-version",
+    "ignore-gnu",
+    "ignore-haiku",
+    "ignore-horizon",
+    "ignore-i686-pc-windows-gnu",
+    "ignore-i686-pc-windows-msvc",
+    "ignore-illumos",
+    "ignore-ios",
+    "ignore-linux",
+    "ignore-lldb",
+    "ignore-llvm-version",
+    "ignore-loongarch32",
+    "ignore-loongarch64",
+    "ignore-macabi",
+    "ignore-macos",
+    "ignore-msp430",
+    "ignore-msvc",
+    "ignore-musl",
+    "ignore-netbsd",
+    "ignore-nightly",
+    "ignore-none",
+    "ignore-nto",
+    "ignore-nvptx64",
+    "ignore-nvptx64-nvidia-cuda",
+    "ignore-openbsd",
+    "ignore-pass",
+    "ignore-powerpc",
+    "ignore-powerpc64",
+    "ignore-remote",
+    "ignore-riscv64",
+    "ignore-rustc-debug-assertions",
+    "ignore-rustc_abi-x86-sse2",
+    "ignore-s390x",
+    "ignore-sgx",
+    "ignore-sparc64",
+    "ignore-spirv",
+    "ignore-stable",
+    "ignore-stage1",
+    "ignore-stage2",
+    "ignore-std-debug-assertions",
+    "ignore-test",
+    "ignore-thumb",
+    "ignore-thumbv8m.base-none-eabi",
+    "ignore-thumbv8m.main-none-eabi",
+    "ignore-tvos",
+    "ignore-unix",
+    "ignore-unknown",
+    "ignore-uwp",
+    "ignore-visionos",
+    "ignore-vxworks",
+    "ignore-wasi",
+    "ignore-wasm",
+    "ignore-wasm32",
+    "ignore-wasm32-bare",
+    "ignore-wasm64",
+    "ignore-watchos",
+    "ignore-windows",
+    "ignore-windows-gnu",
+    "ignore-windows-msvc",
+    "ignore-x32",
+    "ignore-x86",
+    "ignore-x86_64",
+    "ignore-x86_64-apple-darwin",
+    "ignore-x86_64-pc-windows-gnu",
+    "ignore-x86_64-unknown-linux-gnu",
+    "incremental",
+    "known-bug",
+    "llvm-cov-flags",
+    "max-llvm-major-version",
+    "min-cdb-version",
+    "min-gdb-version",
+    "min-lldb-version",
+    "min-llvm-version",
+    "min-system-llvm-version",
+    "needs-asm-support",
+    "needs-backends",
+    "needs-crate-type",
+    "needs-deterministic-layouts",
+    "needs-dlltool",
+    "needs-dynamic-linking",
+    "needs-enzyme",
+    "needs-force-clang-based-tests",
+    "needs-git-hash",
+    "needs-llvm-components",
+    "needs-llvm-zstd",
+    "needs-profiler-runtime",
+    "needs-relocation-model-pic",
+    "needs-run-enabled",
+    "needs-rust-lld",
+    "needs-rustc-debug-assertions",
+    "needs-sanitizer-address",
+    "needs-sanitizer-cfi",
+    "needs-sanitizer-dataflow",
+    "needs-sanitizer-hwaddress",
+    "needs-sanitizer-kcfi",
+    "needs-sanitizer-leak",
+    "needs-sanitizer-memory",
+    "needs-sanitizer-memtag",
+    "needs-sanitizer-safestack",
+    "needs-sanitizer-shadow-call-stack",
+    "needs-sanitizer-support",
+    "needs-sanitizer-thread",
+    "needs-std-debug-assertions",
+    "needs-subprocess",
+    "needs-symlink",
+    "needs-target-has-atomic",
+    "needs-target-std",
+    "needs-threads",
+    "needs-unwind",
+    "needs-wasmtime",
+    "needs-xray",
+    "no-auto-check-cfg",
+    "no-prefer-dynamic",
+    "normalize-stderr",
+    "normalize-stderr-32bit",
+    "normalize-stderr-64bit",
+    "normalize-stdout",
+    "only-16bit",
+    "only-32bit",
+    "only-64bit",
+    "only-aarch64",
+    "only-aarch64-apple-darwin",
+    "only-aarch64-unknown-linux-gnu",
+    "only-apple",
+    "only-arm",
+    "only-avr",
+    "only-beta",
+    "only-bpf",
+    "only-cdb",
+    "only-dist",
+    "only-elf",
+    "only-emscripten",
+    "only-gnu",
+    "only-i686-pc-windows-gnu",
+    "only-i686-pc-windows-msvc",
+    "only-i686-unknown-linux-gnu",
+    "only-ios",
+    "only-linux",
+    "only-loongarch32",
+    "only-loongarch64",
+    "only-loongarch64-unknown-linux-gnu",
+    "only-macos",
+    "only-mips",
+    "only-mips64",
+    "only-msp430",
+    "only-msvc",
+    "only-musl",
+    "only-nightly",
+    "only-nvptx64",
+    "only-powerpc",
+    "only-riscv64",
+    "only-rustc_abi-x86-sse2",
+    "only-s390x",
+    "only-sparc",
+    "only-sparc64",
+    "only-stable",
+    "only-thumb",
+    "only-tvos",
+    "only-uefi",
+    "only-unix",
+    "only-visionos",
+    "only-wasm32",
+    "only-wasm32-bare",
+    "only-wasm32-wasip1",
+    "only-watchos",
+    "only-windows",
+    "only-windows-gnu",
+    "only-windows-msvc",
+    "only-x86",
+    "only-x86_64",
+    "only-x86_64-apple-darwin",
+    "only-x86_64-fortanix-unknown-sgx",
+    "only-x86_64-pc-windows-gnu",
+    "only-x86_64-pc-windows-msvc",
+    "only-x86_64-unknown-linux-gnu",
+    "pp-exact",
+    "pretty-compare-only",
+    "pretty-mode",
+    "proc-macro",
+    "reference",
+    "regex-error-pattern",
+    "remap-src-base",
+    "revisions",
+    "run-crash",
+    "run-fail",
+    "run-fail-or-crash",
+    "run-flags",
+    "run-pass",
+    "run-rustfix",
+    "rustc-env",
+    "rustfix-only-machine-applicable",
+    "should-fail",
+    "should-ice",
+    "stderr-per-bitwidth",
+    "test-mir-pass",
+    "unique-doc-out-dir",
+    "unset-exec-env",
+    "unset-rustc-env",
+    // Used by the tidy check `unknown_revision`.
+    "unused-revision-names",
+    // tidy-alphabetical-end
+];
+
+pub(crate) const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
+    "count",
+    "!count",
+    "files",
+    "!files",
+    "has",
+    "!has",
+    "has-dir",
+    "!has-dir",
+    "hasraw",
+    "!hasraw",
+    "matches",
+    "!matches",
+    "matchesraw",
+    "!matchesraw",
+    "snapshot",
+    "!snapshot",
+];
+
+pub(crate) const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
+    &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index a4103c5b4a9..ba824124e87 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -47,10 +47,14 @@ impl DebuggerCommands {
                 continue;
             };
 
-            if let Some(command) = config.parse_name_value_directive(&line, &command_directive) {
+            if let Some(command) =
+                config.parse_name_value_directive(&line, &command_directive, file, line_no)
+            {
                 commands.push(command);
             }
-            if let Some(pattern) = config.parse_name_value_directive(&line, &check_directive) {
+            if let Some(pattern) =
+                config.parse_name_value_directive(&line, &check_directive, file, line_no)
+            {
                 check_lines.push((line_no, pattern));
             }
         }
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
-Subproject 6a70166b92a1b1560cb3cf056427b011b2a1f2b
+Subproject dde879cf1087cb34a32287bd8ccc4d545bb9fee
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 8e2a796106f..858b058cb7d 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -167,7 +167,7 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
     ("brotli-decompressor", "BSD-3-Clause/MIT"),
     ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"),
     ("inferno", "CDDL-1.0"),
-    ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more.
+    ("option-ext", "MPL-2.0"),
     ("ryu", "Apache-2.0 OR BSL-1.0"),
     ("snap", "BSD-3-Clause"),
     ("subtle", "BSD-3-Clause"),
@@ -226,20 +226,6 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[
     ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptable, but we use it under MIT OR Apache-2.0
 ];
 
-/// Placeholder for non-standard license file.
-const NON_STANDARD_LICENSE: &str = "NON_STANDARD_LICENSE";
-
-/// These dependencies have non-standard licenses but are genenrally permitted.
-const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[
-    // `ring` is included because it is an optional dependency of `hyper`,
-    // which is a training data in rustc-perf for optimized build.
-    // The license of it is generally `ISC AND MIT AND OpenSSL`,
-    // though the `package.license` field is not set.
-    //
-    // See https://github.com/briansmith/ring/issues/902
-    "ring",
-];
-
 const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
@@ -599,7 +585,7 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
             .other_options(vec!["--locked".to_owned()]);
         let metadata = t!(cmd.exec());
 
-        check_license_exceptions(&metadata, exceptions, bad);
+        check_license_exceptions(&metadata, workspace, exceptions, bad);
         if let Some((crates, permitted_deps)) = permitted_deps {
             check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
         }
@@ -730,14 +716,19 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
 /// Check that all licenses of tool dependencies are in the valid list in `LICENSES`.
 ///
 /// Packages listed in `exceptions` are allowed for tools.
-fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], bad: &mut bool) {
+fn check_license_exceptions(
+    metadata: &Metadata,
+    workspace: &str,
+    exceptions: &[(&str, &str)],
+    bad: &mut bool,
+) {
     // Validate the EXCEPTIONS list hasn't changed.
     for (name, license) in exceptions {
         // Check that the package actually exists.
         if !metadata.packages.iter().any(|p| *p.name == *name) {
             tidy_error!(
                 bad,
-                "could not find exception package `{}`\n\
+                "could not find exception package `{}` in workspace `{workspace}`\n\
                 Remove from EXCEPTIONS list if it is no longer used.",
                 name
             );
@@ -746,20 +737,17 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba
         for pkg in metadata.packages.iter().filter(|p| *p.name == *name) {
             match &pkg.license {
                 None => {
-                    if *license == NON_STANDARD_LICENSE
-                        && EXCEPTIONS_NON_STANDARD_LICENSE_DEPS.contains(&pkg.name.as_str())
-                    {
-                        continue;
-                    }
                     tidy_error!(
                         bad,
-                        "dependency exception `{}` does not declare a license expression",
+                        "dependency exception `{}` in workspace `{workspace}` does not declare a license expression",
                         pkg.id
                     );
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        println!("dependency exception `{name}` license has changed");
+                        println!(
+                            "dependency exception `{name}` license in workspace `{workspace}` has changed"
+                        );
                         println!("    previously `{license}` now `{pkg_license}`");
                         println!("    update EXCEPTIONS for the new license");
                         *bad = true;
@@ -783,12 +771,21 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba
         let license = match &pkg.license {
             Some(license) => license,
             None => {
-                tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
+                tidy_error!(
+                    bad,
+                    "dependency `{}` in workspace `{workspace}` does not define a license expression",
+                    pkg.id
+                );
                 continue;
             }
         };
         if !LICENSES.contains(&license.as_str()) {
-            tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
+            tidy_error!(
+                bad,
+                "invalid license `{}` for package `{}` in workspace `{workspace}`",
+                license,
+                pkg.id
+            );
         }
     }
 }
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 35ed61eacc7..fca097c091b 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -519,8 +519,11 @@ pub fn check(path: &Path, bad: &mut bool) {
                         .any(|directive| matches!(directive, Directive::Ignore(_)));
                 let has_alphabetical_directive = line.contains("tidy-alphabetical-start")
                     || line.contains("tidy-alphabetical-end");
-                let has_recognized_directive =
-                    has_recognized_ignore_directive || has_alphabetical_directive;
+                let has_other_tidy_ignore_directive =
+                    line.contains("ignore-tidy-target-specific-tests");
+                let has_recognized_directive = has_recognized_ignore_directive
+                    || has_alphabetical_directive
+                    || has_other_tidy_ignore_directive;
                 if contains_potential_directive && (!has_recognized_directive) {
                     err("Unrecognized tidy directive")
                 }
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index f4a6783abb6..b2d5f259eb2 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -12,12 +12,16 @@ const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
 
 #[derive(Default, Debug)]
 struct RevisionInfo<'a> {
-    target_arch: Option<&'a str>,
+    target_arch: Option<Option<&'a str>>,
     llvm_components: Option<Vec<&'a str>>,
 }
 
 pub fn check(tests_path: &Path, bad: &mut bool) {
     crate::walk::walk(tests_path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
+        if content.contains("// ignore-tidy-target-specific-tests") {
+            return;
+        }
+
         let file = entry.path().display();
         let mut header_map = BTreeMap::new();
         iter_header(content, &mut |HeaderLine { revision, directive, .. }| {
@@ -34,10 +38,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                 && let Some((_, v)) = compile_flags.split_once("--target")
             {
                 let v = v.trim_start_matches([' ', '=']);
-                let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
-                if let Some((arch, _)) = v {
-                    let info = header_map.entry(revision).or_insert(RevisionInfo::default());
-                    info.target_arch.replace(arch);
+                let info = header_map.entry(revision).or_insert(RevisionInfo::default());
+                if v.starts_with("{{") {
+                    info.target_arch.replace(None);
+                } else if let Some((arch, _)) = v.split_once("-") {
+                    info.target_arch.replace(Some(arch));
                 } else {
                     eprintln!("{file}: seems to have a malformed --target value");
                     *bad = true;
@@ -54,9 +59,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
             let rev = rev.unwrap_or("[unspecified]");
             match (target_arch, llvm_components) {
                 (None, None) => {}
-                (Some(_), None) => {
+                (Some(target_arch), None) => {
+                    let llvm_component =
+                        target_arch.map_or_else(|| "<arch>".to_string(), arch_to_llvm_component);
                     eprintln!(
-                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER}` as it has `--target` set"
+                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
                     );
                     *bad = true;
                 }
@@ -66,11 +73,45 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                     );
                     *bad = true;
                 }
-                (Some(_), Some(_)) => {
-                    // FIXME: check specified components against the target architectures we
-                    // gathered.
+                (Some(target_arch), Some(llvm_components)) => {
+                    if let Some(target_arch) = target_arch {
+                        let llvm_component = arch_to_llvm_component(target_arch);
+                        if !llvm_components.contains(&llvm_component.as_str()) {
+                            eprintln!(
+                                "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
+                            );
+                            *bad = true;
+                        }
+                    }
                 }
             }
         }
     });
 }
+
+fn arch_to_llvm_component(arch: &str) -> String {
+    // NOTE: This is an *approximate* mapping of Rust's `--target` architecture to LLVM component
+    // names. It is not intended to be an authoritative source, but rather a best-effort that's good
+    // enough for the purpose of this tidy check.
+    match arch {
+        "amdgcn" => "amdgpu".into(),
+        "aarch64_be" | "arm64_32" | "arm64e" | "arm64ec" => "aarch64".into(),
+        "i386" | "i586" | "i686" | "x86" | "x86_64" | "x86_64h" => "x86".into(),
+        "loongarch32" | "loongarch64" => "loongarch".into(),
+        "nvptx64" => "nvptx".into(),
+        "s390x" => "systemz".into(),
+        "sparc64" | "sparcv9" => "sparc".into(),
+        "wasm32" | "wasm32v1" | "wasm64" => "webassembly".into(),
+        _ if arch.starts_with("armeb")
+            || arch.starts_with("armv")
+            || arch.starts_with("thumbv") =>
+        {
+            "arm".into()
+        }
+        _ if arch.starts_with("bpfe") => "bpf".into(),
+        _ if arch.starts_with("mips") => "mips".into(),
+        _ if arch.starts_with("powerpc") => "powerpc".into(),
+        _ if arch.starts_with("riscv") => "riscv".into(),
+        _ => arch.to_ascii_lowercase(),
+    }
+}
diff --git a/tests/assembly-llvm/nvptx-safe-naming.rs b/tests/assembly-llvm/nvptx-safe-naming.rs
index d7b46aadd9c..6a6659a4e30 100644
--- a/tests/assembly-llvm/nvptx-safe-naming.rs
+++ b/tests/assembly-llvm/nvptx-safe-naming.rs
@@ -1,6 +1,9 @@
 //@ assembly-output: ptx-linker
 //@ compile-flags: --crate-type cdylib -Z unstable-options -Clinker-flavor=llbc
 //@ only-nvptx64
+//@ revisions: LLVM20 LLVM21
+//@ [LLVM21] min-llvm-version: 21
+//@ [LLVM20] max-llvm-major-version: 20
 
 #![feature(abi_ptx)]
 #![no_std]
@@ -15,7 +18,8 @@ extern crate breakpoint_panic_handler;
 #[no_mangle]
 pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) {
     // CHECK:      call.uni (retval0),
-    // CHECK-NEXT: [[IMPL_FN]]
+    // LLVM20-NEXT: [[IMPL_FN]]
+    // LLVM21-SAME: [[IMPL_FN]]
     *b = deep::private::MyStruct::new(*a).square();
 }
 
diff --git a/tests/assembly-llvm/x86-return-float.rs b/tests/assembly-llvm/x86-return-float.rs
index 165c11d2280..4db93f68485 100644
--- a/tests/assembly-llvm/x86-return-float.rs
+++ b/tests/assembly-llvm/x86-return-float.rs
@@ -334,9 +334,9 @@ pub fn return_f128(x: f128) -> f128 {
     // linux-NEXT: .cfi_offset
     // CHECK-NEXT: movl %esp, %ebp
     // linux-NEXT: .cfi_def_cfa_register
-    // linux-NEXT: movaps 8(%ebp), %xmm0
-    // win-NEXT: movups 8(%ebp), %xmm0
-    // CHECK-NEXT: popl %ebp
+    // linux: movaps 8(%ebp), %xmm0
+    // win: movups 8(%ebp), %xmm0
+    // CHECK: popl %ebp
     // linux-NEXT: .cfi_def_cfa
     // CHECK-NEXT: retl
     x
diff --git a/tests/codegen-llvm/abi-efiapi.rs b/tests/codegen-llvm/abi-efiapi.rs
index 1736f0daf0f..4cd645101a8 100644
--- a/tests/codegen-llvm/abi-efiapi.rs
+++ b/tests/codegen-llvm/abi-efiapi.rs
@@ -3,15 +3,15 @@
 //@ add-core-stubs
 //@ revisions:x86_64 i686 aarch64 arm riscv
 //@[x86_64] compile-flags: --target x86_64-unknown-uefi
-//@[x86_64] needs-llvm-components: aarch64 arm riscv
+//@[x86_64] needs-llvm-components: x86
 //@[i686] compile-flags: --target i686-unknown-linux-musl
-//@[i686] needs-llvm-components: aarch64 arm riscv
+//@[i686] needs-llvm-components: x86
 //@[aarch64] compile-flags: --target aarch64-unknown-none
-//@[aarch64] needs-llvm-components: aarch64 arm riscv
+//@[aarch64] needs-llvm-components: aarch64
 //@[arm] compile-flags: --target armv7r-none-eabi
-//@[arm] needs-llvm-components: aarch64 arm riscv
+//@[arm] needs-llvm-components: arm
 //@[riscv] compile-flags: --target riscv64gc-unknown-none-elf
-//@[riscv] needs-llvm-components: aarch64 arm riscv
+//@[riscv] needs-llvm-components: riscv
 //@ compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/cast-target-abi.rs b/tests/codegen-llvm/cast-target-abi.rs
index cbd49e2f022..28d3ad5f61c 100644
--- a/tests/codegen-llvm/cast-target-abi.rs
+++ b/tests/codegen-llvm/cast-target-abi.rs
@@ -4,7 +4,7 @@
 //@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir
 
 //@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
-//@[aarch64] needs-llvm-components: arm
+//@[aarch64] needs-llvm-components: aarch64
 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
 //@[loongarch64] needs-llvm-components: loongarch
 //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
diff --git a/tests/codegen-llvm/cf-protection.rs b/tests/codegen-llvm/cf-protection.rs
index f1349a5dcb9..9efadb59932 100644
--- a/tests/codegen-llvm/cf-protection.rs
+++ b/tests/codegen-llvm/cf-protection.rs
@@ -3,7 +3,7 @@
 //@ add-core-stubs
 //@ revisions: undefined none branch return full
 //@ needs-llvm-components: x86
-//@ [undefined] compile-flags:
+// [undefined] no extra compile-flags
 //@ [none] compile-flags: -Z cf-protection=none
 //@ [branch] compile-flags: -Z cf-protection=branch
 //@ [return] compile-flags: -Z cf-protection=return
diff --git a/tests/codegen-llvm/codemodels.rs b/tests/codegen-llvm/codemodels.rs
index 06d2eade78a..e82e094aab8 100644
--- a/tests/codegen-llvm/codemodels.rs
+++ b/tests/codegen-llvm/codemodels.rs
@@ -1,7 +1,7 @@
 //@ only-x86_64
 
 //@ revisions: NOMODEL MODEL-SMALL MODEL-KERNEL MODEL-MEDIUM MODEL-LARGE
-//@[NOMODEL] compile-flags:
+// [NOMODEL] no compile-flags
 //@[MODEL-SMALL] compile-flags: -C code-model=small
 //@[MODEL-KERNEL] compile-flags: -C code-model=kernel
 //@[MODEL-MEDIUM] compile-flags: -C code-model=medium
diff --git a/tests/codegen-llvm/diverging-function-call-debuginfo.rs b/tests/codegen-llvm/diverging-function-call-debuginfo.rs
new file mode 100644
index 00000000000..1a80fe1643d
--- /dev/null
+++ b/tests/codegen-llvm/diverging-function-call-debuginfo.rs
@@ -0,0 +1,38 @@
+/// Make sure that line debuginfo is correct for diverging calls under certain
+/// conditions. In particular we want to ensure that the line number is never
+/// 0, but we check the absence of 0 by looking for the expected exact line
+/// numbers. Regression test for <https://github.com/rust-lang/rust/issues/59558>.
+
+//@ compile-flags: -g -Clto -Copt-level=0
+//@ no-prefer-dynamic
+
+// First find the scope of both diverge() calls, namely this main() function.
+// CHECK-DAG: [[MAIN_SCOPE:![0-9]+]] = distinct !DISubprogram(name: "main", linkageName: {{.*}}diverging_function_call_debuginfo{{.*}}main{{.*}}
+fn main() {
+    if True == False {
+        // unreachable
+        // Then find the DILocation with the correct line number for this call ...
+        // CHECK-DAG: [[UNREACHABLE_CALL_DBG:![0-9]+]] = !DILocation(line: [[@LINE+1]], {{.*}}scope: [[MAIN_SCOPE]]
+        diverge();
+    }
+
+    // ... and this call.
+    // CHECK-DAG: [[LAST_CALL_DBG:![0-9]+]] = !DILocation(line: [[@LINE+1]], {{.*}}scope: [[MAIN_SCOPE]]
+    diverge();
+}
+
+#[derive(PartialEq)]
+pub enum MyBool {
+    True,
+    False,
+}
+
+use MyBool::*;
+
+fn diverge() -> ! {
+    panic!();
+}
+
+// Finally make sure both DILocations belong to each the respective diverge() call.
+// CHECK-DAG: call void {{.*}}diverging_function_call_debuginfo{{.*}}diverge{{.*}} !dbg [[LAST_CALL_DBG]]
+// CHECK-DAG: call void {{.*}}diverging_function_call_debuginfo{{.*}}diverge{{.*}} !dbg [[UNREACHABLE_CALL_DBG]]
diff --git a/tests/codegen-llvm/ehcontguard_disabled.rs b/tests/codegen-llvm/ehcontguard_disabled.rs
index 9efb2721b3e..962d14e7eb9 100644
--- a/tests/codegen-llvm/ehcontguard_disabled.rs
+++ b/tests/codegen-llvm/ehcontguard_disabled.rs
@@ -1,5 +1,3 @@
-//@ compile-flags:
-
 #![crate_type = "lib"]
 
 // A basic test function.
diff --git a/tests/codegen-llvm/enum/enum-discriminant-eq.rs b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
index 0494c5f551b..d599685c2e5 100644
--- a/tests/codegen-llvm/enum/enum-discriminant-eq.rs
+++ b/tests/codegen-llvm/enum/enum-discriminant-eq.rs
@@ -1,6 +1,9 @@
 //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
 //@ min-llvm-version: 20
 //@ only-64bit
+//@ revisions: LLVM20 LLVM21
+//@ [LLVM21] min-llvm-version: 21
+//@ [LLVM20] max-llvm-major-version: 20
 
 // The `derive(PartialEq)` on enums with field-less variants compares discriminants,
 // so make sure we emit that in some reasonable way.
@@ -137,17 +140,20 @@ pub fn mid_nz32_eq_discr(a: Mid<NonZero<u32>>, b: Mid<NonZero<u32>>) -> bool {
 pub fn mid_ac_eq_discr(a: Mid<AC>, b: Mid<AC>) -> bool {
     // CHECK-LABEL: @mid_ac_eq_discr(
 
-    // CHECK: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
+    // LLVM20: %[[A_REL_DISCR:.+]] = xor i8 %a, -128
     // CHECK: %[[A_IS_NICHE:.+]] = icmp slt i8 %a, 0
     // CHECK: %[[A_NOT_HOLE:.+]] = icmp ne i8 %a, -127
     // CHECK: tail call void @llvm.assume(i1 %[[A_NOT_HOLE]])
-    // CHECK: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
+    // LLVM20: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %[[A_REL_DISCR]], i8 1
 
-    // CHECK: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
+    // LLVM20: %[[B_REL_DISCR:.+]] = xor i8 %b, -128
     // CHECK: %[[B_IS_NICHE:.+]] = icmp slt i8 %b, 0
     // CHECK: %[[B_NOT_HOLE:.+]] = icmp ne i8 %b, -127
     // CHECK: tail call void @llvm.assume(i1 %[[B_NOT_HOLE]])
-    // CHECK: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+    // LLVM20: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %[[B_REL_DISCR]], i8 1
+
+    // LLVM21: %[[A_DISCR:.+]] = select i1 %[[A_IS_NICHE]], i8 %a, i8 -127
+    // LLVM21: %[[B_DISCR:.+]] = select i1 %[[B_IS_NICHE]], i8 %b, i8 -127
 
     // CHECK: %[[R:.+]] = icmp eq i8 %[[A_DISCR]], %[[B_DISCR]]
     // CHECK: ret i1 %[[R]]
diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs
index 344af6eb42f..8a7ee4b4de5 100644
--- a/tests/codegen-llvm/naked-fn/naked-functions.rs
+++ b/tests/codegen-llvm/naked-fn/naked-functions.rs
@@ -8,7 +8,7 @@
 //@[win_i686] compile-flags: --target i686-pc-windows-gnu
 //@[win_i686] needs-llvm-components: x86
 //@[macos] compile-flags: --target aarch64-apple-darwin
-//@[macos] needs-llvm-components: arm
+//@[macos] needs-llvm-components: aarch64
 //@[thumb] compile-flags: --target thumbv7em-none-eabi
 //@[thumb] needs-llvm-components: arm
 
diff --git a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
index f319306f93f..642bf5e7576 100644
--- a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
+++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs
@@ -19,9 +19,9 @@
 //@ only-linux
 //
 //@ revisions:ASAN ASAN-FAT-LTO
-//@                compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
-//@[ASAN]          compile-flags:
-//@[ASAN-FAT-LTO]  compile-flags: -Cprefer-dynamic=false -Clto=fat
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
+// [ASAN] no extra compile-flags
+//@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat
 
 #![crate_type = "staticlib"]
 
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
index 6b40918dd3a..02c31fb8e9b 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
index 942b50deb02..9a60d51713f 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-generalize-pointers
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
index c89d9bdd121..134f4ff4bfd 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
index 220cae1a4fa..4328b7fa07d 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
index bb9a0005903..81a9db1b97a 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-itanium-cxx-abi.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
index 8b844b99142..61056c2a54e 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
index 15c107bea15..182af162d78 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -5,7 +5,7 @@
 //@ [aarch64] compile-flags: --target aarch64-unknown-none
 //@ [aarch64] needs-llvm-components: aarch64
 //@ [x86_64] compile-flags: --target x86_64-unknown-none
-//@ [x86_64] needs-llvm-components:
+//@ [x86_64] needs-llvm-components: x86
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
index 318c277e10c..5eb5b356b05 100644
--- a/tests/codegen-llvm/sanitizer/memory-track-origins.rs
+++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs
@@ -5,7 +5,7 @@
 //@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
 //
 //@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static
-//@[MSAN-0] compile-flags:
+// [MSAN-0] no extra compile-flags
 //@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1
 //@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins
 //@[MSAN-1-LTO] compile-flags: -Zsanitizer-memory-track-origins=1 -C lto=fat
diff --git a/tests/codegen-llvm/ub-checks.rs b/tests/codegen-llvm/ub-checks.rs
index 67f5bff08d5..c40bc9acc52 100644
--- a/tests/codegen-llvm/ub-checks.rs
+++ b/tests/codegen-llvm/ub-checks.rs
@@ -6,7 +6,7 @@
 // but ub-checks are explicitly disabled.
 
 //@ revisions: DEBUG NOCHECKS
-//@ [DEBUG] compile-flags:
+// [DEBUG] no extra compile-flags
 //@ [NOCHECKS] compile-flags: -Zub-checks=no
 //@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes
 
diff --git a/tests/debuginfo/unsized.rs b/tests/debuginfo/unsized.rs
index 17c5e463fba..edd9f5af557 100644
--- a/tests/debuginfo/unsized.rs
+++ b/tests/debuginfo/unsized.rs
@@ -37,7 +37,6 @@
 // cdb-check:    [...] vtable           : 0x[...] [Type: unsigned [...]int[...] (*)[4]]
 
 // cdb-command:dx _box
-// cdb-check:
 // cdb-check:_box             [Type: alloc::boxed::Box<unsized::Foo<dyn$<core::fmt::Debug> >,alloc::alloc::Global>]
 // cdb-check:[+0x000] pointer          : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *]
 // cdb-check:[...] vtable           : 0x[...] [Type: unsigned [...]int[...] (*)[4]]
diff --git a/tests/run-make/link-cfg/rmake.rs b/tests/run-make/link-cfg/rmake.rs
index 732de5dbd0b..18577fb836d 100644
--- a/tests/run-make/link-cfg/rmake.rs
+++ b/tests/run-make/link-cfg/rmake.rs
@@ -12,6 +12,7 @@
 
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
+//@ needs-llvm-components: x86
 
 use run_make_support::{bare_rustc, build_native_dynamic_lib, build_native_static_lib, run, rustc};
 
diff --git a/tests/run-make/mismatching-target-triples/rmake.rs b/tests/run-make/mismatching-target-triples/rmake.rs
index 6f41eac8cda..1bbe945e0da 100644
--- a/tests/run-make/mismatching-target-triples/rmake.rs
+++ b/tests/run-make/mismatching-target-triples/rmake.rs
@@ -4,6 +4,7 @@
 // now replaced by a clearer normal error message. This test checks that this aforementioned
 // error message is used.
 // See https://github.com/rust-lang/rust/issues/10814
+//@ needs-llvm-components: x86
 
 use run_make_support::rustc;
 
diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs
index 017444cfcdd..7bb54e2739c 100644
--- a/tests/run-make/musl-default-linking/rmake.rs
+++ b/tests/run-make/musl-default-linking/rmake.rs
@@ -4,6 +4,7 @@ use run_make_support::{rustc, serde_json};
 // Per https://github.com/rust-lang/compiler-team/issues/422,
 // we should be trying to move these targets to dynamically link
 // musl libc by default.
+//@ needs-llvm-components: aarch64 arm mips powerpc riscv systemz x86
 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-musleabi",
diff --git a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
index fe9587f5022..d43aa9b90ac 100644
--- a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
+++ b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
@@ -1,4 +1,5 @@
 // Test that rustdoc will properly canonicalize the target spec json path just like rustc.
+//@ needs-llvm-components: x86
 
 use run_make_support::{cwd, rustc, rustdoc};
 
diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs
index 7e565588ed6..7c30a5b21b3 100644
--- a/tests/run-make/target-specs/rmake.rs
+++ b/tests/run-make/target-specs/rmake.rs
@@ -4,6 +4,7 @@
 // with the target flag's bundle of new features to check that compilation either succeeds while
 // using them correctly, or fails with the right error message when using them improperly.
 // See https://github.com/rust-lang/rust/pull/16156
+//@ needs-llvm-components: x86
 
 use run_make_support::{diff, rfs, rustc};
 
diff --git a/tests/rustdoc-ui/2024-doctests-checks.rs b/tests/rustdoc-ui/2024-doctests-checks.rs
index 0c3a11771f3..61f90fe6231 100644
--- a/tests/rustdoc-ui/2024-doctests-checks.rs
+++ b/tests/rustdoc-ui/2024-doctests-checks.rs
@@ -3,6 +3,8 @@
 //@ compile-flags: --test --test-args=--test-threads=1
 //@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
 
 /// ```
diff --git a/tests/rustdoc-ui/2024-doctests-checks.stdout b/tests/rustdoc-ui/2024-doctests-checks.stdout
index 534fe466fe7..c86eafd61b9 100644
--- a/tests/rustdoc-ui/2024-doctests-checks.stdout
+++ b/tests/rustdoc-ui/2024-doctests-checks.stdout
@@ -1,12 +1,13 @@
 
 running 1 test
-test $DIR/2024-doctests-checks.rs - Foo (line 8) ... ok
+test $DIR/2024-doctests-checks.rs - Foo (line 10) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 1 test
-test $DIR/2024-doctests-checks.rs - Foo (line 15) ... ok
+test $DIR/2024-doctests-checks.rs - Foo (line 17) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/2024-doctests-crate-attribute.rs b/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
index c9887cbc63b..416d50cb070 100644
--- a/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
+++ b/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
@@ -4,6 +4,8 @@
 //@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 
 /// This doctest is used to ensure that if a crate attribute is present,
 /// it will not be part of the merged doctests.
diff --git a/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout b/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
index c084ac4522e..20618426312 100644
--- a/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
+++ b/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
@@ -1,12 +1,13 @@
 
 running 1 test
-test $DIR/2024-doctests-crate-attribute.rs - Foo (line 20) ... ok
+test $DIR/2024-doctests-crate-attribute.rs - Foo (line 22) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 1 test
-test $DIR/2024-doctests-crate-attribute.rs - Foo (line 11) ... ok
+test $DIR/2024-doctests-crate-attribute.rs - Foo (line 13) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs
index 079d44570bb..e02d2601c58 100644
--- a/tests/rustdoc-ui/doctest/dead-code-2024.rs
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs
@@ -4,6 +4,8 @@
 //@ compile-flags:--test
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 #![doc(test(attr(allow(unused_variables), deny(warnings))))]
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
index a943a177e10..bf9cd65200b 100644
--- a/tests/rustdoc-ui/doctest/dead-code-2024.stdout
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
@@ -1,18 +1,18 @@
 
 running 1 test
-test $DIR/dead-code-2024.rs - f (line 13) - compile ... FAILED
+test $DIR/dead-code-2024.rs - f (line 15) - compile ... FAILED
 
 failures:
 
----- $DIR/dead-code-2024.rs - f (line 13) stdout ----
+---- $DIR/dead-code-2024.rs - f (line 15) stdout ----
 error: trait `T` is never used
-  --> $DIR/dead-code-2024.rs:14:7
+  --> $DIR/dead-code-2024.rs:16:7
    |
 LL | trait T { fn f(); }
    |       ^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-2024.rs:12:9
+  --> $DIR/dead-code-2024.rs:14:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -23,7 +23,8 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/dead-code-2024.rs - f (line 13)
+    $DIR/dead-code-2024.rs - f (line 15)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/dead-code-items.rs b/tests/rustdoc-ui/doctest/dead-code-items.rs
index 015504cbced..ff59bfaabc4 100644
--- a/tests/rustdoc-ui/doctest/dead-code-items.rs
+++ b/tests/rustdoc-ui/doctest/dead-code-items.rs
@@ -4,6 +4,8 @@
 //@ compile-flags:--test --test-args=--test-threads=1
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 #![doc(test(attr(deny(warnings))))]
diff --git a/tests/rustdoc-ui/doctest/dead-code-items.stdout b/tests/rustdoc-ui/doctest/dead-code-items.stdout
index 4b9d8be94dd..ecfe09f09ce 100644
--- a/tests/rustdoc-ui/doctest/dead-code-items.stdout
+++ b/tests/rustdoc-ui/doctest/dead-code-items.stdout
@@ -1,30 +1,30 @@
 
 running 13 tests
-test $DIR/dead-code-items.rs - A (line 32) - compile ... ok
-test $DIR/dead-code-items.rs - A (line 88) - compile ... ok
-test $DIR/dead-code-items.rs - A::field (line 39) - compile ... FAILED
-test $DIR/dead-code-items.rs - A::method (line 94) - compile ... ok
-test $DIR/dead-code-items.rs - C (line 22) - compile ... FAILED
-test $DIR/dead-code-items.rs - Enum (line 70) - compile ... FAILED
-test $DIR/dead-code-items.rs - Enum::Variant1 (line 77) - compile ... FAILED
-test $DIR/dead-code-items.rs - MyTrait (line 103) - compile ... FAILED
-test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) - compile ... FAILED
-test $DIR/dead-code-items.rs - S (line 14) - compile ... ok
-test $DIR/dead-code-items.rs - U (line 48) - compile ... ok
-test $DIR/dead-code-items.rs - U::field (line 55) - compile ... FAILED
-test $DIR/dead-code-items.rs - U::field2 (line 61) - compile ... ok
+test $DIR/dead-code-items.rs - A (line 34) - compile ... ok
+test $DIR/dead-code-items.rs - A (line 90) - compile ... ok
+test $DIR/dead-code-items.rs - A::field (line 41) - compile ... FAILED
+test $DIR/dead-code-items.rs - A::method (line 96) - compile ... ok
+test $DIR/dead-code-items.rs - C (line 24) - compile ... FAILED
+test $DIR/dead-code-items.rs - Enum (line 72) - compile ... FAILED
+test $DIR/dead-code-items.rs - Enum::Variant1 (line 79) - compile ... FAILED
+test $DIR/dead-code-items.rs - MyTrait (line 105) - compile ... FAILED
+test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112) - compile ... FAILED
+test $DIR/dead-code-items.rs - S (line 16) - compile ... ok
+test $DIR/dead-code-items.rs - U (line 50) - compile ... ok
+test $DIR/dead-code-items.rs - U::field (line 57) - compile ... FAILED
+test $DIR/dead-code-items.rs - U::field2 (line 63) - compile ... ok
 
 failures:
 
----- $DIR/dead-code-items.rs - A::field (line 39) stdout ----
+---- $DIR/dead-code-items.rs - A::field (line 41) stdout ----
 error: trait `DeadCodeInField` is never used
-  --> $DIR/dead-code-items.rs:40:7
+  --> $DIR/dead-code-items.rs:42:7
    |
 LL | trait DeadCodeInField {}
    |       ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:38:9
+  --> $DIR/dead-code-items.rs:40:9
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
@@ -32,15 +32,15 @@ LL | #![deny(dead_code)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - C (line 22) stdout ----
+---- $DIR/dead-code-items.rs - C (line 24) stdout ----
 error: unused variable: `unused_error`
-  --> $DIR/dead-code-items.rs:23:5
+  --> $DIR/dead-code-items.rs:25:5
    |
 LL | let unused_error = 5;
    |     ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_error`
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:20:9
+  --> $DIR/dead-code-items.rs:22:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -49,15 +49,15 @@ LL | #![deny(warnings)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - Enum (line 70) stdout ----
+---- $DIR/dead-code-items.rs - Enum (line 72) stdout ----
 error: unused variable: `not_dead_code_but_unused`
-  --> $DIR/dead-code-items.rs:71:5
+  --> $DIR/dead-code-items.rs:73:5
    |
 LL | let not_dead_code_but_unused = 5;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_not_dead_code_but_unused`
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:68:9
+  --> $DIR/dead-code-items.rs:70:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -66,15 +66,15 @@ LL | #![deny(warnings)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - Enum::Variant1 (line 77) stdout ----
+---- $DIR/dead-code-items.rs - Enum::Variant1 (line 79) stdout ----
 error: unused variable: `unused_in_variant`
-  --> $DIR/dead-code-items.rs:80:17
+  --> $DIR/dead-code-items.rs:82:17
    |
 LL | fn main() { let unused_in_variant = 5; }
    |                 ^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_variant`
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:75:9
+  --> $DIR/dead-code-items.rs:77:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -83,15 +83,15 @@ LL | #![deny(warnings)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - MyTrait (line 103) stdout ----
+---- $DIR/dead-code-items.rs - MyTrait (line 105) stdout ----
 error: trait `StillDeadCodeAtMyTrait` is never used
-  --> $DIR/dead-code-items.rs:104:7
+  --> $DIR/dead-code-items.rs:106:7
    |
 LL | trait StillDeadCodeAtMyTrait { }
    |       ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:102:9
+  --> $DIR/dead-code-items.rs:104:9
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
@@ -99,15 +99,15 @@ LL | #![deny(dead_code)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) stdout ----
+---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112) stdout ----
 error: unused variable: `unused_in_impl`
-  --> $DIR/dead-code-items.rs:113:17
+  --> $DIR/dead-code-items.rs:115:17
    |
 LL | fn main() { let unused_in_impl = 5; }
    |                 ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_impl`
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:108:9
+  --> $DIR/dead-code-items.rs:110:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -116,15 +116,15 @@ LL | #![deny(warnings)]
 error: aborting due to 1 previous error
 
 Couldn't compile the test.
----- $DIR/dead-code-items.rs - U::field (line 55) stdout ----
+---- $DIR/dead-code-items.rs - U::field (line 57) stdout ----
 error: trait `DeadCodeInUnionField` is never used
-  --> $DIR/dead-code-items.rs:56:7
+  --> $DIR/dead-code-items.rs:58:7
    |
 LL | trait DeadCodeInUnionField {}
    |       ^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-items.rs:54:9
+  --> $DIR/dead-code-items.rs:56:9
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
@@ -134,13 +134,14 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/dead-code-items.rs - A::field (line 39)
-    $DIR/dead-code-items.rs - C (line 22)
-    $DIR/dead-code-items.rs - Enum (line 70)
-    $DIR/dead-code-items.rs - Enum::Variant1 (line 77)
-    $DIR/dead-code-items.rs - MyTrait (line 103)
-    $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110)
-    $DIR/dead-code-items.rs - U::field (line 55)
+    $DIR/dead-code-items.rs - A::field (line 41)
+    $DIR/dead-code-items.rs - C (line 24)
+    $DIR/dead-code-items.rs - Enum (line 72)
+    $DIR/dead-code-items.rs - Enum::Variant1 (line 79)
+    $DIR/dead-code-items.rs - MyTrait (line 105)
+    $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112)
+    $DIR/dead-code-items.rs - U::field (line 57)
 
 test result: FAILED. 6 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.rs b/tests/rustdoc-ui/doctest/dead-code-module-2.rs
index de7b11b91ec..fd9c313ec9a 100644
--- a/tests/rustdoc-ui/doctest/dead-code-module-2.rs
+++ b/tests/rustdoc-ui/doctest/dead-code-module-2.rs
@@ -4,6 +4,8 @@
 //@ compile-flags:--test
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 #![doc(test(attr(allow(unused_variables))))]
diff --git a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout
index d44068dcbf5..cf737996d5c 100644
--- a/tests/rustdoc-ui/doctest/dead-code-module-2.stdout
+++ b/tests/rustdoc-ui/doctest/dead-code-module-2.stdout
@@ -1,24 +1,24 @@
 
 running 1 test
-test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok
+test $DIR/dead-code-module-2.rs - g (line 26) - compile ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 1 test
-test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED
+test $DIR/dead-code-module-2.rs - my_mod::f (line 18) - compile ... FAILED
 
 failures:
 
----- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ----
+---- $DIR/dead-code-module-2.rs - my_mod::f (line 18) stdout ----
 error: trait `T` is never used
-  --> $DIR/dead-code-module-2.rs:17:7
+  --> $DIR/dead-code-module-2.rs:19:7
    |
 LL | trait T { fn f(); }
    |       ^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-module-2.rs:15:9
+  --> $DIR/dead-code-module-2.rs:17:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -29,7 +29,8 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/dead-code-module-2.rs - my_mod::f (line 16)
+    $DIR/dead-code-module-2.rs - my_mod::f (line 18)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/dead-code-module.rs b/tests/rustdoc-ui/doctest/dead-code-module.rs
index f825749a6a2..d3103ad28e9 100644
--- a/tests/rustdoc-ui/doctest/dead-code-module.rs
+++ b/tests/rustdoc-ui/doctest/dead-code-module.rs
@@ -4,6 +4,8 @@
 //@ compile-flags:--test
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 mod my_mod {
diff --git a/tests/rustdoc-ui/doctest/dead-code-module.stdout b/tests/rustdoc-ui/doctest/dead-code-module.stdout
index b5ccf225d25..83c6af3775e 100644
--- a/tests/rustdoc-ui/doctest/dead-code-module.stdout
+++ b/tests/rustdoc-ui/doctest/dead-code-module.stdout
@@ -1,18 +1,18 @@
 
 running 1 test
-test $DIR/dead-code-module.rs - my_mod::f (line 14) - compile ... FAILED
+test $DIR/dead-code-module.rs - my_mod::f (line 16) - compile ... FAILED
 
 failures:
 
----- $DIR/dead-code-module.rs - my_mod::f (line 14) stdout ----
+---- $DIR/dead-code-module.rs - my_mod::f (line 16) stdout ----
 error: trait `T` is never used
-  --> $DIR/dead-code-module.rs:15:7
+  --> $DIR/dead-code-module.rs:17:7
    |
 LL | trait T { fn f(); }
    |       ^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-module.rs:13:9
+  --> $DIR/dead-code-module.rs:15:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -23,7 +23,8 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/dead-code-module.rs - my_mod::f (line 14)
+    $DIR/dead-code-module.rs - my_mod::f (line 16)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs
index a47bac3daef..2f0d6756b27 100644
--- a/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs
+++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs
@@ -2,6 +2,8 @@
 //@ compile-flags:--test --test-args=--test-threads=1
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 // https://github.com/rust-lang/rust/issues/130470
diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout b/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout
index 22d15f8743c..ceaf60b1201 100644
--- a/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout
+++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.stdout
@@ -22,3 +22,4 @@ failures:
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/edition-2024-error-output.rs b/tests/rustdoc-ui/doctest/edition-2024-error-output.rs
index 82a85debcd1..e1e57ad01cd 100644
--- a/tests/rustdoc-ui/doctest/edition-2024-error-output.rs
+++ b/tests/rustdoc-ui/doctest/edition-2024-error-output.rs
@@ -6,6 +6,8 @@
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ rustc-env:RUST_BACKTRACE=0
 //@ failure-status: 101
 
diff --git a/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout b/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
index 273d7071237..ab6aca239af 100644
--- a/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
+++ b/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
@@ -1,10 +1,10 @@
 
 running 1 test
-test $DIR/edition-2024-error-output.rs - (line 12) ... FAILED
+test $DIR/edition-2024-error-output.rs - (line 14) ... FAILED
 
 failures:
 
----- $DIR/edition-2024-error-output.rs - (line 12) stdout ----
+---- $DIR/edition-2024-error-output.rs - (line 14) stdout ----
 Test executable failed (exit status: 101).
 
 stderr:
@@ -18,7 +18,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
 failures:
-    $DIR/edition-2024-error-output.rs - (line 12)
+    $DIR/edition-2024-error-output.rs - (line 14)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
index 793f8654661..0504c3dc730 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
@@ -5,6 +5,8 @@
 //@ compile-flags:--test
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 /// ```should_panic
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
index 2b04b77c9dc..9047fe0dcdd 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
@@ -1,14 +1,15 @@
 
 running 1 test
-test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAILED
+test $DIR/failed-doctest-should-panic.rs - Foo (line 12) - should panic ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ----
-note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0
+---- $DIR/failed-doctest-should-panic.rs - Foo (line 12) stdout ----
+note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:12:0
 
 failures:
-    $DIR/failed-doctest-should-panic.rs - Foo (line 10)
+    $DIR/failed-doctest-should-panic.rs - Foo (line 12)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout
index ce767fb8443..d80c0da323d 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2015.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
+test $DIR/failed-doctest-test-crate.rs - m (line 16) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
+---- $DIR/failed-doctest-test-crate.rs - m (line 16) stdout ----
 error[E0432]: unresolved import `test`
-  --> $DIR/failed-doctest-test-crate.rs:15:5
+  --> $DIR/failed-doctest-test-crate.rs:17:5
    |
 LL | use test::*;
    |     ^^^^ use of unresolved module or unlinked crate `test`
@@ -22,7 +22,7 @@ For more information about this error, try `rustc --explain E0432`.
 Couldn't compile the test.
 
 failures:
-    $DIR/failed-doctest-test-crate.rs - m (line 14)
+    $DIR/failed-doctest-test-crate.rs - m (line 16)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout
index 80642e93bbd..724bb9bee62 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.edition2024.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
+test $DIR/failed-doctest-test-crate.rs - m (line 16) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
+---- $DIR/failed-doctest-test-crate.rs - m (line 16) stdout ----
 error[E0432]: unresolved import `test`
-  --> $DIR/failed-doctest-test-crate.rs:15:5
+  --> $DIR/failed-doctest-test-crate.rs:17:5
    |
 LL | use test::*;
    |     ^^^^ use of unresolved module or unlinked crate `test`
@@ -19,7 +19,8 @@ For more information about this error, try `rustc --explain E0432`.
 Couldn't compile the test.
 
 failures:
-    $DIR/failed-doctest-test-crate.rs - m (line 14)
+    $DIR/failed-doctest-test-crate.rs - m (line 16)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs
index 6966d3df11c..75f7ac396f5 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs
+++ b/tests/rustdoc-ui/doctest/failed-doctest-test-crate.rs
@@ -7,6 +7,8 @@
 //@ compile-flags:--test
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 /// <https://github.com/rust-lang/rust/pull/137899#discussion_r1976743383>
diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
index ff26e7e3231..0d00a9fc9c4 100644
--- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
+++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/relative-path-include-bytes-132203.rs - (line 18) ... FAILED
+test $DIR/relative-path-include-bytes-132203.rs - (line 20) ... FAILED
 
 failures:
 
----- $DIR/relative-path-include-bytes-132203.rs - (line 18) stdout ----
+---- $DIR/relative-path-include-bytes-132203.rs - (line 20) stdout ----
 error: couldn't read `$DIR/relative-dir-empty-file`: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/relative-path-include-bytes-132203.rs:19:9
+  --> $DIR/relative-path-include-bytes-132203.rs:21:9
    |
 LL | let x = include_bytes!("relative-dir-empty-file");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/relative-path-include-bytes-132203.rs - (line 18)
+    $DIR/relative-path-include-bytes-132203.rs - (line 20)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout
index e4c65703081..fa5bd7c93fa 100644
--- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout
+++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout
@@ -4,3 +4,4 @@ test $DIR/auxiliary/relative-dir.md - (line 1) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
index ceacd69a5fd..321edc3ee84 100644
--- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
+++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs
@@ -9,6 +9,8 @@
 //@ normalize-stdout: "tests.rustdoc-ui.doctest." -> "$$DIR/"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout: "`: .* \(os error 2\)" -> "`: $$FILE_NOT_FOUND_MSG (os error 2)"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 
 // https://github.com/rust-lang/rust/issues/132203
 // This version, because it's edition2024, passes thanks to the new
diff --git a/tests/rustdoc-ui/doctest/stdout-and-stderr.rs b/tests/rustdoc-ui/doctest/stdout-and-stderr.rs
index 9b0c69d8839..a4eda8c7f83 100644
--- a/tests/rustdoc-ui/doctest/stdout-and-stderr.rs
+++ b/tests/rustdoc-ui/doctest/stdout-and-stderr.rs
@@ -9,6 +9,8 @@
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 //@ rustc-env:RUST_BACKTRACE=0
 
diff --git a/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout b/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout
index b2febe1344f..a35a4d7c3cb 100644
--- a/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout
+++ b/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout
@@ -1,12 +1,12 @@
 
 running 3 tests
-test $DIR/stdout-and-stderr.rs - (line 15) ... FAILED
-test $DIR/stdout-and-stderr.rs - (line 20) ... FAILED
-test $DIR/stdout-and-stderr.rs - (line 24) ... FAILED
+test $DIR/stdout-and-stderr.rs - (line 17) ... FAILED
+test $DIR/stdout-and-stderr.rs - (line 22) ... FAILED
+test $DIR/stdout-and-stderr.rs - (line 26) ... FAILED
 
 failures:
 
----- $DIR/stdout-and-stderr.rs - (line 15) stdout ----
+---- $DIR/stdout-and-stderr.rs - (line 17) stdout ----
 Test executable failed (exit status: 101).
 
 stdout:
@@ -21,7 +21,7 @@ assertion `left == right` failed
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
----- $DIR/stdout-and-stderr.rs - (line 20) stdout ----
+---- $DIR/stdout-and-stderr.rs - (line 22) stdout ----
 Test executable failed (exit status: 101).
 
 stderr:
@@ -33,14 +33,15 @@ assertion `left == right` failed
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
----- $DIR/stdout-and-stderr.rs - (line 24) stdout ----
+---- $DIR/stdout-and-stderr.rs - (line 26) stdout ----
 Test executable failed (exit status: 1).
 
 
 failures:
-    $DIR/stdout-and-stderr.rs - (line 15)
-    $DIR/stdout-and-stderr.rs - (line 20)
-    $DIR/stdout-and-stderr.rs - (line 24)
+    $DIR/stdout-and-stderr.rs - (line 17)
+    $DIR/stdout-and-stderr.rs - (line 22)
+    $DIR/stdout-and-stderr.rs - (line 26)
 
 test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.rs b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
index 3b4fb3f3443..df30e01b25e 100644
--- a/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
@@ -3,6 +3,8 @@
 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
+//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
+//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
 //@ failure-status: 101
 
 /// ```
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
index 62e1fb10b9f..13567b41e51 100644
--- a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
@@ -1,17 +1,17 @@
 
 running 1 test
-test $DIR/wrong-ast-2024.rs - three (line 18) - should panic ... ok
+test $DIR/wrong-ast-2024.rs - three (line 20) - should panic ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 2 tests
-test $DIR/wrong-ast-2024.rs - one (line 8) ... FAILED
-test $DIR/wrong-ast-2024.rs - two (line 13) ... FAILED
+test $DIR/wrong-ast-2024.rs - one (line 10) ... FAILED
+test $DIR/wrong-ast-2024.rs - two (line 15) ... FAILED
 
 failures:
 
----- $DIR/wrong-ast-2024.rs - one (line 8) stdout ----
+---- $DIR/wrong-ast-2024.rs - one (line 10) stdout ----
 error[E0758]: unterminated block comment
   --> $DIR/wrong-ast-2024.rs:$LINE:$COL
    |
@@ -22,7 +22,7 @@ error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0758`.
 Couldn't compile the test.
----- $DIR/wrong-ast-2024.rs - two (line 13) stdout ----
+---- $DIR/wrong-ast-2024.rs - two (line 15) stdout ----
 error: unexpected closing delimiter: `}`
   --> $DIR/wrong-ast-2024.rs:$LINE:$COL
    |
@@ -34,8 +34,9 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/wrong-ast-2024.rs - one (line 8)
-    $DIR/wrong-ast-2024.rs - two (line 13)
+    $DIR/wrong-ast-2024.rs - one (line 10)
+    $DIR/wrong-ast-2024.rs - two (line 15)
 
 test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+all doctests ran in $TIME; merged doctests compilation took $TIME
diff --git a/tests/rustdoc/extern/extern-html-alias.rs b/tests/rustdoc/extern/extern-html-alias.rs
new file mode 100644
index 00000000000..3ff782d3963
--- /dev/null
+++ b/tests/rustdoc/extern/extern-html-alias.rs
@@ -0,0 +1,9 @@
+//@ compile-flags:-Z unstable-options --extern-html-root-url externs_name=https://renamed.example.com  --extern-html-root-url empty=https://bad.invalid
+//@ aux-crate:externs_name=empty.rs
+//@ edition: 2018
+
+extern crate externs_name as renamed;
+
+//@ has extern_html_alias/index.html
+//@ has - '//a/@href' 'https://renamed.example.com/empty/index.html'
+pub use renamed as yet_different_name;
diff --git a/tests/rustdoc/extern/extern-html-fallback.rs b/tests/rustdoc/extern/extern-html-fallback.rs
new file mode 100644
index 00000000000..ddac9bf713c
--- /dev/null
+++ b/tests/rustdoc/extern/extern-html-fallback.rs
@@ -0,0 +1,14 @@
+//@ compile-flags:-Z unstable-options --extern-html-root-url yet_another_name=https://bad.invalid --extern-html-root-url renamed_privately=https://bad.invalid --extern-html-root-url renamed_locally=https://bad.invalid --extern-html-root-url empty=https://localhost
+//@ aux-crate:externs_name=empty.rs
+//@ edition: 2018
+
+mod m {
+    pub extern crate externs_name as renamed_privately;
+}
+
+// renaming within the crate's source code is not supposed to affect CLI flags
+extern crate externs_name as renamed_locally;
+
+//@ has extern_html_fallback/index.html
+//@ has - '//a/@href' 'https://localhost/empty/index.html'
+pub use crate::renamed_locally as yet_another_name;
diff --git a/tests/ui/README.md b/tests/ui/README.md
index 86c9ad9c1ce..66c1bb905a7 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -654,10 +654,6 @@ Tests on range patterns where one of the bounds is not a direct value.
 
 Tests for the standard library collection [`std::collections::HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html).
 
-## `tests/ui/hello_world/`
-
-Tests that the basic hello-world program is not somehow broken.
-
 ## `tests/ui/higher-ranked/`
 
 Tests for higher-ranked trait bounds.
diff --git a/tests/ui/borrowck/liberated-region-from-outer-closure.rs b/tests/ui/borrowck/liberated-region-from-outer-closure.rs
new file mode 100644
index 00000000000..dcc6370b4a1
--- /dev/null
+++ b/tests/ui/borrowck/liberated-region-from-outer-closure.rs
@@ -0,0 +1,12 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/144608>.
+
+fn example<T: Copy>(x: T) -> impl FnMut(&mut ()) {
+    move |_: &mut ()| {
+        move || needs_static_lifetime(x);
+        //~^ ERROR the parameter type `T` may not live long enough
+    }
+}
+
+fn needs_static_lifetime<T: 'static>(obj: T) {}
+
+fn main() {}
diff --git a/tests/ui/borrowck/liberated-region-from-outer-closure.stderr b/tests/ui/borrowck/liberated-region-from-outer-closure.stderr
new file mode 100644
index 00000000000..98b45ac499d
--- /dev/null
+++ b/tests/ui/borrowck/liberated-region-from-outer-closure.stderr
@@ -0,0 +1,17 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/liberated-region-from-outer-closure.rs:5:17
+   |
+LL |         move || needs_static_lifetime(x);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 |
+   |                 the parameter type `T` must be valid for the static lifetime...
+   |                 ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | fn example<T: Copy + 'static>(x: T) -> impl FnMut(&mut ()) {
+   |                    +++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/enum-discriminant/wrapping_niche.rs b/tests/ui/enum-discriminant/wrapping_niche.rs
new file mode 100644
index 00000000000..8097414be68
--- /dev/null
+++ b/tests/ui/enum-discriminant/wrapping_niche.rs
@@ -0,0 +1,24 @@
+//! Test that we produce the same niche range no
+//! matter of signendess if the discriminants are the same.
+
+#![feature(rustc_attrs)]
+
+#[repr(u16)]
+#[rustc_layout(debug)]
+enum UnsignedAroundZero {
+    //~^ ERROR: layout_of
+    A = 65535,
+    B = 0,
+    C = 1,
+}
+
+#[repr(i16)]
+#[rustc_layout(debug)]
+enum SignedAroundZero {
+    //~^ ERROR: layout_of
+    A = -1,
+    B = 0,
+    C = 1,
+}
+
+fn main() {}
diff --git a/tests/ui/enum-discriminant/wrapping_niche.stderr b/tests/ui/enum-discriminant/wrapping_niche.stderr
new file mode 100644
index 00000000000..e3e1755e14d
--- /dev/null
+++ b/tests/ui/enum-discriminant/wrapping_niche.stderr
@@ -0,0 +1,238 @@
+error: layout_of(UnsignedAroundZero) = Layout {
+           size: Size(2 bytes),
+           align: AbiAlign {
+               abi: Align(2 bytes),
+           },
+           backend_repr: Scalar(
+               Initialized {
+                   value: Int(
+                       I16,
+                       false,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I16,
+                       false,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+           ),
+           uninhabited: false,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I16,
+                       false,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 9885373149222004003,
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 9885373149222004003,
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 2,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 9885373149222004003,
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: 2648004449468912780,
+       }
+  --> $DIR/wrapping_niche.rs:8:1
+   |
+LL | enum UnsignedAroundZero {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(SignedAroundZero) = Layout {
+           size: Size(2 bytes),
+           align: AbiAlign {
+               abi: Align(2 bytes),
+           },
+           backend_repr: Scalar(
+               Initialized {
+                   value: Int(
+                       I16,
+                       true,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I16,
+                       true,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+           ),
+           uninhabited: false,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I16,
+                       true,
+                   ),
+                   valid_range: (..=1) | (65535..),
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 2684536712112553499,
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 2684536712112553499,
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAlign {
+                           abi: Align(2 bytes),
+                       },
+                       backend_repr: Memory {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       uninhabited: false,
+                       variants: Single {
+                           index: 2,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: 2684536712112553499,
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: 10738146848450213996,
+       }
+  --> $DIR/wrapping_niche.rs:17:1
+   |
+LL | enum SignedAroundZero {
+   | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs
index 5e2e4fab51d..f4a2766ff4c 100644
--- a/tests/ui/errors/remap-path-prefix-sysroot.rs
+++ b/tests/ui/errors/remap-path-prefix-sysroot.rs
@@ -2,7 +2,7 @@
 //@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes
 //@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped
 //@ [with-remap]compile-flags: --remap-path-prefix={{src-base}}=remapped-tests-ui
-//@ [without-remap]compile-flags:
+// [without-remap] no extra compile-flags
 
 // The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically
 // as the remapped revision will not begin with $SRC_DIR_REAL,
diff --git a/tests/ui/errors/wrong-target-spec.rs b/tests/ui/errors/wrong-target-spec.rs
index a3a0e05d826..1a976888112 100644
--- a/tests/ui/errors/wrong-target-spec.rs
+++ b/tests/ui/errors/wrong-target-spec.rs
@@ -2,6 +2,7 @@
 // checks that such invalid target specs are rejected by the compiler.
 // See https://github.com/rust-lang/rust/issues/33329
 
+// ignore-tidy-target-specific-tests
 //@ needs-llvm-components: x86
 //@ compile-flags: --target x86_64_unknown-linux-musl
 
diff --git a/tests/ui/linkage-attr/unstable-flavor.rs b/tests/ui/linkage-attr/unstable-flavor.rs
index 6aa9efb58d1..5412e248f34 100644
--- a/tests/ui/linkage-attr/unstable-flavor.rs
+++ b/tests/ui/linkage-attr/unstable-flavor.rs
@@ -4,9 +4,9 @@
 //
 //@ revisions: bpf ptx
 //@ [bpf] compile-flags: --target=bpfel-unknown-none -C linker-flavor=bpf --crate-type=rlib
-//@ [bpf] needs-llvm-components:
+//@ [bpf] needs-llvm-components: bpf
 //@ [ptx] compile-flags: --target=nvptx64-nvidia-cuda -C linker-flavor=ptx --crate-type=rlib
-//@ [ptx] needs-llvm-components:
+//@ [ptx] needs-llvm-components: nvptx
 
 #![feature(no_core)]
 #![no_core]
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
index a445534c8d8..2742162c821 100644
--- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -9,6 +9,9 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 mut &'^1 i32, &'^2 i32)),
                (),
            ]
+   = note: late-bound region is '?1
+   = note: late-bound region is '?2
+   = note: late-bound region is '?3
 
 error: lifetime may not live long enough
   --> $DIR/escape-argument-callee.rs:26:45
diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr
index 7fd1cd8c3e4..22cb0367ad8 100644
--- a/tests/ui/nll/closure-requirements/escape-argument.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument.stderr
@@ -9,6 +9,8 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 mut &'^1 i32, &'^1 i32)),
                (),
            ]
+   = note: late-bound region is '?1
+   = note: late-bound region is '?2
 
 note: no external requirements
   --> $DIR/escape-argument.rs:20:1
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 60087ec992b..134ce99014d 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -9,6 +9,8 @@ LL |         |_outlives1, _outlives2, _outlives3, x, y| {
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'?2 &'^0 u32>, std::cell::Cell<&'^1 &'?3 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
                (),
            ]
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
    = note: late-bound region is '?4
    = note: late-bound region is '?5
    = note: late-bound region is '?6
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 7325a9de8b2..f5527eeb2cd 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -9,6 +9,12 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'^3 &'?2 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
                (),
            ]
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
+   = note: late-bound region is '?9
+   = note: late-bound region is '?10
    = note: late-bound region is '?3
    = note: late-bound region is '?4
    = note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 621c1ea083b..e13653f3423 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -9,6 +9,7 @@ LL |     foo(cell, |cell_a, cell_x| {
                for<Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&'^0 u32>)),
                (),
            ]
+   = note: late-bound region is '?2
 
 error[E0521]: borrowed data escapes outside of closure
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:22:9
@@ -43,6 +44,7 @@ LL |     foo(cell, |cell_a, cell_x| {
                for<Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&'^0 u32>)),
                (),
            ]
+   = note: late-bound region is '?2
    = note: number of external vids: 2
    = note: where '?1: '?0
 
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index b9365c94a1b..9e9eae98597 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -9,6 +9,11 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'^1 u32>, &'^3 std::cell::Cell<&'^4 u32>)),
                (),
            ]
+   = note: late-bound region is '?4
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
    = note: late-bound region is '?2
    = note: late-bound region is '?3
    = note: number of external vids: 4
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index e5d2867103c..303fcd4cdfc 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -9,6 +9,12 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'?1 &'^1 u32>, &'^2 std::cell::Cell<&'?2 &'^3 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
                (),
            ]
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
+   = note: late-bound region is '?9
+   = note: late-bound region is '?10
    = note: late-bound region is '?3
    = note: late-bound region is '?4
    = note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
index a14bfb06e83..aa75b4c811c 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -9,6 +9,8 @@ LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'^1 &'?2 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
                (),
            ]
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
    = note: late-bound region is '?3
    = note: late-bound region is '?4
    = note: number of external vids: 5
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index 49c65d77ddd..30ee259d3dc 100644
--- a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -9,6 +9,8 @@ LL |         |_outlives1, _outlives2, x, y| {
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::cell::Cell<&'?1 &'^0 u32>, std::cell::Cell<&'^1 &'?2 u32>, std::cell::Cell<&'^0 u32>, std::cell::Cell<&'^1 u32>)),
                (),
            ]
+   = note: late-bound region is '?4
+   = note: late-bound region is '?5
    = note: late-bound region is '?3
    = note: number of external vids: 4
    = note: where '?1: '?2
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index f48ed2823dd..6b04e346c69 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -9,6 +9,11 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'^1 &'?1 u32>, &'^2 std::cell::Cell<&'^3 u32>, &'^4 std::cell::Cell<&'^1 u32>)),
                (),
            ]
+   = note: late-bound region is '?4
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
    = note: late-bound region is '?2
    = note: late-bound region is '?3
 
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index a090e94593f..ae2129c65f2 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -9,6 +9,12 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
                for<Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 std::cell::Cell<&'^1 &'?1 u32>, &'^2 std::cell::Cell<&'^3 &'?2 u32>, &'^4 std::cell::Cell<&'^1 u32>, &'^5 std::cell::Cell<&'^3 u32>)),
                (),
            ]
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
+   = note: late-bound region is '?7
+   = note: late-bound region is '?8
+   = note: late-bound region is '?9
+   = note: late-bound region is '?10
    = note: late-bound region is '?3
    = note: late-bound region is '?4
 
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index bc5c04a27a3..1f1cce1e885 100644
--- a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -9,6 +9,8 @@ LL |     expect_sig(|a, b| b); // ought to return `a`
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((&'^0 i32, &'^1 i32)) -> &'^0 i32,
                (),
            ]
+   = note: late-bound region is '?1
+   = note: late-bound region is '?2
 
 error: lifetime may not live long enough
   --> $DIR/return-wrong-bound-region.rs:11:23
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index e58764354c0..396e149554c 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -9,6 +9,8 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &'^0 ()>>, &'^1 T)),
                (),
            ]
+   = note: late-bound region is '?2
+   = note: late-bound region is '?3
    = note: number of external vids: 2
    = note: where T: '?1
 
@@ -31,6 +33,8 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
                for<Region(BrAnon), Region(BrAnon)> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &'^0 ()>>, &'^1 T)),
                (),
            ]
+   = note: late-bound region is '?3
+   = note: late-bound region is '?4
    = note: late-bound region is '?2
    = note: number of external vids: 3
    = note: where T: '?1
diff --git a/tests/ui/target_modifiers/defaults_check.rs b/tests/ui/target_modifiers/defaults_check.rs
index de72acd32bc..ce1d534fd75 100644
--- a/tests/ui/target_modifiers/defaults_check.rs
+++ b/tests/ui/target_modifiers/defaults_check.rs
@@ -6,7 +6,7 @@
 //@ needs-llvm-components: x86
 
 //@ revisions: ok ok_explicit error
-//@[ok] compile-flags:
+// [ok] no extra compile-flags
 //@[ok_explicit] compile-flags: -Zreg-struct-return=false
 //@[error] compile-flags: -Zreg-struct-return=true
 //@[ok] check-pass
diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.rs b/tests/ui/target_modifiers/incompatible_fixedx18.rs
index 6c13984f608..5ba676406ee 100644
--- a/tests/ui/target_modifiers/incompatible_fixedx18.rs
+++ b/tests/ui/target_modifiers/incompatible_fixedx18.rs
@@ -5,7 +5,7 @@
 //@ revisions:allow_match allow_mismatch error_generated
 //@[allow_match] compile-flags: -Zfixed-x18
 //@[allow_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=fixed-x18
-//@[error_generated] compile-flags:
+// [error_generated] no extra compile-flags
 //@[allow_mismatch] check-pass
 //@[allow_match] check-pass
 
diff --git a/tests/ui/target_modifiers/incompatible_regparm.rs b/tests/ui/target_modifiers/incompatible_regparm.rs
index 395c26fc2c0..e76bfc976a1 100644
--- a/tests/ui/target_modifiers/incompatible_regparm.rs
+++ b/tests/ui/target_modifiers/incompatible_regparm.rs
@@ -5,7 +5,7 @@
 //@ revisions:allow_regparm_mismatch allow_no_value error_generated
 //@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
 //@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch
-//@[error_generated] compile-flags:
+// [error_generated] no extra compile-flags
 //@[allow_regparm_mismatch] check-pass
 
 #![feature(no_core)]
diff --git a/tests/ui/target_modifiers/no_value_bool.rs b/tests/ui/target_modifiers/no_value_bool.rs
index ceba40afa89..72130f8737c 100644
--- a/tests/ui/target_modifiers/no_value_bool.rs
+++ b/tests/ui/target_modifiers/no_value_bool.rs
@@ -8,7 +8,7 @@
 //@ revisions: ok ok_explicit error error_explicit
 //@[ok] compile-flags: -Zreg-struct-return
 //@[ok_explicit] compile-flags: -Zreg-struct-return=true
-//@[error] compile-flags:
+// [error] no extra compile-flags
 //@[error_explicit] compile-flags: -Zreg-struct-return=false
 //@[ok] check-pass
 //@[ok_explicit] check-pass
diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs
index 2436be50027..316a857662a 100644
--- a/tests/ui/transmutability/enums/niche_optimization.rs
+++ b/tests/ui/transmutability/enums/niche_optimization.rs
@@ -75,8 +75,8 @@ fn one_niche() {
 
     assert::is_transmutable::<OptionLike, u8>();
     assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V1, OptionLike>();
     assert::is_transmutable::<V254, OptionLike>();
-    assert::is_transmutable::<V255, OptionLike>();
 }
 
 fn one_niche_alt() {
@@ -97,9 +97,9 @@ fn one_niche_alt() {
     };
 
     assert::is_transmutable::<OptionLike, u8>();
-    assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V1, OptionLike>();
+    assert::is_transmutable::<V2, OptionLike>();
     assert::is_transmutable::<V254, OptionLike>();
-    assert::is_transmutable::<V255, OptionLike>();
 }
 
 fn two_niche() {
@@ -121,9 +121,9 @@ fn two_niche() {
 
     assert::is_transmutable::<OptionLike, u8>();
     assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V1, OptionLike>();
+    assert::is_transmutable::<V2, OptionLike>();
     assert::is_transmutable::<V253, OptionLike>();
-    assert::is_transmutable::<V254, OptionLike>();
-    assert::is_transmutable::<V255, OptionLike>();
 }
 
 fn no_niche() {
@@ -142,7 +142,7 @@ fn no_niche() {
     }
 
     const _: () = {
-        assert!(std::mem::size_of::<OptionLike>() == 2);
+        assert!(std::mem::size_of::<OptionLike>() == 1);
     };
 
     #[repr(C)]
diff --git a/tests/ui/hello_world/main.rs b/tests/ui/warnings/hello-world.rs
index 1b687eb1373..1b687eb1373 100644
--- a/tests/ui/hello_world/main.rs
+++ b/tests/ui/warnings/hello-world.rs
diff --git a/triagebot.toml b/triagebot.toml
index 894f56df741..e1b4983adf7 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -50,6 +50,21 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
+# [backport.*] sections autonominate pull requests for a backport
+# see: https://forge.rust-lang.org/triagebot/backport.html
+
+[backport.t-compiler-beta-backport]
+# The pull request MUST have one of these labels
+required-pr-labels = ["T-compiler"]
+# The regression MUST have this label
+required-issue-label = "regression-from-stable-to-beta"
+# if the above conditions matches, the PR will receive these labels
+add-labels = ["beta-nominated"]
+
+[backport.t-compiler-stable-backport]
+required-pr-labels = ["T-compiler"]
+required-issue-label = "regression-from-stable-to-stable"
+add-labels = ["stable-nominated"]
 
 # ------------------------------------------------------------------------------
 # Ping groups