about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_gcc/build_system/src/test.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs145
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs6
-rw-r--r--compiler/rustc_target/src/abi/call/powerpc64.rs67
-rw-r--r--library/alloc/tests/task.rs4
-rw-r--r--library/core/tests/ptr.rs9
-rw-r--r--library/std/src/sys/pal/unix/rand.rs310
-rw-r--r--library/std/src/thread/mod.rs15
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs18
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs38
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs10
-rw-r--r--src/bootstrap/src/core/builder.rs13
-rw-r--r--src/bootstrap/src/core/builder/tests.rs4
-rw-r--r--src/bootstrap/src/core/config/config.rs20
-rw-r--r--src/bootstrap/src/core/config/flags.rs13
-rw-r--r--src/bootstrap/src/core/download.rs8
-rw-r--r--src/bootstrap/src/lib.rs27
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rwxr-xr-xsrc/ci/docker/scripts/x86_64-gnu-llvm.sh6
-rw-r--r--src/etc/completions/x.py.fish3
-rw-r--r--src/etc/completions/x.py.ps13
-rw-r--r--src/etc/completions/x.py.sh10
-rw-r--r--src/etc/completions/x.py.zsh3
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs53
-rw-r--r--src/tools/miri/tests/pass/dyn-traits.rs10
-rw-r--r--src/tools/miri/tests/pass/function_pointers.rs3
-rw-r--r--src/tools/miri/tests/pass/rc.rs3
-rw-r--r--tests/assembly/powerpc64-struct-abi.rs132
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr22
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr22
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.rs4
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr40
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr40
-rw-r--r--tests/ui/consts/const-eval/ub-incorrect-vtable.rs4
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.rs14
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr83
-rw-r--r--tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs (renamed from tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/async-closures.rs (renamed from tests/ui/sanitizer/cfi-async-closures.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/can-reveal-opaques.rs (renamed from tests/ui/sanitizer/cfi-can-reveal-opaques.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs (renamed from tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.stderr (renamed from tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/closures.rs (renamed from tests/ui/sanitizer/cfi-closures.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/complex-receiver.rs (renamed from tests/ui/sanitizer/cfi-complex-receiver.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/coroutine.rs (renamed from tests/ui/sanitizer/cfi-coroutine.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/drop-in-place.rs (renamed from tests/ui/sanitizer/cfi-drop-in-place.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/drop-no-principal.rs (renamed from tests/ui/sanitizer/cfi-drop-no-principal.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/fn-ptr.rs (renamed from tests/ui/sanitizer/cfi-fn-ptr.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs (renamed from tests/ui/sanitizer/cfi-generalize-pointers-attr-cfg.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs (renamed from tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.stderr (renamed from tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/invalid-attr-encoding.rs (renamed from tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr (renamed from tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr)2
-rw-r--r--tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.aarch64.stderr (renamed from tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs (renamed from tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.x86_64.stderr (renamed from tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs (renamed from tests/ui/sanitizer/cfi-normalize-integers-attr-cfg.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs (renamed from tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.stderr (renamed from tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/requires-lto.rs (renamed from tests/ui/sanitizer/cfi-requires-lto.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/requires-lto.stderr (renamed from tests/ui/sanitizer/cfi-requires-lto.stderr)0
-rw-r--r--tests/ui/sanitizer/cfi/self-ref.rs (renamed from tests/ui/sanitizer/cfi-self-ref.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/sized-associated-ty.rs (renamed from tests/ui/sanitizer/cfi-sized-associated-ty.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/supertraits.rs (renamed from tests/ui/sanitizer/cfi-supertraits.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/virtual-auto.rs (renamed from tests/ui/sanitizer/cfi-virtual-auto.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs (renamed from tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs)0
-rw-r--r--tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.stderr (renamed from tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr)0
76 files changed, 703 insertions, 535 deletions
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index dabf6c5aa3e..83fa8059b1a 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -552,7 +552,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
             &"--stage",
             &"0",
             &"tests/assembly/asm",
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_dir),
@@ -1020,7 +1020,7 @@ where
             &"--stage",
             &"0",
             &format!("tests/{}", test_type),
-            &"--rustc-args",
+            &"--compiletest-rustc-args",
             &rustc_args,
         ],
         Some(&rust_path),
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index c3d7f2234ed..37bd6d6e530 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -400,6 +400,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             (ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
                 let val = self.read_immediate(src)?;
+                // MIR building generates odd NOP casts, prevent them from causing unexpected trouble.
+                // See <https://github.com/rust-lang/rust/issues/128880>.
+                // FIXME: ideally we wouldn't have to do this.
+                if data_a == data_b {
+                    return self.write_immediate(*val, dest);
+                }
                 // Take apart the old pointer, and find the dynamic type.
                 let (old_data, old_vptr) = val.to_scalar_pair();
                 let old_data = old_data.to_pointer(self)?;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 7af4e0c285b..761ab81e228 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
 use super::{
     throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocKind, AllocRange, Allocation,
     ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy,
-    MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
+    MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, CTFE_ALLOC_SALT,
 };
 
 /// Data returned by [`Machine::after_stack_pop`], and consumed by
@@ -575,6 +575,14 @@ pub trait Machine<'tcx>: Sized {
     {
         eval(ecx, val, span, layout)
     }
+
+    /// Returns the salt to be used for a deduplicated global alloation.
+    /// If the allocation is for a function, the instance is provided as well
+    /// (this lets Miri ensure unique addresses for some functions).
+    fn get_global_alloc_salt(
+        ecx: &InterpCx<'tcx, Self>,
+        instance: Option<ty::Instance<'tcx>>,
+    ) -> usize;
 }
 
 /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
@@ -677,4 +685,12 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         let (prov, offset) = ptr.into_parts();
         Some((prov.alloc_id(), offset, prov.immutable()))
     }
+
+    #[inline(always)]
+    fn get_global_alloc_salt(
+        _ecx: &InterpCx<$tcx, Self>,
+        _instance: Option<ty::Instance<$tcx>>,
+    ) -> usize {
+        CTFE_ALLOC_SALT
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 2e5d0ae7736..910aec9b8e1 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -195,7 +195,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     pub fn fn_ptr(&mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>) -> Pointer<M::Provenance> {
         let id = match fn_val {
-            FnVal::Instance(instance) => self.tcx.reserve_and_set_fn_alloc(instance),
+            FnVal::Instance(instance) => {
+                let salt = M::get_global_alloc_salt(self, Some(instance));
+                self.tcx.reserve_and_set_fn_alloc(instance, salt)
+            }
             FnVal::Other(extra) => {
                 // FIXME(RalfJung): Should we have a cache here?
                 let id = self.tcx.reserve_alloc_id();
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 470a62026b9..2afdd02c880 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -1008,7 +1008,8 @@ where
         // Use cache for immutable strings.
         let ptr = if mutbl.is_not() {
             // Use dedup'd allocation function.
-            let id = tcx.allocate_bytes_dedup(str.as_bytes());
+            let salt = M::get_global_alloc_salt(self, None);
+            let id = tcx.allocate_bytes_dedup(str.as_bytes(), salt);
 
             // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
             M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))?
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index fb50661b826..cd4faf06655 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -28,7 +28,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ensure_monomorphic_enough(*self.tcx, ty)?;
         ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
 
-        let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref);
+        let salt = M::get_global_alloc_salt(self, None);
+        let vtable_symbolic_allocation =
+            self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref, salt);
         let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
         Ok(vtable_ptr.into())
     }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 1851a61d753..91e71c12cae 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -13,7 +13,6 @@ use std::num::NonZero;
 use std::{fmt, io};
 
 use rustc_ast::LitKind;
-use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::ErrorGuaranteed;
@@ -46,7 +45,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
 pub use self::value::Scalar;
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::{self, GenericArgKind, Instance, Ty, TyCtxt};
+use crate::ty::{self, Instance, Ty, TyCtxt};
 
 /// Uniquely identifies one of the following:
 /// - A constant
@@ -126,11 +125,10 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
             AllocDiscriminant::Alloc.encode(encoder);
             alloc.encode(encoder);
         }
-        GlobalAlloc::Function { instance, unique } => {
+        GlobalAlloc::Function { instance } => {
             trace!("encoding {:?} with {:#?}", alloc_id, instance);
             AllocDiscriminant::Fn.encode(encoder);
             instance.encode(encoder);
-            unique.encode(encoder);
         }
         GlobalAlloc::VTable(ty, poly_trait_ref) => {
             trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
@@ -219,38 +217,32 @@ impl<'s> AllocDecodingSession<'s> {
         }
 
         // Now decode the actual data.
-        let alloc_id = decoder.with_position(pos, |decoder| {
-            match alloc_kind {
-                AllocDiscriminant::Alloc => {
-                    trace!("creating memory alloc ID");
-                    let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
-                    trace!("decoded alloc {:?}", alloc);
-                    decoder.interner().reserve_and_set_memory_alloc(alloc)
-                }
-                AllocDiscriminant::Fn => {
-                    trace!("creating fn alloc ID");
-                    let instance = ty::Instance::decode(decoder);
-                    trace!("decoded fn alloc instance: {:?}", instance);
-                    let unique = bool::decode(decoder);
-                    // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
-                    // is not possible in this context. That's why the allocation stores
-                    // whether it is unique or not.
-                    decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique)
-                }
-                AllocDiscriminant::VTable => {
-                    trace!("creating vtable alloc ID");
-                    let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
-                    let poly_trait_ref =
-                        <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
-                    trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
-                    decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref)
-                }
-                AllocDiscriminant::Static => {
-                    trace!("creating extern static alloc ID");
-                    let did = <DefId as Decodable<D>>::decode(decoder);
-                    trace!("decoded static def-ID: {:?}", did);
-                    decoder.interner().reserve_and_set_static_alloc(did)
-                }
+        let alloc_id = decoder.with_position(pos, |decoder| match alloc_kind {
+            AllocDiscriminant::Alloc => {
+                trace!("creating memory alloc ID");
+                let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
+                trace!("decoded alloc {:?}", alloc);
+                decoder.interner().reserve_and_set_memory_alloc(alloc)
+            }
+            AllocDiscriminant::Fn => {
+                trace!("creating fn alloc ID");
+                let instance = ty::Instance::decode(decoder);
+                trace!("decoded fn alloc instance: {:?}", instance);
+                decoder.interner().reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT)
+            }
+            AllocDiscriminant::VTable => {
+                trace!("creating vtable alloc ID");
+                let ty = <Ty<'_> as Decodable<D>>::decode(decoder);
+                let poly_trait_ref =
+                    <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
+                trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
+                decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref, CTFE_ALLOC_SALT)
+            }
+            AllocDiscriminant::Static => {
+                trace!("creating extern static alloc ID");
+                let did = <DefId as Decodable<D>>::decode(decoder);
+                trace!("decoded static def-ID: {:?}", did);
+                decoder.interner().reserve_and_set_static_alloc(did)
             }
         });
 
@@ -265,12 +257,7 @@ impl<'s> AllocDecodingSession<'s> {
 #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
-    Function {
-        instance: Instance<'tcx>,
-        /// Stores whether this instance is unique, i.e. all pointers to this function use the same
-        /// alloc ID.
-        unique: bool,
-    },
+    Function { instance: Instance<'tcx> },
     /// This alloc ID points to a symbolic (not-reified) vtable.
     VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -323,14 +310,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
     }
 }
 
+pub const CTFE_ALLOC_SALT: usize = 0;
+
 pub(crate) struct AllocMap<'tcx> {
     /// Maps `AllocId`s to their corresponding allocations.
     alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
 
-    /// Used to ensure that statics and functions only get one associated `AllocId`.
-    //
-    // FIXME: Should we just have two separate dedup maps for statics and functions each?
-    dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
+    /// Used to deduplicate global allocations: functions, vtables, string literals, ...
+    ///
+    /// The `usize` is a "salt" used by Miri to make deduplication imperfect, thus better emulating
+    /// the actual guarantees.
+    dedup: FxHashMap<(GlobalAlloc<'tcx>, usize), AllocId>,
 
     /// The `AllocId` to assign to the next requested ID.
     /// Always incremented; never gets smaller.
@@ -368,74 +358,40 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Reserves a new ID *if* this allocation has not been dedup-reserved before.
     /// Should not be used for mutable memory.
-    fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
+    fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>, salt: usize) -> AllocId {
         let mut alloc_map = self.alloc_map.lock();
         if let GlobalAlloc::Memory(mem) = alloc {
             if mem.inner().mutability.is_mut() {
                 bug!("trying to dedup-reserve mutable memory");
             }
         }
-        if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
+        let alloc_salt = (alloc, salt);
+        if let Some(&alloc_id) = alloc_map.dedup.get(&alloc_salt) {
             return alloc_id;
         }
         let id = alloc_map.reserve();
-        debug!("creating alloc {alloc:?} with id {id:?}");
-        alloc_map.alloc_map.insert(id, alloc.clone());
-        alloc_map.dedup.insert(alloc, id);
+        debug!("creating alloc {:?} with id {id:?}", alloc_salt.0);
+        alloc_map.alloc_map.insert(id, alloc_salt.0.clone());
+        alloc_map.dedup.insert(alloc_salt, id);
         id
     }
 
     /// Generates an `AllocId` for a memory allocation. If the exact same memory has been
     /// allocated before, this will return the same `AllocId`.
-    pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>) -> AllocId {
-        self.reserve_and_set_dedup(GlobalAlloc::Memory(mem))
+    pub fn reserve_and_set_memory_dedup(self, mem: ConstAllocation<'tcx>, salt: usize) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::Memory(mem), salt)
     }
 
     /// Generates an `AllocId` for a static or return a cached one in case this function has been
     /// called on the same static before.
     pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId {
-        self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
-    }
-
-    /// Generates an `AllocId` for a function. The caller must already have decided whether this
-    /// function obtains a unique AllocId or gets de-duplicated via the cache.
-    fn reserve_and_set_fn_alloc_internal(self, instance: Instance<'tcx>, unique: bool) -> AllocId {
-        let alloc = GlobalAlloc::Function { instance, unique };
-        if unique {
-            // Deduplicate.
-            self.reserve_and_set_dedup(alloc)
-        } else {
-            // Get a fresh ID.
-            let mut alloc_map = self.alloc_map.lock();
-            let id = alloc_map.reserve();
-            alloc_map.alloc_map.insert(id, alloc);
-            id
-        }
+        let salt = 0; // Statics have a guaranteed unique address, no salt added.
+        self.reserve_and_set_dedup(GlobalAlloc::Static(static_id), salt)
     }
 
-    /// Generates an `AllocId` for a function. Depending on the function type,
-    /// this might get deduplicated or assigned a new ID each time.
-    pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
-        // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
-        // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
-        // duplicated across crates. We thus generate a new `AllocId` for every mention of a
-        // function. This means that `main as fn() == main as fn()` is false, while `let x = main as
-        // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
-        // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
-        // actually emit duplicate functions. It does that when they have non-lifetime generics, or
-        // when they can be inlined. All other functions are given a unique address.
-        // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
-        // upon for anything. But if we don't do this, backtraces look terrible.
-        let is_generic = instance
-            .args
-            .into_iter()
-            .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
-        let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline {
-            InlineAttr::Never => false,
-            _ => true,
-        };
-        let unique = !is_generic && !can_be_inlined;
-        self.reserve_and_set_fn_alloc_internal(instance, unique)
+    /// Generates an `AllocId` for a function. Will get deduplicated.
+    pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>, salt: usize) -> AllocId {
+        self.reserve_and_set_dedup(GlobalAlloc::Function { instance }, salt)
     }
 
     /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
@@ -443,8 +399,9 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         ty: Ty<'tcx>,
         poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        salt: usize,
     ) -> AllocId {
-        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref))
+        self.reserve_and_set_dedup(GlobalAlloc::VTable(ty, poly_trait_ref), salt)
     }
 
     /// Interns the `Allocation` and return a new `AllocId`, even if there's already an identical
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index dd367d38e46..971e51be256 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1438,11 +1438,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     /// Returns the same `AllocId` if called again with the same bytes.
-    pub fn allocate_bytes_dedup(self, bytes: &[u8]) -> interpret::AllocId {
+    pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
         let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
         let alloc = self.mk_const_alloc(alloc);
-        self.reserve_and_set_memory_dedup(alloc)
+        self.reserve_and_set_memory_dedup(alloc, salt)
     }
 
     /// Returns a range of the start/end indices specified with the
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index f38f27b84f0..951112dfe85 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 
-use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar};
+use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, CTFE_ALLOC_SALT};
 use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
 
 #[derive(Clone, Copy, PartialEq, HashStable)]
@@ -73,6 +73,11 @@ pub(crate) fn vtable_min_entries<'tcx>(
 
 /// Retrieves an allocation that represents the contents of a vtable.
 /// Since this is a query, allocations are cached and not duplicated.
+///
+/// This is an "internal" `AllocId` that should never be used as a value in the interpreted program.
+/// The interpreter should use `AllocId` that refer to a `GlobalAlloc::VTable` instead.
+/// (This is similar to statics, which also have a similar "internal" `AllocId` storing their
+/// initial contents.)
 pub(super) fn vtable_allocation_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
@@ -114,7 +119,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
             VtblEntry::MetadataDropInPlace => {
                 if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
                     let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
-                    let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
+                    let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                     let fn_ptr = Pointer::from(fn_alloc_id);
                     Scalar::from_pointer(fn_ptr, &tcx)
                 } else {
@@ -127,7 +132,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
             VtblEntry::Method(instance) => {
                 // Prepare the fn ptr we write into the vtable.
                 let instance = instance.polymorphize(tcx);
-                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance);
+                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                 let fn_ptr = Pointer::from(fn_alloc_id);
                 Scalar::from_pointer(fn_ptr, &tcx)
             }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 10cf545f1b7..4430aab73a8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -2,7 +2,9 @@
 
 use rustc_ast as ast;
 use rustc_hir::LangItem;
-use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, Scalar};
+use rustc_middle::mir::interpret::{
+    Allocation, LitToConstError, LitToConstInput, Scalar, CTFE_ALLOC_SALT,
+};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{
@@ -140,7 +142,7 @@ fn lit_to_mir_constant<'tcx>(
             ConstValue::Slice { data: allocation, meta: allocation.inner().size().bytes() }
         }
         (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
-            let id = tcx.allocate_bytes_dedup(data);
+            let id = tcx.allocate_bytes_dedup(data, CTFE_ALLOC_SALT);
             ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
         }
         (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) =>
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
index 11a6cb52bab..749eea0ef63 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
@@ -41,64 +41,23 @@ where
     })
 }
 
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI)
+fn classify<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI, is_ret: bool)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
-    if !ret.layout.is_sized() {
+    if arg.is_ignore() || !arg.layout.is_sized() {
         // Not touching this...
         return;
     }
-    if !ret.layout.is_aggregate() {
-        ret.extend_integer_width_to(64);
+    if !arg.layout.is_aggregate() {
+        arg.extend_integer_width_to(64);
         return;
     }
 
     // The ELFv1 ABI doesn't return aggregates in registers
-    if abi == ELFv1 {
-        ret.make_indirect();
-        return;
-    }
-
-    if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
-        ret.cast_to(uniform);
-        return;
-    }
-
-    let size = ret.layout.size;
-    let bits = size.bits();
-    if bits <= 128 {
-        let unit = if cx.data_layout().endian == Endian::Big {
-            Reg { kind: RegKind::Integer, size }
-        } else if bits <= 8 {
-            Reg::i8()
-        } else if bits <= 16 {
-            Reg::i16()
-        } else if bits <= 32 {
-            Reg::i32()
-        } else {
-            Reg::i64()
-        };
-
-        ret.cast_to(Uniform::new(unit, size));
-        return;
-    }
-
-    ret.make_indirect();
-}
-
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
-where
-    Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
-{
-    if !arg.layout.is_sized() {
-        // Not touching this...
-        return;
-    }
-    if !arg.layout.is_aggregate() {
-        arg.extend_integer_width_to(64);
+    if is_ret && abi == ELFv1 {
+        arg.make_indirect();
         return;
     }
 
@@ -108,7 +67,10 @@ where
     }
 
     let size = arg.layout.size;
-    if size.bits() <= 64 {
+    if is_ret && size.bits() > 128 {
+        // Non-homogeneous aggregates larger than two doublewords are returned indirectly.
+        arg.make_indirect();
+    } else if size.bits() <= 64 {
         // Aggregates smaller than a doubleword should appear in
         // the least-significant bits of the parameter doubleword.
         arg.cast_to(Reg { kind: RegKind::Integer, size })
@@ -138,14 +100,9 @@ where
         }
     };
 
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(cx, &mut fn_abi.ret, abi);
-    }
+    classify(cx, &mut fn_abi.ret, abi, true);
 
     for arg in fn_abi.args.iter_mut() {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(cx, arg, abi);
+        classify(cx, arg, abi, false);
     }
 }
diff --git a/library/alloc/tests/task.rs b/library/alloc/tests/task.rs
index 034039a1eae..390dec14484 100644
--- a/library/alloc/tests/task.rs
+++ b/library/alloc/tests/task.rs
@@ -4,7 +4,7 @@ use alloc::task::{LocalWake, Wake};
 use core::task::{LocalWaker, Waker};
 
 #[test]
-#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails
+#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail
 fn test_waker_will_wake_clone() {
     struct NoopWaker;
 
@@ -20,7 +20,7 @@ fn test_waker_will_wake_clone() {
 }
 
 #[test]
-#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails
+#[cfg_attr(miri, ignore)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it can fail
 fn test_local_waker_will_wake_clone() {
     struct NoopWaker;
 
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index bc1940ebf32..78d1b137e63 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -810,9 +810,12 @@ fn ptr_metadata() {
         assert_ne!(address_1, address_2);
         // Different erased type => different vtable pointer
         assert_ne!(address_2, address_3);
-        // Same erased type and same trait => same vtable pointer
-        assert_eq!(address_3, address_4);
-        assert_eq!(address_3, address_5);
+        // Same erased type and same trait => same vtable pointer.
+        // This is *not guaranteed*, so we skip it in Miri.
+        if !cfg!(miri) {
+            assert_eq!(address_3, address_4);
+            assert_eq!(address_3, address_5);
+        }
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
index 8a78ea8e7cc..cc0852aab43 100644
--- a/library/std/src/sys/pal/unix/rand.rs
+++ b/library/std/src/sys/pal/unix/rand.rs
@@ -2,7 +2,9 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     const KEY_LEN: usize = core::mem::size_of::<u64>();
 
     let mut v = [0u8; KEY_LEN * 2];
-    imp::fill_bytes(&mut v);
+    if let Err(err) = read(&mut v) {
+        panic!("failed to retrieve random hash map seed: {err}");
+    }
 
     let key1 = v[0..KEY_LEN].try_into().unwrap();
     let key2 = v[KEY_LEN..].try_into().unwrap();
@@ -10,27 +12,78 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
 }
 
-#[cfg(all(
-    unix,
-    not(target_os = "openbsd"),
-    not(target_os = "netbsd"),
-    not(target_os = "fuchsia"),
-    not(target_os = "redox"),
-    not(target_os = "vxworks"),
-    not(target_os = "emscripten"),
-    not(target_os = "vita"),
-    not(target_vendor = "apple"),
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_vendor = "apple",
+        target_os = "openbsd",
+        target_os = "emscripten",
+        target_os = "vita",
+        all(target_os = "netbsd", not(netbsd10)),
+        target_os = "fuchsia",
+        target_os = "vxworks",
+    ))] {
+        // Some systems have a syscall that directly retrieves random data.
+        // If that is guaranteed to be available, use it.
+        use imp::syscall as read;
+    } else {
+        // Otherwise, try the syscall to see if it exists only on some systems
+        // and fall back to reading from the random device otherwise.
+        fn read(bytes: &mut [u8]) -> crate::io::Result<()> {
+            use crate::fs::File;
+            use crate::io::Read;
+            use crate::sync::OnceLock;
+
+            #[cfg(any(
+                target_os = "linux",
+                target_os = "android",
+                target_os = "espidf",
+                target_os = "horizon",
+                target_os = "freebsd",
+                target_os = "dragonfly",
+                target_os = "solaris",
+                target_os = "illumos",
+                netbsd10,
+            ))]
+            if let Some(res) = imp::syscall(bytes) {
+                return res;
+            }
+
+            const PATH: &'static str = if cfg!(target_os = "redox") {
+                "/scheme/rand"
+            } else {
+                "/dev/urandom"
+            };
+
+            static FILE: OnceLock<File> = OnceLock::new();
+
+            FILE.get_or_try_init(|| File::open(PATH))?.read_exact(bytes)
+        }
+    }
+}
+
+// All these systems a `getrandom` syscall.
+//
+// It is not guaranteed to be available, so return None to fallback to the file
+// implementation.
+#[cfg(any(
+    target_os = "linux",
+    target_os = "android",
+    target_os = "espidf",
+    target_os = "horizon",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "solaris",
+    target_os = "illumos",
+    netbsd10,
 ))]
 mod imp {
-    use crate::fs::File;
-    use crate::io::Read;
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    use crate::sys::weak::syscall;
+    use crate::io::{Error, Result};
+    use crate::sync::atomic::{AtomicBool, Ordering};
+    use crate::sys::os::errno;
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
     fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
-        use crate::sync::atomic::{AtomicBool, Ordering};
-        use crate::sys::os::errno;
+        use crate::sys::weak::syscall;
 
         // A weak symbol allows interposition, e.g. for perf measurements that want to
         // disable randomness for consistency. Otherwise, we'll try a raw syscall.
@@ -59,6 +112,7 @@ mod imp {
     }
 
     #[cfg(any(
+        target_os = "dragonfly",
         target_os = "espidf",
         target_os = "horizon",
         target_os = "freebsd",
@@ -70,51 +124,11 @@ mod imp {
         unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
     }
 
-    #[cfg(target_os = "dragonfly")]
-    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
-        extern "C" {
-            fn getrandom(
-                buf: *mut libc::c_void,
-                buflen: libc::size_t,
-                flags: libc::c_uint,
-            ) -> libc::ssize_t;
-        }
-        unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
-    }
-
-    #[cfg(not(any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "espidf",
-        target_os = "horizon",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "solaris",
-        target_os = "illumos",
-        netbsd10
-    )))]
-    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
-        false
-    }
-
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        target_os = "espidf",
-        target_os = "horizon",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "solaris",
-        target_os = "illumos",
-        netbsd10
-    ))]
-    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
-        use crate::sync::atomic::{AtomicBool, Ordering};
-        use crate::sys::os::errno;
-
+    pub fn syscall(v: &mut [u8]) -> Option<Result<()>> {
         static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
+
         if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
-            return false;
+            return None;
         }
 
         let mut read = 0;
