about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-07-02 20:25:23 +0000
committerbors <bors@rust-lang.org>2025-07-02 20:25:23 +0000
commit6677875279b560442a07a08d5119b4cd6b3c5593 (patch)
tree042116f02b557a7f5cdf876003e854d59bd2553c
parent1ce9c977ffcff7c3b12bfe5629a682da0e74a7a1 (diff)
parentc572231fb911433fea2b5748da3e9bc1bf9cf2c2 (diff)
downloadrust-6677875279b560442a07a08d5119b4cd6b3c5593.tar.gz
rust-6677875279b560442a07a08d5119b4cd6b3c5593.zip
Auto merge of #143337 - matthiaskrgr:rollup-lqwhe0i, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#141847 (Explain `TOCTOU` on the top of `std::fs`, and reference it in functions)
 - rust-lang/rust#142138 (Add `Vec::into_chunks`)
 - rust-lang/rust#142321 (Expose elf abi on ppc64 targets)
 - rust-lang/rust#142886 (ci: aarch64-gnu: Stop skipping `panic_abort_doc_tests`)
 - rust-lang/rust#143194 (fix bitcast of single-element SIMD vectors)
 - rust-lang/rust#143231 (Suggest use another lifetime specifier instead of underscore lifetime)
 - rust-lang/rust#143232 ([COMPILETEST-UNTANGLE 3/N] Use "directives" consistently within compiletest)
 - rust-lang/rust#143258 (Don't recompute `DisambiguatorState` for every RPITIT in trait definition)
 - rust-lang/rust#143274 (ci: support optional jobs)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs28