@@ -125,8 +139,7 @@ mod imp {
                 if err == libc::EINTR {
                     continue;
                 } else if err == libc::ENOSYS || err == libc::EPERM {
-                    // Fall back to reading /dev/urandom if `getrandom` is not
-                    // supported on the current kernel.
+                    // `getrandom` is not supported on the current system.
                     //
                     // Also fall back in case it is disabled by something like
                     // seccomp or inside of docker.
@@ -142,123 +155,83 @@ mod imp {
                     //     https://github.com/moby/moby/issues/42680
                     //
                     GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
-                    return false;
+                    return None;
                 } else if err == libc::EAGAIN {
-                    return false;
+                    // getrandom has failed because it would have blocked as the
+                    // non-blocking pool (urandom) has not been initialized in
+                    // the kernel yet due to a lack of entropy. Fallback to
+                    // reading from `/dev/urandom` which will return potentially
+                    // insecure random data to avoid blocking applications which
+                    // could depend on this call without ever knowing they do and
+                    // don't have a work around.
+                    return None;
                 } else {
-                    panic!("unexpected getrandom error: {err}");
+                    return Some(Err(Error::from_raw_os_error(err)));
                 }
             } else {
                 read += result as usize;
             }
         }
-        true
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
-        // meaning it would have blocked because the non-blocking pool (urandom)
-        // has not initialized in the kernel yet due to a lack of entropy. The
-        // fallback we do here is to avoid blocking applications which could
-        // depend on this call without ever knowing they do and don't have a
-        // work around. The PRNG of /dev/urandom will still be used but over a
-        // possibly predictable entropy pool.
-        if getrandom_fill_bytes(v) {
-            return;
-        }
 