-rw-r--r--compiler/rustc_middle/src/query/mod.rs7
-rw-r--r--compiler/rustc_resolve/messages.ftl1
-rw-r--r--compiler/rustc_resolve/src/errors.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs58
-rw-r--r--library/alloc/src/vec/mod.rs55
-rw-r--r--library/std/src/fs.rs50
-rw-r--r--library/std/src/path.rs6
-rw-r--r--src/ci/citool/src/jobs.rs7
-rw-r--r--src/ci/citool/src/jobs/tests.rs26
-rw-r--r--src/ci/citool/tests/test-jobs.yml5
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile3
-rw-r--r--src/ci/github-actions/jobs.yml11
-rw-r--r--src/tools/compiletest/src/directive-list.rs2
-rw-r--r--src/tools/compiletest/src/directives.rs (renamed from src/tools/compiletest/src/header.rs)41
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs (renamed from src/tools/compiletest/src/header/auxiliary.rs)2
-rw-r--r--src/tools/compiletest/src/directives/cfg.rs (renamed from src/tools/compiletest/src/header/cfg.rs)2
-rw-r--r--src/tools/compiletest/src/directives/needs.rs (renamed from src/tools/compiletest/src/header/needs.rs)2
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs (renamed from src/tools/compiletest/src/header/test-auxillary/error_annotation.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/known_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/known_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile (renamed from src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/tests.rs (renamed from src/tools/compiletest/src/header/tests.rs)8
-rw-r--r--src/tools/compiletest/src/lib.rs14
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs6
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs4
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs2
-rw-r--r--tests/codegen/transmute-scalar.rs55
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/error-codes/E0637.stderr2
-rw-r--r--tests/ui/underscore-lifetime/in-binder.stderr12
-rw-r--r--tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr4
42 files changed, 306 insertions, 132 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 7ef04213d32..60cf4e28b5a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     // While optimizations will remove no-op transmutes, they might still be
     // there in debug or things that aren't no-op in MIR because they change
     // the Rust type but not the underlying layout/niche.
-    if from_scalar == to_scalar {
+    if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
         return imm;
     }
 
@@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
     imm = match (from_scalar.primitive(), to_scalar.primitive()) {
-        (Int(..) | Float(_), Int(..) | Float(_)) => {
-            if from_backend_ty == to_backend_ty {
-                imm
-            } else {
-                bx.bitcast(imm, to_backend_ty)
-            }
-        }
+        (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
         (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
         (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
         (Pointer(..), Int(..)) => {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 6b2854d96af..d2566cda7bf 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2459,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // type a projection.
                 let in_trait = match opaque_ty.origin {
                     hir::OpaqueTyOrigin::FnReturn {
+                        parent,
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
                     }
                     | hir::OpaqueTyOrigin::AsyncFn {
+                        parent,
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
-                    } => true,
+                    } => Some(parent),
                     hir::OpaqueTyOrigin::FnReturn {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
@@ -2474,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
                     }
-                    | hir::OpaqueTyOrigin::TyAlias { .. } => false,
+                    | hir::OpaqueTyOrigin::TyAlias { .. } => None,
                 };
 
                 self.lower_opaque_ty(opaque_ty.def_id, in_trait)
@@ -2594,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
     #[instrument(level = "debug", skip(self), ret)]
-    fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
+    fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
         let tcx = self.tcx();
 
         let lifetimes = tcx.opaque_captured_lifetimes(def_id);
         debug!(?lifetimes);
 
-        // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
-        // generate the def_id of an associated type for the trait and return as
-        // type a projection.
-        let def_id = if in_trait {
-            tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id()
+        // If this is an RPITIT and we are using the new RPITIT lowering scheme,
+        // do a linear search to map this to the synthetic associated type that
+        // it will be lowered to.
+        let def_id = if let Some(parent_def_id) = in_trait {
+            *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id)
+                .iter()
+                .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) {
+                    Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
+                        opaque_def_id.expect_local() == def_id
+                    }
+                    _ => unreachable!(),
+                })
+                .unwrap()
         } else {
             def_id.to_def_id()
         };
@@ -2627,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         });
         debug!(?args);
 
-        if in_trait {
+        if in_trait.is_some() {
             Ty::new_projection_from_args(tcx, def_id, args)
         } else {
             Ty::new_opaque(tcx, def_id, args)
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 3e68f0f784e..05154633a38 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1093,13 +1093,6 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
-    /// associated item.
-    query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
-        desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
-        cache_on_disk_if { true }
-    }
-
     /// Given an `impl_id`, return the trait it implements along with some header information.
     /// Return `None` if this is an inherent impl.
     query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 58942474e32..aa818cc9c46 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -432,6 +432,7 @@ resolve_undeclared_label =
 
 resolve_underscore_lifetime_is_reserved = `'_` cannot be used here
     .label = `'_` is a reserved lifetime name
+    .help = use another lifetime specifier
 
 resolve_unexpected_res_change_ty_to_const_param_sugg =
     you might have meant to write a const parameter here
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 6d3752c0c83..671f4ed9842 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
 
 #[derive(Diagnostic)]
 #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)]
+#[help]
 pub(crate) struct UnderscoreLifetimeIsReserved {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index 66733d5d4b8..b01ca989282 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index ecf68ddff8c..bc7e445f3f8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv1".into();
     base.llvm_abiname = "elfv1".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index e205aef8285..4dc76f0936c 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index bcb328020ee..9dc44aa05cc 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 37c888ba514..10072f8092d 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv1".into();
     base.llvm_abiname = "elfv1".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 3096c4d14ad..a7f4e0eabb0 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index 9e406af53b5..af5704b51ba 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index f145c5b8c14..26ee6a68c6a 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index f14a45aa1e3..a65f9b347dc 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,9 +1,8 @@
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatorState};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) {
         associated_item_def_ids,
         associated_items,
         associated_types_for_impl_traits_in_associated_fn,
-        associated_type_for_impl_trait_in_trait,
         impl_item_implementor_ids,
         ..*providers
     };
@@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
         container: ty::AssocItemContainer::Impl,
     }
 }
-struct RPITVisitor {
-    rpits: FxIndexSet<LocalDefId>,
+struct RPITVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    synthetics: Vec<LocalDefId>,
+    data: DefPathData,
+    disambiguator: DisambiguatorState,
 }
 
-impl<'tcx> Visitor<'tcx> for RPITVisitor {
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
-        if let hir::TyKind::OpaqueDef(opaq) = ty.kind
-            && self.rpits.insert(opaq.def_id)
-        {
-            for bound in opaq.bounds {
-                intravisit::walk_param_bound(self, bound);
-            }
-        }
-        intravisit::walk_ty(self, ty)
+impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
+    fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
+        self.synthetics.push(associated_type_for_impl_trait_in_trait(
+            self.tcx,
+            opaque.def_id,
+            self.data,
+            &mut self.disambiguator,
+        ));
+        intravisit::walk_opaque_ty(self, opaque)
     }
 }
 
@@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
     match tcx.def_kind(parent_def_id) {
         DefKind::Trait => {
-            let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
-
             if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
+                let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
+                let mut visitor = RPITVisitor {
+                    tcx,
+                    synthetics: vec![],
+                    data,
+                    disambiguator: DisambiguatorState::with(parent_def_id, data, 0),
+                };
                 visitor.visit_fn_ret_ty(output);
-
-                tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
-                    tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
-                }))
+                tcx.arena.alloc_from_iter(
+                    visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
+                )
             } else {
                 &[]
             }