-        // getrandom failed because it is permanently or temporarily (because
-        // of missing entropy) unavailable. Open /dev/urandom, read from it,
-        // and close it again.
-        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
-        file.read_exact(v).expect("failed to read /dev/urandom")
+        Some(Ok(()))
     }
 }
 
-#[cfg(target_vendor = "apple")]
+#[cfg(any(
+    target_os = "macos", // Supported since macOS 10.12+.
+    target_os = "openbsd",
+    target_os = "emscripten",
+    target_os = "vita",
+))]
 mod imp {
-    use libc::{c_int, c_void, size_t};
-
-    use crate::io;
-
-    #[inline(always)]
-    fn random_failure() -> ! {
-        panic!("unexpected random generation error: {}", io::Error::last_os_error());
-    }
-
-    #[cfg(target_os = "macos")]
-    fn getentropy_fill_bytes(v: &mut [u8]) {
-        extern "C" {
-            fn getentropy(bytes: *mut c_void, count: size_t) -> c_int;
-        }
+    use crate::io::{Error, Result};
 
+    pub fn syscall(v: &mut [u8]) -> Result<()> {
         // getentropy(2) permits a maximum buffer size of 256 bytes
         for s in v.chunks_mut(256) {
-            let ret = unsafe { getentropy(s.as_mut_ptr().cast(), s.len()) };
+            let ret = unsafe { libc::getentropy(s.as_mut_ptr().cast(), s.len()) };
             if ret == -1 {
-                random_failure()
+                return Err(Error::last_os_error());
             }
         }
-    }
 
-    #[cfg(not(target_os = "macos"))]
-    fn ccrandom_fill_bytes(v: &mut [u8]) {
-        extern "C" {
-            fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
-        }
-
-        let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
-        if ret == -1 {
-            random_failure()
-        }
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        // All supported versions of macOS (10.12+) support getentropy.
-        //
-        // `getentropy` is measurably faster (via Divan) then the other alternatives so its preferred
-        // when usable.
-        #[cfg(target_os = "macos")]
-        getentropy_fill_bytes(v);
-
-        // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
-        // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
-        // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
-        // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
-        // so we only use it on non-Mac OSes where the better entrypoints are blocked.
-        //
-        // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
-        // via `libSystem` (libc) while the other needs to link to `Security.framework`.
-        //
-        // Note that while `getentropy` has a available attribute in the macOS headers, the lack
-        // of a header in the iOS (and others) SDK means that its can cause app store rejections.
-        // Just use `CCRandomGenerateBytes` instead.
-        #[cfg(not(target_os = "macos"))]
-        ccrandom_fill_bytes(v);
+        Ok(())
     }
 }
 
-#[cfg(any(target_os = "openbsd", target_os = "emscripten", target_os = "vita"))]
+// On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
+// call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
+// manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
+// its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
+// so we only use it when `getentropy` is blocked, which appears to be the case
+// on all platforms except macOS (see #102643).
+//
+// `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
+// via `libSystem` (libc) while the other needs to link to `Security.framework`.
+#[cfg(all(target_vendor = "apple", not(target_os = "macos")))]
 mod imp {
-    use crate::sys::os::errno;
+    use libc::size_t;
 
-    pub fn fill_bytes(v: &mut [u8]) {
-        // getentropy(2) permits a maximum buffer size of 256 bytes
-        for s in v.chunks_mut(256) {
-            let ret = unsafe { libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) };
-            if ret == -1 {
-                panic!("unexpected getentropy error: {}", errno());
-            }
+    use crate::ffi::{c_int, c_void};
+    use crate::io::{Error, Result};
+
+    pub fn syscall(v: &mut [u8]) -> Result<()> {
+        extern "C" {
+            fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
         }
+
+        let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
+        if ret != -1 { Ok(()) } else { Err(Error::last_os_error()) }
     }
 }
 
 // FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
 #[cfg(all(target_os = "netbsd", not(netbsd10)))]
 mod imp {
+    use crate::io::{Error, Result};
     use crate::ptr;
 
-    pub fn fill_bytes(v: &mut [u8]) {
+    pub fn syscall(v: &mut [u8]) -> Result<()> {
         let mib = [libc::CTL_KERN, libc::KERN_ARND];
         // kern.arandom permits a maximum buffer size of 256 bytes
         for s in v.chunks_mut(256) {
@@ -273,39 +246,30 @@ mod imp {
                     0,
                 )
             };
-            if ret == -1 || s_len != s.len() {
-                panic!(
-                    "kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
-                    ret,
-                    s.len(),
-                    s_len
-                );
+            if ret == -1 {
+                return Err(Error::last_os_error());
+            } else if s_len != s.len() {
+                // FIXME(joboet): this can't actually happen, can it?
+                panic!("read less bytes than requested from kern.arandom");
             }
         }
+
+        Ok(())
     }
 }
 
 #[cfg(target_os = "fuchsia")]
 mod imp {
+    use crate::io::Result;
+
     #[link(name = "zircon")]
     extern "C" {
         fn zx_cprng_draw(buffer: *mut u8, len: usize);
     }
 
-    pub fn fill_bytes(v: &mut [u8]) {
-        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
-    }
-}
-
-#[cfg(target_os = "redox")]
-mod imp {
-    use crate::fs::File;
-    use crate::io::Read;
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        // Open rand:, read from it, and close it again.
-        let mut file = File::open("rand:").expect("failed to open rand:");
-        file.read_exact(v).expect("failed to read rand:")
+    pub fn syscall(v: &mut [u8]) -> Result<()> {
+        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) };
+        Ok(())
     }
 }
 
@@ -314,25 +278,25 @@ mod imp {
     use core::sync::atomic::AtomicBool;
     use core::sync::atomic::Ordering::Relaxed;
 
-    use crate::io;
+    use crate::io::{Error, Result};
 
-    pub fn fill_bytes(v: &mut [u8]) {
+    pub fn syscall(v: &mut [u8]) -> Result<()> {
         static RNG_INIT: AtomicBool = AtomicBool::new(false);
         while !RNG_INIT.load(Relaxed) {
             let ret = unsafe { libc::randSecure() };
             if ret < 0 {
-                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
+                return Err(Error::last_os_error());
             } else if ret > 0 {
                 RNG_INIT.store(true, Relaxed);
                 break;
             }
+
             unsafe { libc::usleep(10) };
         }
+
         let ret = unsafe {
             libc::randABytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
         };
-        if ret < 0 {
-            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-        }
+        if ret >= 0 { Ok(()) } else { Err(Error::last_os_error()) }
     }
 }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 59720f77465..88b31cd78a6 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -434,25 +434,24 @@ impl Builder {
     ///
     /// [`io::Result`]: crate::io::Result
     #[unstable(feature = "thread_spawn_unchecked", issue = "55132")]
-    pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>>
+    pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
     where
         F: FnOnce() -> T,
-        F: Send + 'a,
-        T: Send + 'a,
+        F: Send,
+        T: Send,
     {
         Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?))
     }
 
-    unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
+    unsafe fn spawn_unchecked_<'scope, F, T>(
         self,
         f: F,
         scope_data: Option<Arc<scoped::ScopeData>>,
     ) -> io::Result<JoinInner<'scope, T>>
     where
         F: FnOnce() -> T,