@@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn(
             let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
                 return &[];
             };
-
             tcx.arena.alloc_from_iter(
                 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
                     move |&trait_assoc_def_id| {
@@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn(
 fn associated_type_for_impl_trait_in_trait(
     tcx: TyCtxt<'_>,
     opaque_ty_def_id: LocalDefId,
+    data: DefPathData,
+    disambiguator: &mut DisambiguatorState,
 ) -> LocalDefId {
     let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
     | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
@@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait(
     let trait_def_id = tcx.local_parent(fn_def_id);
     assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
 
-    // Collect all opaque types in return position for the method and use
-    // the index as the disambiguator to make an unique def path.
-    let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
-    visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap());
-    let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap();
-
     let span = tcx.def_span(opaque_ty_def_id);
     // Also use the method name to create an unique def path.
-    let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
     let trait_assoc_ty = tcx.at(span).create_def(
         trait_def_id,
         // No name because this is an anonymous associated type.
         None,
         DefKind::AssocTy,
         Some(data),
-        &mut DisambiguatorState::with(trait_def_id, data, disambiguator),
+        disambiguator,
     );
 
     let local_def_id = trait_assoc_ty.def_id();
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 5bd82560da7..ee7a882a13c 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -3031,6 +3031,61 @@ impl<T, A: Allocator> Vec<T, A> {
             (initialized, spare, &mut self.len)
         }
     }
+
+    /// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping
+    /// elements in the remainder. `N` must be greater than zero.
+    ///
+    /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the
+    /// nearest multiple with a reallocation or deallocation.
+    ///
+    /// This function can be used to reverse [`Vec::into_flattened`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_into_chunks)]
+    ///
+    /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]);
+    ///
+    /// let vec = vec![0, 1, 2, 3];
+    /// let chunks: Vec<[u8; 10]> = vec.into_chunks();
+    /// assert!(chunks.is_empty());
+    ///
+    /// let flat = vec![0; 8 * 8 * 8];
+    /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks();
+    /// assert_eq!(reshaped.len(), 1);
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "vec_into_chunks", issue = "142137")]
+    pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> {
+        const {
+            assert!(N != 0, "chunk size must be greater than zero");
+        }
+
+        let (len, cap) = (self.len(), self.capacity());
+
+        let len_remainder = len % N;
+        if len_remainder != 0 {
+            self.truncate(len - len_remainder);
+        }
+
+        let cap_remainder = cap % N;
+        if !T::IS_ZST && cap_remainder != 0 {
+            self.buf.shrink_to_fit(cap - cap_remainder);
+        }
+
+        let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc();
+
+        // SAFETY:
+        // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
+        // - `[T; N]` has the same alignment as `T`
+        // - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap`
+        // - `len / N <= cap / N` because `len <= cap`
+        // - the allocated memory consists of `len / N` valid values of type `[T; N]`
+        // - `cap / N` fits the size of the allocated memory after shrinking
+        unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) }
+    }
 }
 
 impl<T: Clone, A: Allocator> Vec<T, A> {
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index d9902d41928..8f6c8386c25 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -4,6 +4,27 @@
 //! filesystem. All methods in this module represent cross-platform filesystem
 //! operations. Extra platform-specific functionality can be found in the
 //! extension traits of `std::os::$platform`.
+//!
+//! # Time of Check to Time of Use (TOCTOU)
+//!
+//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use"
+//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions)
+//! and then uses the result of that check to make a decision, but the condition may have changed
+//! between the check and the use.
+//!
+//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to
+//! TOCTOU - another process could create the file between your check and creation attempt.
+//!
+//! Another example is with symbolic links: when removing a directory, if another process replaces
+//! the directory with a symbolic link between the check and the removal operation, the removal
+//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use
+//! atomic operations to prevent such race conditions.
+//!
+//! To avoid TOCTOU issues:
+//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by
+//! changes made by other processes.
+//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating).
+//! - Keep file open for the duration of operations.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
@@ -548,13 +569,14 @@ impl File {
     /// non-exhaustive list of likely errors.
     ///
     /// This option is useful because it is atomic. Otherwise between checking whether a file
-    /// exists and creating a new one, the file may have been created by another process (a TOCTOU
+    /// exists and creating a new one, the file may have been created by another process (a [TOCTOU]
     /// race condition / attack).
     ///
     /// This can also be written using
     /// `File::options().read(true).write(true).create_new(true).open(...)`.
     ///
     /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists
+    /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
     ///
     /// # Examples
     ///
@@ -1610,7 +1632,7 @@ impl OpenOptions {
     ///
     /// This option is useful because it is atomic. Otherwise between checking
     /// whether a file exists and creating a new one, the file may have been
-    /// created by another process (a TOCTOU race condition / attack).
+    /// created by another process (a [TOCTOU] race condition / attack).
     ///
     /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
     /// ignored.
@@ -1621,6 +1643,7 @@ impl OpenOptions {
     /// [`.create()`]: OpenOptions::create
     /// [`.truncate()`]: OpenOptions::truncate
     /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists
+    /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
     ///
     /// # Examples
     ///
@@ -2954,17 +2977,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`.
 ///
 /// ## Time-of-check to time-of-use (TOCTOU) race conditions
-/// On a few platforms there is no way to remove a directory's contents without following symlinks
-/// unless you perform a check and then operate on paths based on that directory.
-/// This allows concurrently-running code to replace the directory with a symlink after the check,
-/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race.
-/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms
-/// except the following. It should not be used in security-sensitive contexts on these platforms:
-/// - Miri: Even when emulating targets where the underlying implementation will protect against
-/// TOCTOU races, Miri will not do so.
-/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement
-/// the required platform support to do so.
+/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou).
+///
+/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default.
+/// However, on the following platforms, this protection is not provided and the function should
+/// not be used in security-sensitive contexts:
+/// - **Miri**: Even when emulating targets where the underlying implementation will protect against
+///   TOCTOU races, Miri will not do so.
+/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement
+///   the required platform support to do so.
 ///
+/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
 /// [changes]: io#platform-specific-behavior
 ///
 /// # Errors
@@ -3238,7 +3261,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
 /// permission is denied on one of the parent directories.
 ///
 /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
-/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
+/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
 /// where those bugs are not an issue.
 ///
 /// # Examples
@@ -3251,6 +3274,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
 /// ```
 ///
 /// [`Path::exists`]: crate::path::Path::exists
+/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
 #[stable(feature = "fs_try_exists", since = "1.81.0")]
 #[inline]
 pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index b734d2b324c..0ce20a143df 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3127,7 +3127,7 @@ impl Path {
     /// Returns `true` if the path points at an existing entity.
     ///
     /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
-    /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs.
+    /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
     ///
     /// This function will traverse symbolic links to query information about the
     /// destination file.
@@ -3148,6 +3148,7 @@ impl Path {
     /// check errors, call [`Path::try_exists`].
     ///
     /// [`try_exists()`]: Self::try_exists
+    /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
     #[stable(feature = "path_ext", since = "1.5.0")]
     #[must_use]
     #[inline]
@@ -3167,7 +3168,7 @@ impl Path {
     /// permission is denied on one of the parent directories.
     ///
     /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
-    /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
+    /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
     /// where those bugs are not an issue.
     ///
     /// This is an alias for [`std::fs::exists`](crate::fs::exists).
@@ -3180,6 +3181,7 @@ impl Path {
     /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
     /// ```
     ///
+    /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
     /// [`exists()`]: Self::exists
     #[stable(feature = "path_try_exists", since = "1.63.0")]
     #[inline]
diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs
index 81e002edb15..31c761d1670 100644
--- a/src/ci/citool/src/jobs.rs
+++ b/src/ci/citool/src/jobs.rs
@@ -66,6 +66,8 @@ pub struct JobDatabase {
     pub try_jobs: Vec<Job>,
     #[serde(rename = "auto")]
     pub auto_jobs: Vec<Job>,
+    #[serde(rename = "optional")]
+    pub optional_jobs: Vec<Job>,
 
     /// Shared environments for the individual run types.
     envs: JobEnvironments,
@@ -75,9 +77,10 @@ impl JobDatabase {
     /// Find `auto` jobs that correspond to the passed `pattern`.
     /// Patterns are matched using the glob syntax.
     /// For example `dist-*` matches all jobs starting with `dist-`.
-    fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
+    fn find_auto_or_optional_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
         self.auto_jobs
             .iter()
+            .chain(self.optional_jobs.iter())
             .filter(|j| glob_match::glob_match(pattern, &j.name))
             .cloned()
             .collect()
@@ -181,7 +184,7 @@ fn calculate_jobs(
                 let mut jobs: Vec<Job> = vec![];
                 let mut unknown_patterns = vec![];
                 for pattern in patterns {
-                    let matched_jobs = db.find_auto_jobs_by_pattern(pattern);
+                    let matched_jobs = db.find_auto_or_optional_jobs_by_pattern(pattern);
                     if matched_jobs.is_empty() {
                         unknown_patterns.push(pattern.clone());
                     } else {
diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs
index ed5444d4333..63ac508b632 100644
--- a/src/ci/citool/src/jobs/tests.rs
+++ b/src/ci/citool/src/jobs/tests.rs
@@ -46,6 +46,13 @@ auto:
     - name: test-msvc-i686-2
       os: ubuntu
       env: {}
+optional:
+    - name: optional-job-1
+      os: ubuntu
+      env: {}
+    - name: optional-dist-x86_64
+      os: ubuntu
+      env: {}
 "#,
     )
     .unwrap();
@@ -57,12 +64,18 @@ auto:
         "*i686*",
         &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"],
     );
+    // Test that optional jobs are found
+    check_pattern(&db, "optional-*", &["optional-job-1", "optional-dist-x86_64"]);
+    check_pattern(&db, "*optional*", &["optional-job-1", "optional-dist-x86_64"]);
 }
 
 #[track_caller]
 fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) {
-    let jobs =
-        db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::<Vec<_>>();
+    let jobs = db
+        .find_auto_or_optional_jobs_by_pattern(pattern)
+        .into_iter()
+        .map(|j| j.name)
+        .collect::<Vec<_>>();
 
     assert_eq!(jobs, expected);
 }
@@ -116,8 +129,13 @@ fn validate_jobs() {
         load_job_db(&db_str).expect("Failed to load job database")
     };
 
-    let all_jobs =
-        db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::<Vec<_>>();
+    let all_jobs = db
+        .pr_jobs
+        .iter()
+        .chain(db.try_jobs.iter())
+        .chain(db.auto_jobs.iter())
+        .chain(db.optional_jobs.iter())
+        .collect::<Vec<_>>();
 
     let errors: Vec<anyhow::Error> =
         all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect();
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index d262da11102..7b349ceba3f 100644
--- a/src/ci/citool/tests/test-jobs.yml
+++ b/src/ci/citool/tests/test-jobs.yml
@@ -139,3 +139,8 @@ auto:
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
+
+# Jobs that only run when explicitly invoked via `@bors try`.
+optional:
+  - name: test-optional-job
+    <<: *job-linux-4c
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
index d5027589e0b..e6133fce83e 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
@@ -26,6 +26,5 @@ ENV RUST_CONFIGURE_ARGS \
  --enable-sanitizers \
  --enable-profiler \
  --enable-compiler-docs
-# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733
 ENV SCRIPT python3 ../x.py --stage 2 test && \
-  python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\"
+  python3 ../x.py --stage 2 test src/tools/cargo
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 3aa435003d3..1e253131c1a 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -160,6 +160,17 @@ pr:
 try:
   - <<: *job-dist-x86_64-linux
 
+# Jobs that only run when explicitly invoked in one of the following ways:
+# - comment `@bors2 try jobs=<job-name>`
+# - `try-job: <job-name>` in the PR description and comment `@bors try` or `@bors2 try`.
+optional:
+  # This job is used just to test optional jobs.
+  # It will be replaced by tier 2 and tier 3 jobs in the future.
+  - name: optional-mingw-check-1
+    env:
+      IMAGE: mingw-check-1
+    <<: *job-linux-4c
+
 # Main CI jobs that have to be green to merge a commit into master
 # These jobs automatically inherit envs.auto, to avoid repeating
 # it in each job definition.
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 2ecb4fc8652..adf2a7bffef 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -1,6 +1,6 @@
 /// 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 headers to this list when needed.
+/// 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",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/directives.rs
index 5636a146b0f..a6242cf0c22 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -11,10 +11,10 @@ use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
+use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
+use crate::directives::needs::CachedNeedsConditions;
 use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
-use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
-use crate::header::needs::CachedNeedsConditions;
 use crate::help;
 use crate::util::static_regex;
 
@@ -24,11 +24,11 @@ mod needs;
 #[cfg(test)]
 mod tests;
 
-pub struct HeadersCache {
+pub struct DirectivesCache {
     needs: CachedNeedsConditions,
 }
 
-impl HeadersCache {
+impl DirectivesCache {
     pub fn load(config: &Config) -> Self {
         Self { needs: CachedNeedsConditions::load(config) }
     }
@@ -54,7 +54,7 @@ impl EarlyProps {
     pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
         let mut props = EarlyProps::default();
         let mut poisoned = false;
-        iter_header(
+        iter_directives(
             config.mode,
             &config.suite,
             &mut poisoned,
@@ -138,12 +138,12 @@ pub struct TestProps {
     pub incremental_dir: Option<Utf8PathBuf>,
     // If `true`, this test will use incremental compilation.
     //
-    // This can be set manually with the `incremental` header, or implicitly
+    // This can be set manually with the `incremental` directive, or implicitly
     // by being a part of an incremental mode test. Using the `incremental`
-    // header should be avoided if possible; using an incremental mode test is
+    // directive should be avoided if possible; using an incremental mode test is
     // preferred. Incremental mode tests support multiple passes, which can
     // verify that the incremental cache can be loaded properly after being
-    // created. Just setting the header will only verify the behavior with
+    // created. Just setting the directive will only verify the behavior with
     // creating an incremental cache, but doesn't check that it is created
     // correctly.
     //
@@ -347,7 +347,7 @@ impl TestProps {
 
             let mut poisoned = false;
 
-            iter_header(
+            iter_directives(
                 config.mode,
                 &config.suite,
                 &mut poisoned,
@@ -642,11 +642,11 @@ impl TestProps {
         let check_ui = |mode: &str| {
             // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
             if config.mode != Mode::Ui && config.mode != Mode::Crashes {
-                panic!("`{}-fail` header is only supported in UI tests", mode);
+                panic!("`{}-fail` directive is only supported in UI tests", mode);
             }
         };
         if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") {
-            panic!("`compile-fail` header is useless in UI tests");
+            panic!("`compile-fail` directive is useless in UI tests");
         }
         let fail_mode = if config.parse_name_directive(ln, "check-fail") {
             check_ui("check");
@@ -662,7 +662,7 @@ impl TestProps {
         };
         match (self.fail_mode, fail_mode) {
             (None, Some(_)) => self.fail_mode = fail_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -674,10 +674,10 @@ impl TestProps {
             (Mode::Codegen, "build-pass") => (),
             (Mode::Incremental, _) => {
                 if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
-                    panic!("`{s}` header is only supported in `cfail` incremental tests")
+                    panic!("`{s}` directive is only supported in `cfail` incremental tests")
                 }
             }
-            (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
+            (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"),
         };
         let pass_mode = if config.parse_name_directive(ln, "check-pass") {
             check_no_run("check-pass");
@@ -693,7 +693,7 @@ impl TestProps {
         };
         match (self.pass_mode, pass_mode) {
             (None, Some(_)) => self.pass_mode = pass_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -794,7 +794,7 @@ 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_header`] passes to its callback function.
+/// which [`iter_directives`] passes to its callback function.
 ///
 /// For example:
 ///
@@ -867,7 +867,7 @@ pub(crate) fn check_directive<'a>(
 
 const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
 
-fn iter_header(
+fn iter_directives(
     mode: Mode,
     _suite: &str,
     poisoned: &mut bool,
@@ -1163,8 +1163,7 @@ enum NormalizeKind {
     Stderr64bit,
 }
 
-/// Parses the regex and replacement values of a `//@ normalize-*` header,
-/// in the format:
+/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format:
 /// ```text
 /// "REGEX" -> "REPLACEMENT"
 /// ```
@@ -1373,7 +1372,7 @@ where
 
 pub(crate) fn make_test_description<R: Read>(
     config: &Config,
-    cache: &HeadersCache,
+    cache: &DirectivesCache,
     name: String,
     path: &Utf8Path,
     src: R,
@@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description<R: Read>(
     let mut local_poisoned = false;
 
     // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
-    iter_header(
+    iter_directives(
         config.mode,
         &config.suite,
         &mut local_poisoned,
diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index 0e1f3a785f8..cdb75f6ffa9 100644
--- a/src/tools/compiletest/src/header/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -3,8 +3,8 @@
 
 use std::iter;
 
+use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
-use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index f1f1384afb9..35f6a9e1644 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -1,7 +1,7 @@
 use std::collections::HashSet;
 
 use crate::common::{CompareMode, Config, Debugger};
-use crate::header::IgnoreDecision;
+use crate::directives::IgnoreDecision;
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/directives/needs.rs
index b1165f4bb18..ee46f4c70cb 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/directives/needs.rs
@@ -1,5 +1,5 @@
 use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
-use crate::header::{IgnoreDecision, llvm_has_libzstd};
+use crate::directives::{IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
index fea66a5e07b..fea66a5e07b 100644
--- a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
index 99834b14c1e..99834b14c1e 100644
--- a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
index 4b565e0e6df..4b565e0e6df 100644
--- a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile
+++ b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
index d4406031043..d4406031043 100644
--- a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 31b49b09bcd..d4570f82677 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -4,7 +4,7 @@ use camino::Utf8Path;
 use semver::Version;
 
 use super::{
-    EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header,
+    DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
     parse_normalize_rule,
 };
 use crate::common::{Config, Debugger, Mode};
@@ -17,9 +17,9 @@ fn make_test_description<R: Read>(
     src: R,
     revision: Option<&str>,
 ) -> CollectedTestDesc {
-    let cache = HeadersCache::load(config);
+    let cache = DirectivesCache::load(config);
     let mut poisoned = false;
-    let test = crate::header::make_test_description(
+    let test = crate::directives::make_test_description(
         config,
         &cache,
         name,
@@ -785,7 +785,7 @@ fn threads_support() {
 
 fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
     let rdr = std::io::Cursor::new(&buf);
-    iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
+    iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 09de3eb4c70..dfce4b8b408 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -12,9 +12,9 @@ pub mod common;
 pub mod compute_diff;
 mod debuggers;
 pub mod diagnostics;
+pub mod directives;
 pub mod errors;
 mod executor;
-pub mod header;
 mod json;
 mod raise_fd_limit;
 mod read2;
@@ -37,13 +37,13 @@ use rayon::iter::{ParallelBridge, ParallelIterator};
 use tracing::debug;
 use walkdir::WalkDir;
 
-use self::header::{EarlyProps, make_test_description};
+use self::directives::{EarlyProps, make_test_description};
 use crate::common::{
     CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
     output_base_dir, output_relative_path,
 };
+use crate::directives::DirectivesCache;
 use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
-use crate::header::HeadersCache;
 use crate::util::logv;
 
 /// Creates the `Config` instance for this invocation of compiletest.
@@ -254,8 +254,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
     let llvm_version =
-        matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else(
-            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
+        matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else(
+            || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
     let run_ignored = matches.opt_present("ignored");
@@ -618,7 +618,7 @@ pub fn run_tests(config: Arc<Config>) {
 /// Read-only context data used during test collection.
 struct TestCollectorCx {
     config: Arc<Config>,
-    cache: HeadersCache,
+    cache: DirectivesCache,
     common_inputs_stamp: Stamp,
     modified_tests: Vec<Utf8PathBuf>,
 }
@@ -654,7 +654,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
         modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
             fatal!("modified_tests: {}: {err}", config.src_test_suite_root);
         });
-    let cache = HeadersCache::load(&config);
+    let cache = DirectivesCache::load(&config);
 
     let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
     let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new(""))
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 53b5990d3cd..f8bf4ee3022 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -23,8 +23,8 @@ use crate::common::{
     output_base_dir, output_base_name, output_testname_unique,
 };
 use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
+use crate::directives::TestProps;
 use crate::errors::{Error, ErrorKind, load_errors};
-use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
 use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
 use crate::{ColorConfig, help, json, stamp_file_path, warning};
@@ -2039,7 +2039,7 @@ impl<'test> TestCx<'test> {
         // Provide more context on failures.
         filecheck.args(&["--dump-input-context", "100"]);
 
-        // Add custom flags supplied by the `filecheck-flags:` test header.
+        // Add custom flags supplied by the `filecheck-flags:` test directive.
         filecheck.args(&self.props.filecheck_flags);
 
         // FIXME(jieyouxu): don't pass an empty Path
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 31240dff9a1..d9e1e4dfc8d 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -49,7 +49,7 @@ impl TestCx<'_> {
             std::fs::remove_file(pdb_file).unwrap();
         }
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
@@ -135,7 +135,7 @@ impl TestCx<'_> {
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compiler_run_result = self.compile_test(should_run, Emit::None);
         if !compiler_run_result.status.success() {
@@ -359,7 +359,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index cc50a918f75..f6bc85cd051 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -52,10 +52,10 @@ impl TestCx<'_> {
             // don't test rustfix with nll right now
         } else if self.config.rustfix_coverage {
             // Find out which tests have `MachineApplicable` suggestions but are missing
-            // `run-rustfix` or `run-rustfix-only-machine-applicable` headers.
+            // `run-rustfix` or `run-rustfix-only-machine-applicable` directives.
             //
             // This will return an empty `Vec` in case the executed test file has a
-            // `compile-flags: --error-format=xxxx` header with a value other than `json`.
+            // `compile-flags: --error-format=xxxx` directive with a value other than `json`.
             let suggestions = get_suggestions_from_json(
                 &rustfix_input,
                 &HashSet::new(),
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index addb0af4a54..6461f38f527 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 use std::{env, fs};
 
 use build_helper::util::try_run;
-use compiletest::header::TestProps;
+use compiletest::directives::TestProps;
 use config::Config;
 
 mod config;
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index c57ade58c30..3ac6ba3beb1 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -1,6 +1,12 @@
+//@ add-core-stubs
 //@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
 
 #![crate_type = "lib"]
+#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
+#![no_core]
+extern crate minicore;
+
+use minicore::*;
 
 // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
 // without needing to pointercast, and SRoA will turn that into a `bitcast`.
@@ -14,7 +20,7 @@
 // CHECK-NEXT: ret i32 %_0
 #[no_mangle]
 pub fn f32_to_bits(x: f32) -> u32 {
-    unsafe { std::mem::transmute(x) }
+    unsafe { mem::transmute(x) }
 }
 
 // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
@@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 {
 // CHECK-NEXT: ret i8 %_0
 #[no_mangle]
 pub fn bool_to_byte(b: bool) -> u8 {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
@@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 {
 // CHECK-NEXT: ret i1 %_0
 #[no_mangle]
 pub unsafe fn byte_to_bool(byte: u8) -> bool {
-    std::mem::transmute(byte)
+    mem::transmute(byte)
 }
 
 // CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p)
 // CHECK: ret ptr %p
 #[no_mangle]
 pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
-    unsafe { std::mem::transmute(p) }
+    unsafe { mem::transmute(p) }
 }
 
 // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
@@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
 // CHECK-NEXT: ret [[USIZE]] %_0
 #[no_mangle]
 pub fn ptr_to_int(p: *mut u16) -> usize {
-    unsafe { std::mem::transmute(p) }
+    unsafe { mem::transmute(p) }
 }
 
 // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
@@ -53,7 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
 // CHECK-NEXT: ret ptr %_0
 #[no_mangle]
 pub fn int_to_ptr(i: usize) -> *mut u16 {
-    unsafe { std::mem::transmute(i) }
+    unsafe { mem::transmute(i) }
 }
 
 // This is the one case where signedness matters to transmuting:
@@ -70,7 +76,7 @@ pub enum FakeBoolSigned {
 // CHECK-NEXT: ret i8 %_0
 #[no_mangle]
 pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
@@ -78,7 +84,7 @@ pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
 // CHECK-NEXT: ret i1 %_0
 #[no_mangle]
 pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 #[repr(u8)]
@@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned {
 // CHECK: ret i1 %b
 #[no_mangle]
 pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
 // CHECK: ret i1 %b
 #[no_mangle]
 pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
+}
+
+#[repr(simd)]
+struct S([i64; 1]);
+
+// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b)
+// CHECK: bitcast <1 x i64> %b to i64
+// CHECK: ret i64
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b)
+// CHECK: bitcast i64 %b to <1 x i64>
+// CHECK: ret <1 x i64>
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
+    unsafe { mem::transmute(b) }
 }
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 532c1ab13d1..2484974cdc2 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
+   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr
index 95a5a58ab85..88c08cb94ba 100644
--- a/tests/ui/error-codes/E0637.stderr
+++ b/tests/ui/error-codes/E0637.stderr
@@ -3,6 +3,8 @@ error[E0637]: `'_` cannot be used here
    |
 LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
    |                        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0106]: missing lifetime specifier
   --> $DIR/E0637.rs:1:62
diff --git a/tests/ui/underscore-lifetime/in-binder.stderr b/tests/ui/underscore-lifetime/in-binder.stderr
index fcd7eddb576..f25db4d0889 100644
--- a/tests/ui/underscore-lifetime/in-binder.stderr
+++ b/tests/ui/underscore-lifetime/in-binder.stderr
@@ -3,36 +3,48 @@ error[E0637]: `'_` cannot be used here
    |
 LL | impl<'_> IceCube<'_> {}
    |      ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:12:15
    |
 LL | struct Struct<'_> {
    |               ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:17:11
    |
 LL | enum Enum<'_> {
    |           ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:22:13
    |
 LL | union Union<'_> {
    |             ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:27:13
    |
 LL | trait Trait<'_> {
    |             ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:31:8
    |
 LL | fn foo<'_>() {
    |        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index d940166e9e2..50359309c92 100644
--- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -15,12 +15,16 @@ error[E0637]: `'_` cannot be used here
    |
 LL | fn foo<'_>
    |        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/underscore-lifetime-binders.rs:10:25
    |
 LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
    |                         ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:10:33