-        F: Send + 'a,
-        T: Send + 'a,
-        'scope: 'a,
+        F: Send,
+        T: Send,
     {
         let Builder { name, stack_size } = self;
 
@@ -532,7 +531,7 @@ impl Builder {
             // will call `decrement_num_running_threads` and therefore signal that this thread is
             // done.
             drop(their_packet);
-            // Here, the lifetime `'a` and even `'scope` can end. `main` keeps running for a bit
+            // Here, the lifetime `'scope` can end. `main` keeps running for a bit
             // after that before returning itself.
         };
 
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 49310367182..f608e5d715e 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -121,7 +121,7 @@ fn clean(build: &Build, all: bool, stage: Option<u32>) {
 
 fn clean_specific_stage(build: &Build, stage: u32) {
     for host in &build.hosts {
-        let entries = match build.out.join(host.triple).read_dir() {
+        let entries = match build.out.join(host).read_dir() {
             Ok(iter) => iter,
             Err(_) => continue,
         };
@@ -148,7 +148,7 @@ fn clean_default(build: &Build) {
     rm_rf(&build.out.join("bootstrap-shims-dump"));
     rm_rf(&build.out.join("rustfmt.stamp"));
 
-    let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t.triple)).collect();
+    let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect();
     // After cross-compilation, artifacts of the host architecture (which may differ from build.host)
     // might not get removed.
     // Adding its path (linked one for easier accessibility) will solve this problem.
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index c09180e542f..4353cfadd8d 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -246,7 +246,7 @@ impl Step for Std {
                 .rustc_snapshot_sysroot()
                 .join("lib")
                 .join("rustlib")
-                .join(compiler.host.triple)
+                .join(compiler.host)
                 .join("bin");
             if src_sysroot_bin.exists() {
                 let target_sysroot_bin =
@@ -432,7 +432,7 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
-    } else if target.ends_with("windows-gnu") {
+    } else if target.is_windows_gnu() {
         for obj in ["crt2.o", "dllcrt2.o"].iter() {
             let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
             let target = libdir_self_contained.join(obj);
@@ -651,8 +651,8 @@ impl Step for StdLink {
                 compiler: self.compiler,
                 force_recompile: self.force_recompile,
             });
-            let libdir = sysroot.join(lib).join("rustlib").join(target.triple).join("lib");
-            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host.triple).join("lib");
+            let libdir = sysroot.join(lib).join("rustlib").join(target).join("lib");
+            let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host).join("lib");
             (libdir, hostdir)
         } else {
             let libdir = builder.sysroot_libdir(target_compiler, target);
@@ -670,12 +670,12 @@ impl Step for StdLink {
                 .build
                 .config
                 .initial_rustc
-                .starts_with(builder.out.join(compiler.host.triple).join("stage0/bin"))
+                .starts_with(builder.out.join(compiler.host).join("stage0/bin"))
         {
             // Copy bin files from stage0/bin to stage0-sysroot/bin
-            let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");
+            let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");
 
-            let host = compiler.host.triple;
+            let host = compiler.host;
             let stage0_bin_dir = builder.out.join(host).join("stage0/bin");
             let sysroot_bin_dir = sysroot.join("bin");
             t!(fs::create_dir_all(&sysroot_bin_dir));
@@ -793,7 +793,7 @@ impl Step for StartupObjects {
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
-        if !target.ends_with("windows-gnu") {
+        if !target.is_windows_gnu() {
             return vec![];
         }
 
@@ -1554,7 +1554,7 @@ impl Step for Sysroot {
     /// For all other stages, it's the same stage directory that the compiler lives in.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
-        let host_dir = builder.out.join(compiler.host.triple);
+        let host_dir = builder.out.join(compiler.host);
 
         let sysroot_dir = |stage| {
             if stage == 0 {
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 43306eab1b1..530eb9b446a 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -275,12 +275,8 @@ fn make_win_dist(
     }
 
     //Copy platform tools to platform-specific bin directory
-    let target_bin_dir = plat_root
-        .join("lib")
-        .join("rustlib")
-        .join(target.triple)
-        .join("bin")
-        .join("self-contained");
+    let target_bin_dir =
+        plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained");
     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
     for src in target_tools {
         builder.copy_link_to_folder(&src, &target_bin_dir);
@@ -295,12 +291,8 @@ fn make_win_dist(
     );
 
     //Copy platform libs to platform-specific lib directory
-    let target_lib_dir = plat_root
-        .join("lib")
-        .join("rustlib")
-        .join(target.triple)
-        .join("lib")
-        .join("self-contained");
+    let target_lib_dir =
+        plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained");
     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
     for src in target_libs {
         builder.copy_link_to_folder(&src, &target_lib_dir);
@@ -450,7 +442,7 @@ impl Step for Rustc {
             // component for now.
             maybe_install_llvm_runtime(builder, host, image);
 
-            let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
+            let dst_dir = image.join("lib/rustlib").join(host).join("bin");
             t!(fs::create_dir_all(&dst_dir));
 
             // Copy over lld if it's there
@@ -607,7 +599,7 @@ fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp
 
 /// Copy stamped files into an image's `target/lib` directory.
 fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
-    let dst = image.join("lib/rustlib").join(target.triple).join("lib");
+    let dst = image.join("lib/rustlib").join(target).join("lib");
     let self_contained_dst = dst.join("self-contained");
     t!(fs::create_dir_all(&dst));
     t!(fs::create_dir_all(&self_contained_dst));
@@ -769,7 +761,7 @@ impl Step for Analysis {
 
         let src = builder
             .stage_out(compiler, Mode::Std)
-            .join(target.triple)
+            .join(target)
             .join(builder.cargo_dir())
             .join("deps")
             .join("save-analysis");
@@ -1509,7 +1501,7 @@ impl Step for Extended {
         tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) }));
         tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std"));
 
-        if target.ends_with("windows-gnu") {
+        if target.is_windows_gnu() {
             tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw"));
         }
 
@@ -1683,7 +1675,7 @@ impl Step for Extended {
                     prepare(tool);
                 }
             }
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 prepare("rust-mingw");
             }
 
@@ -1830,7 +1822,7 @@ impl Step for Extended {
                 .arg("-t")
                 .arg(etc.join("msi/remove-duplicates.xsl"))
                 .run(builder);
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
@@ -1876,7 +1868,7 @@ impl Step for Extended {
                 if built_tools.contains("miri") {
                     cmd.arg("-dMiriDir=miri");
                 }
-                if target.ends_with("windows-gnu") {
+                if target.is_windows_gnu() {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
                 cmd.run(builder);
@@ -1901,7 +1893,7 @@ impl Step for Extended {
             }
             candle("AnalysisGroup.wxs".as_ref());
 
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 candle("GccGroup.wxs".as_ref());
             }
 
@@ -1941,7 +1933,7 @@ impl Step for Extended {
                 cmd.arg("DocsGroup.wixobj");
             }
 
-            if target.ends_with("windows-gnu") {
+            if target.is_windows_gnu() {
                 cmd.arg("GccGroup.wixobj");
             }
             // ICE57 wrongly complains about the shortcuts
@@ -1973,7 +1965,7 @@ fn add_env(builder: &Builder<'_>, cmd: &mut BootstrapCommand, target: TargetSele
 
     if target.contains("windows-gnullvm") {
         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
-    } else if target.contains("windows-gnu") {
+    } else if target.is_windows_gnu() {
         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
     } else {
         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
@@ -2087,7 +2079,7 @@ fn maybe_install_llvm(
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
+    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
     // We do not need to copy LLVM files into the sysroot if it is not
     // dynamically linked; it is already included into librustc_llvm
     // statically.
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 2cd5db706c2..301633559fe 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -699,13 +699,12 @@ fn doc_std(
     let compiler = builder.compiler(stage, builder.config.build);
 
     let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" };
-    let target_dir =
-        builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name);
+    let target_dir = builder.stage_out(compiler, Mode::Std).join(target).join(target_doc_dir_name);
 
     // This is directory where the compiler will place the output of the command.
     // We will then copy the files from this directory into the final `out` directory, the specified
     // as a function parameter.
-    let out_dir = target_dir.join(target.triple).join("doc");
+    let out_dir = target_dir.join(target).join("doc");
 
     let mut cargo =
         builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, Kind::Doc);
@@ -846,7 +845,7 @@ impl Step for Rustc {
 
         let mut to_open = None;
 
-        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
         for krate in &*self.crates {
             // Create all crate output directories first to make sure rustdoc uses
             // relative links.
@@ -992,7 +991,7 @@ macro_rules! tool_doc {
                 // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
                 // cargo.rustdocflag("--generate-link-to-definition");
 
-                let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
+                let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc");
                 $(for krate in $crates {
                     let dir_name = krate.replace("-", "_");
                     t!(fs::create_dir_all(out_dir.join(&*dir_name)));
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 6ed001d8fd5..cc01afd4c18 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -149,7 +149,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         let _guard =
             builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
         let _time = helpers::timeit(builder);
-        linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc")).run(builder);
+        linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -435,7 +435,7 @@ impl Miri {
         compiler: Compiler,
         target: TargetSelection,
     ) -> PathBuf {
-        let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
+        let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");
         let mut cargo = builder::Cargo::new(
             builder,
             compiler,
@@ -1115,7 +1115,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
 }
 
 fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
-    builder.out.join(host.triple).join("test")
+    builder.out.join(host).join("test")
 }
 
 macro_rules! default_test {
@@ -1817,7 +1817,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
-        flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
+        flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
 
         if suite != "mir-opt" {
             if let Some(linker) = builder.linker(target) {
@@ -2685,7 +2685,7 @@ impl Step for Crate {
                     if builder.download_rustc() && compiler.stage > 0 {
                         let sysroot = builder
                             .out
-                            .join(compiler.host.triple)
+                            .join(compiler.host)
                             .join(format!("stage{}-test-sysroot", compiler.stage));
                         cargo.env("RUSTC_SYSROOT", sysroot);
                     }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index ccdeb442af4..454cc20d155 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1171,7 +1171,7 @@ impl<'a> Builder<'a> {
                     .sysroot(self.compiler)
                     .join(lib)
                     .join("rustlib")
-                    .join(self.target.triple)
+                    .join(self.target)
                     .join("lib");
                 // Avoid deleting the rustlib/ directory we just copied
                 // (in `impl Step for Sysroot`).
@@ -1254,7 +1254,7 @@ impl<'a> Builder<'a> {
 
         // Ensure that the downloaded LLVM libraries can be found.
         if self.config.llvm_from_ci {
-            let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+            let ci_llvm_lib = self.out.join(compiler.host).join("ci-llvm").join("lib");
             dylib_dirs.push(ci_llvm_lib);
         }
 
@@ -1504,9 +1504,9 @@ impl<'a> Builder<'a> {
                 Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
                 Mode::Std => {
                     if self.config.cmd.json() {
-                        out_dir.join(target.triple).join("json-doc")
+                        out_dir.join(target).join("json-doc")
                     } else {
-                        out_dir.join(target.triple).join("doc")
+                        out_dir.join(target).join("doc")
                     }
                 }
                 _ => panic!("doc mode {mode:?} not expected"),
@@ -2226,11 +2226,6 @@ impl<'a> Builder<'a> {
             rustdocflags.arg("--cfg=parallel_compiler");
         }
 
-        // Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything.
-        self.config.cmd.rustc_args().iter().for_each(|v| {
-            rustflags.arg(v);
-        });
-
         Cargo {
             command: cargo,
             compiler,
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index e06df65c1bc..c554684d5a7 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -633,7 +633,7 @@ mod dist {
         config.paths = vec!["library/std".into()];
         config.cmd = Subcommand::Test {
             test_args: vec![],
-            rustc_args: vec![],
+            compiletest_rustc_args: vec![],
             no_fail_fast: false,
             no_doc: true,
             doc: false,
@@ -704,7 +704,7 @@ mod dist {
         let mut config = configure(&["A-A"], &["A-A"]);
         config.cmd = Subcommand::Test {
             test_args: vec![],
-            rustc_args: vec![],
+            compiletest_rustc_args: vec![],
             no_fail_fast: false,
             doc: true,
             no_doc: false,
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 35ee4a29c68..36de8324f67 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -514,6 +514,10 @@ impl TargetSelection {
         self.contains("windows")
     }
 
+    pub fn is_windows_gnu(&self) -> bool {
+        self.ends_with("windows-gnu")
+    }
+
     /// Path to the file defining the custom target, if any.
     pub fn filepath(&self) -> Option<&Path> {
         self.file.as_ref().map(Path::new)
@@ -542,6 +546,14 @@ impl PartialEq<&str> for TargetSelection {
     }
 }
 
+// Targets are often used as directory names throughout bootstrap.
+// This impl makes it more ergonomics to use them as such.
+impl AsRef<Path> for TargetSelection {
+    fn as_ref(&self) -> &Path {
+        self.triple.as_ref()
+    }
+}
+
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Debug, Default, Clone, PartialEq, Eq)]
 pub struct Target {
@@ -1469,7 +1481,7 @@ impl Config {
             config.download_beta_toolchain();
             config
                 .out
-                .join(config.build.triple)
+                .join(config.build)
                 .join("stage0")
                 .join("bin")
                 .join(exe("rustc", config.build))
@@ -1484,7 +1496,7 @@ impl Config {
             config.download_beta_toolchain();
             config
                 .out
-                .join(config.build.triple)
+                .join(config.build)
                 .join("stage0")
                 .join("bin")
                 .join(exe("cargo", config.build))
@@ -2277,13 +2289,13 @@ impl Config {
     /// The absolute path to the downloaded LLVM artifacts.
     pub(crate) fn ci_llvm_root(&self) -> PathBuf {
         assert!(self.llvm_from_ci);
-        self.out.join(&*self.build.triple).join("ci-llvm")
+        self.out.join(self.build).join("ci-llvm")
     }
 
     /// Directory where the extracted `rustc-dev` component is stored.
     pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
         assert!(self.download_rustc());
-        self.out.join(self.build.triple).join("ci-rustc")
+        self.out.join(self.build).join("ci-rustc")
     }
 
     /// Determine whether llvm should be linked dynamically.
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 3948fe0d98c..c3f17402814 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -357,9 +357,9 @@ pub enum Subcommand {
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
         test_args: Vec<String>,
-        /// extra options to pass the compiler when running tests
+        /// extra options to pass the compiler when running compiletest tests
         #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
-        rustc_args: Vec<String>,
+        compiletest_rustc_args: Vec<String>,
         #[arg(long)]
         /// do not run doc tests
         no_doc: bool,
@@ -402,9 +402,6 @@ pub enum Subcommand {
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
         test_args: Vec<String>,
-        /// extra options to pass the compiler when running tests
-        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
-        rustc_args: Vec<String>,
         #[arg(long)]
         /// do not run doc tests
         no_doc: bool,
@@ -509,10 +506,10 @@ impl Subcommand {
         }
     }
 
-    pub fn rustc_args(&self) -> Vec<&str> {
+    pub fn compiletest_rustc_args(&self) -> Vec<&str> {
         match *self {
-            Subcommand::Test { ref rustc_args, .. } | Subcommand::Miri { ref rustc_args, .. } => {
-                rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
+            Subcommand::Test { ref compiletest_rustc_args, .. } => {
+                compiletest_rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
             }
             _ => vec![],
         }
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 4d1aea3cd95..8131666fcb2 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -379,7 +379,7 @@ impl Config {
         let version = &self.stage0_metadata.compiler.version;
         let host = self.build;
 
-        let bin_root = self.out.join(host.triple).join("stage0");
+        let bin_root = self.out.join(host).join("stage0");
         let clippy_stamp = bin_root.join(".clippy-stamp");
         let cargo_clippy = bin_root.join("bin").join(exe("cargo-clippy", host));
         if cargo_clippy.exists() && !program_out_of_date(&clippy_stamp, date) {
@@ -412,7 +412,7 @@ impl Config {
         let channel = format!("{version}-{date}");
 
         let host = self.build;
-        let bin_root = self.out.join(host.triple).join("rustfmt");
+        let bin_root = self.out.join(host).join("rustfmt");
         let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
         if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
@@ -519,7 +519,7 @@ impl Config {
         extra_components: &[&str],
         download_component: fn(&Config, String, &str, &str),
     ) {
-        let host = self.build.triple;
+        let host = self.build;
         let bin_root = self.out.join(host).join(sysroot);
         let rustc_stamp = bin_root.join(".rustc-stamp");
 
@@ -592,7 +592,7 @@ impl Config {
             t!(fs::create_dir_all(&cache_dir));
         }
 
-        let bin_root = self.out.join(self.build.triple).join(destination);
+        let bin_root = self.out.join(self.build).join(destination);
         let tarball = cache_dir.join(&filename);
         let (base_url, url, should_verify) = match mode {
             DownloadSource::CI => {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index e8a61ab4cf5..bfd0e42acfd 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -452,7 +452,7 @@ impl Build {
         }
 
         // Make a symbolic link so we can use a consistent directory in the documentation.
-        let build_triple = build.out.join(build.build.triple);
+        let build_triple = build.out.join(build.build);
         t!(fs::create_dir_all(&build_triple));
         let host = build.out.join("host");
         if host.is_symlink() {
@@ -807,10 +807,7 @@ impl Build {
     }
 
     fn tools_dir(&self, compiler: Compiler) -> PathBuf {
-        let out = self
-            .out
-            .join(&*compiler.host.triple)
-            .join(format!("stage{}-tools-bin", compiler.stage));
+        let out = self.out.join(compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
         t!(fs::create_dir_all(&out));
         out
     }
@@ -827,14 +824,14 @@ impl Build {
             Mode::ToolBootstrap => "-bootstrap-tools",
             Mode::ToolStd | Mode::ToolRustc => "-tools",
         };
-        self.out.join(&*compiler.host.triple).join(format!("stage{}{}", compiler.stage, suffix))
+        self.out.join(compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular compiler, whether or not we're building the
     /// standard library, and targeting the specified architecture.
     fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
-        self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
+        self.stage_out(compiler, mode).join(target).join(self.cargo_dir())
     }
 
     /// Root output directory of LLVM for `target`
@@ -845,36 +842,36 @@ impl Build {
         if self.config.llvm_from_ci && self.config.build == target {
             self.config.ci_llvm_root()
         } else {
-            self.out.join(&*target.triple).join("llvm")
+            self.out.join(target).join("llvm")
         }
     }
 
     fn lld_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("lld")
+        self.out.join(target).join("lld")
     }
 
     /// Output directory for all documentation for a target
     fn doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("doc")
+        self.out.join(target).join("doc")
     }
 
     /// Output directory for all JSON-formatted documentation for a target
     fn json_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("json-doc")
+        self.out.join(target).join("json-doc")
     }
 
     fn test_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("test")
+        self.out.join(target).join("test")
     }
 
     /// Output directory for all documentation for a target
     fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("compiler-doc")
+        self.out.join(target).join("compiler-doc")
     }
 
     /// Output directory for some generated md crate documentation for a target (temporary)
     fn md_doc_out(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("md-doc")
+        self.out.join(target).join("md-doc")
     }
 
     /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
@@ -954,7 +951,7 @@ impl Build {
 
     /// Directory for libraries built from C/C++ code and shared between stages.
     fn native_dir(&self, target: TargetSelection) -> PathBuf {
-        self.out.join(&*target.triple).join("native")
+        self.out.join(target).join("native")
     }
 
     /// Root output directory for rust_test_helpers library compiled for
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 84dac25188e..c629f04c00e 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -225,4 +225,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "New option `llvm.libzstd` to control whether llvm is built with zstd support.",
     },
+    ChangeInfo {
+        change_id: 128841,
+        severity: ChangeSeverity::Warning,
+        summary: "./x test --rustc-args was renamed to --compiletest-rustc-args as it only applies there. ./x miri --rustc-args was also removed.",
+    },
 ];
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
index b3921f11421..98290f5a72c 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
@@ -18,9 +18,9 @@ if [[ -z "${PR_CI_JOB}" ]]; then
     # compiler, and is sensitive to the addition of new flags.
     ../x.py --stage 1 test tests/ui-fulldeps
 
-    # The tests are run a second time with the size optimizations enabled.
-    ../x.py --stage 1 test library/std library/alloc library/core \
-        --rustc-args "--cfg feature=\"optimize_for_size\""
+    # Rebuild the stdlib with the size optimizations enabled and run tests again.
+    RUSTFLAGS_NOT_BOOTSTRAP="--cfg feature=\"optimize_for_size\"" ../x.py --stage 1 test \
+        library/std library/alloc library/core
 fi
 
 # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 805fc8aa8cc..297dc11cd61 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -266,7 +266,7 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
-complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
+complete -c x.py -n "__fish_seen_subcommand_from test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
@@ -313,7 +313,6 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l enable-bolt-settings -
 complete -c x.py -n "__fish_seen_subcommand_from test" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
-complete -c x.py -n "__fish_seen_subcommand_from miri" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
 complete -c x.py -n "__fish_seen_subcommand_from miri" -l build -d 'build target of the stage0 compiler' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index ce590d2fa48..4b424471a26 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -338,7 +338,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         }
         'x.py;test' {
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
-            [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
+            [CompletionResult]::new('--compiletest-rustc-args', 'compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests')
             [CompletionResult]::new('--extra-checks', 'extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
             [CompletionResult]::new('--compare-mode', 'compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', 'pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
@@ -392,7 +392,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         }
         'x.py;miri' {
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
-            [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
             [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`')
             [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index a4234905476..60ba8d3ba70 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -1300,7 +1300,7 @@ _x.py() {
             return 0
             ;;
         x.py__miri)
-            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1310,10 +1310,6 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --rustc-args)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
                 --config)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -1862,7 +1858,7 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -1872,7 +1868,7 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
-                --rustc-args)
+                --compiletest-rustc-args)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index fc8be4f7881..688f692da24 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -337,7 +337,7 @@ _arguments "${_arguments_options[@]}" \
 (test)
 _arguments "${_arguments_options[@]}" \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
-'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
+'*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS: ' \
 '--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE: ' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run: ' \
@@ -393,7 +393,6 @@ _arguments "${_arguments_options[@]}" \
 (miri)
 _arguments "${_arguments_options[@]}" \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
-'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \
 '--build=[build target of the stage0 compiler]:BUILD:( )' \
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 2b3ae6df5de..966d38508f6 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -56,6 +56,7 @@ extern crate either;
 extern crate tracing;
 
 // The rustc crates we need
+extern crate rustc_attr;
 extern crate rustc_apfloat;
 extern crate rustc_ast;
 extern crate rustc_const_eval;
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 94598e7d2e3..754f8cf1381 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -11,6 +11,7 @@ use rand::rngs::StdRng;
 use rand::Rng;
 use rand::SeedableRng;
 
+use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
 use rustc_data_structures::static_assert_size;
@@ -23,6 +24,7 @@ use rustc_middle::{
         Instance, Ty, TyCtxt,
     },
 };
+use rustc_session::config::InliningThreshold;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::{Span, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
@@ -47,10 +49,10 @@ pub const SIGRTMIN: i32 = 34;
 /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
 pub const SIGRTMAX: i32 = 42;
 
-/// Each const has multiple addresses, but only this many. Since const allocations are never
-/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would
-/// produce unbounded memory usage.
-const ADDRS_PER_CONST: usize = 16;
+/// Each anonymous global (constant, vtable, function pointer, ...) has multiple addresses, but only
+/// this many. Since const allocations are never deallocated, choosing a new [`AllocId`] and thus
+/// base address for each evaluation would produce unbounded memory usage.
+const ADDRS_PER_ANON_GLOBAL: usize = 32;
 
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
@@ -1372,7 +1374,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             catch_unwind: None,
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
-            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_CONST,
+            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL,
         };
 
         Ok(frame.with_extra(extra))
@@ -1518,4 +1520,45 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             Entry::Occupied(oe) => Ok(oe.get().clone()),
         }
     }
+
+    fn get_global_alloc_salt(
+        ecx: &InterpCx<'tcx, Self>,
+        instance: Option<ty::Instance<'tcx>>,
+    ) -> usize {
+        let unique = if let Some(instance) = instance {
+            // Functions cannot be identified by pointers, as asm-equal functions can get
+            // deduplicated by the linker (we set the "unnamed_addr" attribute for LLVM) and
+            // functions can be duplicated across crates. We thus generate a new `AllocId` for every
+            // mention of a function. This means that `main as fn() == main as fn()` is false, while
+            // `let x = main as fn(); x == x` is true. However, as a quality-of-life feature it can
+            // be useful to identify certain functions uniquely, e.g. for backtraces. So we identify
+            // whether codegen will actually emit duplicate functions. It does that when they have
+            // non-lifetime generics, or when they can be inlined. All other functions are given a
+            // unique address. This is not a stable guarantee! The `inline` attribute is a hint and
+            // cannot be relied upon for anything. But if we don't do this, the
+            // `__rust_begin_short_backtrace`/`__rust_end_short_backtrace` logic breaks and panic
+            // backtraces look terrible.
+            let is_generic = instance
+                .args
+                .into_iter()
+                .any(|kind| !matches!(kind.unpack(), ty::GenericArgKind::Lifetime(_)));
+            let can_be_inlined = matches!(
+                ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
+                InliningThreshold::Always
+            ) || !matches!(
+                ecx.tcx.codegen_fn_attrs(instance.def_id()).inline,
+                InlineAttr::Never
+            );
+            !is_generic && !can_be_inlined
+        } else {
+            // Non-functions are never unique.
+            false
+        };
+        // Always use the same salt if the allocation is unique.
+        if unique {
+            CTFE_ALLOC_SALT
+        } else {
+            ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL
+        }
+    }
 }
diff --git a/src/tools/miri/tests/pass/dyn-traits.rs b/src/tools/miri/tests/pass/dyn-traits.rs
index 908d521a0d8..f6220120968 100644
--- a/src/tools/miri/tests/pass/dyn-traits.rs
+++ b/src/tools/miri/tests/pass/dyn-traits.rs
@@ -141,7 +141,17 @@ fn unsized_dyn_autoderef() {
 }
 */
 
+fn vtable_ptr_eq() {
+    use std::{fmt, ptr};
+
+    // We don't always get the same vtable when casting this to a wide pointer.
+    let x = &2;
+    let x_wide = x as &dyn fmt::Display;
+    assert!((0..256).any(|_| !ptr::eq(x as &dyn fmt::Display, x_wide)));
+}
+
 fn main() {
     ref_box_dyn();
     box_box_trait();
+    vtable_ptr_eq();
 }
diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs
index 2aa3ebf2dd0..a5c4bc5e0d9 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -82,7 +82,8 @@ fn main() {
     assert!(return_fn_ptr(i) == i);
     assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
     // Miri gives different addresses to different reifications of a generic function.
-    assert!(return_fn_ptr(f) != f);
+    // at least if we try often enough.
+    assert!((0..256).any(|_| return_fn_ptr(f) != f));
     // However, if we only turn `f` into a function pointer and use that pointer,
     // it is equal to itself.
     let f2 = f as fn() -> i32;
diff --git a/src/tools/miri/tests/pass/rc.rs b/src/tools/miri/tests/pass/rc.rs
index 6dd1b3aff9e..b1470dabc26 100644
--- a/src/tools/miri/tests/pass/rc.rs
+++ b/src/tools/miri/tests/pass/rc.rs
@@ -75,7 +75,8 @@ fn rc_fat_ptr_eq() {
     let p = Rc::new(1) as Rc<dyn Debug>;
     let a: *const dyn Debug = &*p;
     let r = Rc::into_raw(p);
-    assert!(a == r);
+    // Only compare the pointer parts, as the vtable might differ.
+    assert!(a as *const () == r as *const ());
     drop(unsafe { Rc::from_raw(r) });
 }
 
diff --git a/tests/assembly/powerpc64-struct-abi.rs b/tests/assembly/powerpc64-struct-abi.rs
new file mode 100644
index 00000000000..9a3540d8b41
--- /dev/null
+++ b/tests/assembly/powerpc64-struct-abi.rs
@@ -0,0 +1,132 @@
+//@ revisions: elfv1-be elfv2-be elfv2-le
+//@ assembly-output: emit-asm
+//@ compile-flags: -O
+//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[elfv1-be] needs-llvm-components: powerpc
+//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl
+//@[elfv2-be] needs-llvm-components: powerpc
+//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu
+//@[elfv2-le] needs-llvm-components: powerpc
+//@[elfv1-be] filecheck-flags: --check-prefix be
+//@[elfv2-be] filecheck-flags: --check-prefix be
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "freeze"]
+trait Freeze {}
+
+#[lang = "unpin"]
+trait Unpin {}
+
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for FiveU32s {}
+impl Copy for FiveU16s {}
+impl Copy for ThreeU8s {}
+
+#[repr(C)]
+struct FiveU32s(u32, u32, u32, u32, u32);
+
+#[repr(C)]
+struct FiveU16s(u16, u16, u16, u16, u16);
+
+#[repr(C)]
+struct ThreeU8s(u8, u8, u8);
+
+// CHECK-LABEL: read_large
+// be: lwz [[REG1:.*]], 16(4)
+// be-NEXT: stw [[REG1]], 16(3)
+// be-NEXT: ld [[REG2:.*]], 8(4)
+// be-NEXT: ld [[REG3:.*]], 0(4)
+// be-NEXT: std [[REG2]], 8(3)
+// be-NEXT: std [[REG3]], 0(3)
+// elfv2-le: lxvd2x [[REG1:.*]], 0, 4
+// elfv2-le-NEXT: lwz [[REG2:.*]], 16(4)
+// elfv2-le-NEXT: stw [[REG2]], 16(3)
+// elfv2-le-NEXT: stxvd2x [[REG1]], 0, 3
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn read_large(x: &FiveU32s) -> FiveU32s {
+    *x
+}
+
+// CHECK-LABEL: read_medium
+// elfv1-be: lhz [[REG1:.*]], 8(4)
+// elfv1-be-NEXT: ld [[REG2:.*]], 0(4)
+// elfv1-be-NEXT: sth [[REG1]], 8(3)
+// elfv1-be-NEXT: std [[REG2]], 0(3)
+// elfv2-be: lhz [[REG1:.*]], 8(3)
+// elfv2-be-NEXT: ld 3, 0(3)
+// elfv2-be-NEXT: sldi 4, [[REG1]], 48
+// elfv2-le: ld [[REG1:.*]], 0(3)
+// elfv2-le-NEXT: lhz 4, 8(3)
+// elfv2-le-NEXT: mr 3, [[REG1]]
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn read_medium(x: &FiveU16s) -> FiveU16s {
+    *x
+}
+
+// CHECK-LABEL: read_small
+// elfv1-be: lbz [[REG1:.*]], 2(4)
+// elfv1-be-NEXT: lhz [[REG2:.*]], 0(4)
+// elfv1-be-NEXT: stb [[REG1]], 2(3)
+// elfv1-be-NEXT: sth [[REG2]], 0(3)
+// elfv2-be: lhz [[REG1:.*]], 0(3)
+// elfv2-be-NEXT: lbz 3, 2(3)
+// elfv2-be-NEXT: rldimi 3, [[REG1]], 8, 0
+// elfv2-le: lbz [[REG1:.*]], 2(3)
+// elfv2-le-NEXT: lhz 3, 0(3)
+// elfv2-le-NEXT: rldimi 3, [[REG1]], 16, 0
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn read_small(x: &ThreeU8s) -> ThreeU8s {
+    *x
+}
+
+// CHECK-LABEL: write_large
+// CHECK: std 3, 0(6)
+// be-NEXT: rldicl [[REG1:.*]], 5, 32, 32
+// CHECK-NEXT: std 4, 8(6)
+// be-NEXT: stw [[REG1]], 16(6)
+// elfv2-le-NEXT: stw 5, 16(6)
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn write_large(x: FiveU32s, dest: &mut FiveU32s) {
+    *dest = x;
+}
+
+// CHECK-LABEL: write_medium
+// CHECK: std 3, 0(5)
+// be-NEXT: rldicl [[REG1:.*]], 4, 16, 48
+// be-NEXT: sth [[REG1]], 8(5)
+// elfv2-le-NEXT: sth 4, 8(5)
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn write_medium(x: FiveU16s, dest: &mut FiveU16s) {
+    *dest = x;
+}
+
+// CHECK-LABEL: write_small
+// be: stb 3, 2(4)
+// be-NEXT: srwi [[REG1:.*]], 3, 8
+// be-NEXT: sth [[REG1]], 0(4)
+// The order these instructions are emitted in changed in LLVM 18.
+// elfv2-le-DAG: sth 3, 0(4)
+// elfv2-le-DAG: srwi [[REG1:.*]], 3, 16
+// elfv2-le-NEXT: stb [[REG1]], 2(4)
+// CHECK-NEXT: blr
+#[no_mangle]
+extern "C" fn write_small(x: ThreeU8s, dest: &mut ThreeU8s) {
+    *dest = x;
+}
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index 25f17f9c38a..27c85cc8ce4 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -436,17 +436,27 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
                ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
            }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-bytes.rs:196:62
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:196:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ 00 00 00 00                         │ ╾──╼....
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-bytes.rs:199:65
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:199:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC32 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼                         │ ╾──╼╾──╼
+           }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:204:1
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 0fb9694895d..2b0ce99a881 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -436,17 +436,27 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
                ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
            }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-bytes.rs:196:62
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:196:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/raw-bytes.rs:199:65
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/raw-bytes.rs:199:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC32 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼
+           }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/raw-bytes.rs:204:1
diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs
index de1a81b0024..0df732df30e 100644
--- a/tests/ui/consts/const-eval/raw-bytes.rs
+++ b/tests/ui/consts/const-eval/raw-bytes.rs
@@ -194,10 +194,10 @@ const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool
 //~| expected a boolean
 
 const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| null pointer
 const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| vtable
 
 // Uninhabited types
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
index 439ccb24e61..5c47cbfdf3b 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
@@ -1,46 +1,56 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-incorrect-vtable.rs:19:14
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:18:1
+   |
+LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer
    |
-LL |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC8 as vtable pointer but it does not point to a vtable
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼                         │ ╾──╼╾──╼
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-incorrect-vtable.rs:24:14
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:23:1
+   |
+LL | const INVALID_VTABLE_SIZE: &dyn Trait =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer
    |
-LL |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC9 as vtable pointer but it does not point to a vtable
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼                         │ ╾──╼╾──╼
+           }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC1<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼                         │ ╾──╼╾──╼
+               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC3<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼                         │ ╾──╼╾──╼
+               ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:44:1
    |
 LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼                         │ ╾──╼╾──╼
+               ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼                         │ ╾──╼╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -51,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
-               ╾ALLOC6<imm>╼ ╾ALLOC7╼                         │ ╾──╼╾──╼
+               ╾ALLOC10<imm>╼ ╾ALLOC11╼                         │ ╾──╼╾──╼
            }
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
index 89bf959703a..f400073aca2 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
@@ -1,46 +1,56 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-incorrect-vtable.rs:19:14
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:18:1
+   |
+LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer
    |
-LL |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC8 as vtable pointer but it does not point to a vtable
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-incorrect-vtable.rs:24:14
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:23:1
+   |
+LL | const INVALID_VTABLE_SIZE: &dyn Trait =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer
    |
-LL |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC9 as vtable pointer but it does not point to a vtable
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼
+           }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:33:1
    |
 LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC1<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼
+               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:38:1
    |
 LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC3<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼
+               ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-incorrect-vtable.rs:44:1
    |
 LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼
+               ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
@@ -51,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
-               ╾ALLOC6<imm>╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼
+               ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼
            }
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
index 4325495a380..8058f7693a7 100644
--- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
+++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs
@@ -17,12 +17,12 @@ trait Trait {}
 
 const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
-//~^ ERROR evaluation of constant value failed
+//~^^ ERROR it is undefined behavior to use this value
 //~| vtable
 
 const INVALID_VTABLE_SIZE: &dyn Trait =
     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
-//~^ ERROR evaluation of constant value failed
+//~^^ ERROR it is undefined behavior to use this value
 //~| vtable
 
 #[repr(transparent)]
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs
index 3956146f6ae..991d4424dcf 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs
@@ -123,13 +123,13 @@ const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4u
 //~^ ERROR it is undefined behavior to use this value
 //~| vtable
 const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| vtable
 const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| vtable
 const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| vtable
 const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
 //~^ ERROR it is undefined behavior to use this value
@@ -142,10 +142,10 @@ const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool
 
 // # raw trait object
 const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| null pointer
 const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-//~^ ERROR evaluation of constant value failed
+//~^ ERROR it is undefined behavior to use this value
 //~| vtable
 const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw
 // Officially blessed way to get the vtable
@@ -154,12 +154,12 @@ const DYN_METADATA: ptr::DynMetadata<dyn Send> = ptr::metadata::<dyn Send>(ptr::
 
 static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-    //~^ ERROR could not evaluate static initializer
+    //~^^ ERROR it is undefined behavior to use this value
     //~| null pointer
 };
 static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-    //~^ ERROR could not evaluate static initializer
+    //~^^ ERROR it is undefined behavior to use this value
     //~| vtable
 };
 
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index c29cc836fff..92f0029a5b3 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -218,29 +218,44 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
                HEX_DUMP
            }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:125:57
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:125:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC20 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:128:57
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:128:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC21 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:131:56
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:131:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC22 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:134:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23<imm>, but expected a vtable pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -258,29 +273,49 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
                HEX_DUMP
            }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:144:62
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:144:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
-   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/ub-wide-ptr.rs:147:65
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:147:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC23 as vtable pointer but it does not point to a vtable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:156:5
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:155:1
    |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:161:5
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-wide-ptr.rs:160:1
    |
-LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC24 as vtable pointer but it does not point to a vtable
+LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31<imm>, but expected a vtable pointer
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error: aborting due to 29 previous errors
 
diff --git a/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
index dd604b6bf7d..dd604b6bf7d 100644
--- a/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs
+++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
diff --git a/tests/ui/sanitizer/cfi-async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs
index d94f2992d84..d94f2992d84 100644
--- a/tests/ui/sanitizer/cfi-async-closures.rs
+++ b/tests/ui/sanitizer/cfi/async-closures.rs
diff --git a/tests/ui/sanitizer/cfi-can-reveal-opaques.rs b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
index 55988a62a8c..55988a62a8c 100644
--- a/tests/ui/sanitizer/cfi-can-reveal-opaques.rs
+++ b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs
diff --git a/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.rs b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs
index 10c5bf6ea5e..10c5bf6ea5e 100644
--- a/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.rs
+++ b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.rs
diff --git a/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.stderr
index de67d6a6b7f..de67d6a6b7f 100644
--- a/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr
+++ b/tests/ui/sanitizer/cfi/canonical-jump-tables-requires-cfi.stderr
diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi/closures.rs
index 9f9002da674..9f9002da674 100644
--- a/tests/ui/sanitizer/cfi-closures.rs
+++ b/tests/ui/sanitizer/cfi/closures.rs
diff --git a/tests/ui/sanitizer/cfi-complex-receiver.rs b/tests/ui/sanitizer/cfi/complex-receiver.rs
index c7b45a775ca..c7b45a775ca 100644
--- a/tests/ui/sanitizer/cfi-complex-receiver.rs
+++ b/tests/ui/sanitizer/cfi/complex-receiver.rs
diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs
index ad994fcf737..ad994fcf737 100644
--- a/tests/ui/sanitizer/cfi-coroutine.rs
+++ b/tests/ui/sanitizer/cfi/coroutine.rs
diff --git a/tests/ui/sanitizer/cfi-drop-in-place.rs b/tests/ui/sanitizer/cfi/drop-in-place.rs
index 8ce2c432602..8ce2c432602 100644
--- a/tests/ui/sanitizer/cfi-drop-in-place.rs
+++ b/tests/ui/sanitizer/cfi/drop-in-place.rs
diff --git a/tests/ui/sanitizer/cfi-drop-no-principal.rs b/tests/ui/sanitizer/cfi/drop-no-principal.rs
index c1c88c8c71c..c1c88c8c71c 100644
--- a/tests/ui/sanitizer/cfi-drop-no-principal.rs
+++ b/tests/ui/sanitizer/cfi/drop-no-principal.rs
diff --git a/tests/ui/sanitizer/cfi-fn-ptr.rs b/tests/ui/sanitizer/cfi/fn-ptr.rs
index 505b4b8e7f0..505b4b8e7f0 100644
--- a/tests/ui/sanitizer/cfi-fn-ptr.rs
+++ b/tests/ui/sanitizer/cfi/fn-ptr.rs
diff --git a/tests/ui/sanitizer/cfi-generalize-pointers-attr-cfg.rs b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs
index d46002c69fd..d46002c69fd 100644
--- a/tests/ui/sanitizer/cfi-generalize-pointers-attr-cfg.rs
+++ b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs
diff --git a/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.rs b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs
index 8ba13bd3639..8ba13bd3639 100644
--- a/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.rs
+++ b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.rs
diff --git a/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.stderr b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.stderr
index 621708de241..621708de241 100644
--- a/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.stderr
+++ b/tests/ui/sanitizer/cfi/generalize-pointers-requires-cfi.stderr
diff --git a/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.rs b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs
index 7ef6bd2f0ac..7ef6bd2f0ac 100644
--- a/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.rs
+++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs
diff --git a/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr b/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr
index 93ec134241e..1aa6bef17b1 100644
--- a/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr
+++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr
@@ -1,5 +1,5 @@
 error: malformed `cfi_encoding` attribute input
-  --> $DIR/cfi-invalid-attr-cfi-encoding.rs:10:1
+  --> $DIR/invalid-attr-encoding.rs:10:1
    |
 LL | #[cfi_encoding]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.aarch64.stderr
index 7f596a19104..7f596a19104 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
+++ b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.aarch64.stderr
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.rs b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs
index c628709d7a1..c628709d7a1 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.rs
+++ b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.rs
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.x86_64.stderr
index 7f596a19104..7f596a19104 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
+++ b/tests/ui/sanitizer/cfi/is-incompatible-with-kcfi.x86_64.stderr
diff --git a/tests/ui/sanitizer/cfi-normalize-integers-attr-cfg.rs b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs
index 24c2c2c13da..24c2c2c13da 100644
--- a/tests/ui/sanitizer/cfi-normalize-integers-attr-cfg.rs
+++ b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs
diff --git a/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.rs b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs
index a7ecefbf7ef..a7ecefbf7ef 100644
--- a/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.rs
+++ b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.rs
diff --git a/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.stderr b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.stderr
index 748fb60dad9..748fb60dad9 100644
--- a/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.stderr
+++ b/tests/ui/sanitizer/cfi/normalize-integers-requires-cfi.stderr
diff --git a/tests/ui/sanitizer/cfi-requires-lto.rs b/tests/ui/sanitizer/cfi/requires-lto.rs
index 5a34f696e05..5a34f696e05 100644
--- a/tests/ui/sanitizer/cfi-requires-lto.rs
+++ b/tests/ui/sanitizer/cfi/requires-lto.rs
diff --git a/tests/ui/sanitizer/cfi-requires-lto.stderr b/tests/ui/sanitizer/cfi/requires-lto.stderr
index efc0c43138e..efc0c43138e 100644
--- a/tests/ui/sanitizer/cfi-requires-lto.stderr
+++ b/tests/ui/sanitizer/cfi/requires-lto.stderr
diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi/self-ref.rs
index 3b524ac661c..3b524ac661c 100644
--- a/tests/ui/sanitizer/cfi-self-ref.rs
+++ b/tests/ui/sanitizer/cfi/self-ref.rs
diff --git a/tests/ui/sanitizer/cfi-sized-associated-ty.rs b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
index f5b4e22e9d9..f5b4e22e9d9 100644
--- a/tests/ui/sanitizer/cfi-sized-associated-ty.rs
+++ b/tests/ui/sanitizer/cfi/sized-associated-ty.rs
diff --git a/tests/ui/sanitizer/cfi-supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs
index 4bb6177577f..4bb6177577f 100644
--- a/tests/ui/sanitizer/cfi-supertraits.rs
+++ b/tests/ui/sanitizer/cfi/supertraits.rs
diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi/virtual-auto.rs
index 6971d516a20..6971d516a20 100644
--- a/tests/ui/sanitizer/cfi-virtual-auto.rs
+++ b/tests/ui/sanitizer/cfi/virtual-auto.rs
diff --git a/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs
index 954e4ec3b85..954e4ec3b85 100644
--- a/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs
+++ b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.rs
diff --git a/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.stderr
index 8d6dc1d8f1e..8d6dc1d8f1e 100644
--- a/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr
+++ b/tests/ui/sanitizer/cfi/with-rustc-lto-requires-single-codegen-unit.stderr