diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index c394844e62593..963e5de91cefe 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -616,22 +616,34 @@ fn codegen_stmt<'tcx>(
                 Rvalue::UnaryOp(un_op, ref operand) => {
                     let operand = codegen_operand(fx, operand);
                     let layout = operand.layout();
-                    let val = operand.load_scalar(fx);
                     let res = match un_op {
-                        UnOp::Not => match layout.ty.kind() {
-                            ty::Bool => {
-                                let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
-                                CValue::by_val(res, layout)
+                        UnOp::Not => {
+                            let val = operand.load_scalar(fx);
+                            match layout.ty.kind() {
+                                ty::Bool => {
+                                    let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
+                                    CValue::by_val(res, layout)
+                                }
+                                ty::Uint(_) | ty::Int(_) => {
+                                    CValue::by_val(fx.bcx.ins().bnot(val), layout)
+                                }
+                                _ => unreachable!("un op Not for {:?}", layout.ty),
                             }
-                            ty::Uint(_) | ty::Int(_) => {
-                                CValue::by_val(fx.bcx.ins().bnot(val), layout)
+                        }
+                        UnOp::Neg => {
+                            let val = operand.load_scalar(fx);
+                            match layout.ty.kind() {
+                                ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
+                                ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
+                                _ => unreachable!("un op Neg for {:?}", layout.ty),
                             }
-                            _ => unreachable!("un op Not for {:?}", layout.ty),
-                        },
-                        UnOp::Neg => match layout.ty.kind() {
-                            ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
-                            ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
-                            _ => unreachable!("un op Neg for {:?}", layout.ty),
+                        }
+                        UnOp::PtrMetadata => match layout.abi {
+                            Abi::Scalar(_) => CValue::zst(dest_layout),
+                            Abi::ScalarPair(_, _) => {
+                                CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
+                            }
+                            _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
                         },
                     };
                     lval.write_cvalue(fx, res);
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 64e83e43d3272..ba98f2e772cbf 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>(
     assert!(layout.is_sized(), "unsized const value");
 
     if layout.is_zst() {
-        return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout);
+        return CValue::zst(layout);
     }
 
     match const_val {
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 4146137c2263a..512a96450a4b6 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> {
         CValue(CValueInner::ByValPair(value, extra), layout)
     }
 
+    /// Create an instance of a ZST
+    ///
+    /// The is represented by a dangling pointer of suitable alignment.
+    pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> {
+        assert!(layout.is_zst());
+        CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout)
+    }
+
     pub(crate) fn layout(&self) -> TyAndLayout<'tcx> {
         self.1
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 5b2f9a3be2792..cc0e913965067 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 for elem in place_ref.projection.iter() {
                     match elem {
                         mir::ProjectionElem::Field(ref f, _) => {
+                            debug_assert!(
+                                !o.layout.ty.is_any_ptr(),
+                                "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
+                                 but tried to access field {f:?} of pointer {o:?}",
+                            );
                             o = o.extract_field(bx, f.index());
                         }
                         mir::ProjectionElem::Index(_)
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 7c3569a9dd2e2..449fd9ae0db9c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             cg_base = match *elem {
                 mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
                 mir::ProjectionElem::Field(ref field, _) => {
+                    debug_assert!(
+                        !cg_base.layout.ty.is_any_ptr(),
+                        "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
+                         but tried to access field {field:?} of pointer {cg_base:?}",
+                    );
                     cg_base.project_field(bx, field.index())
                 }
                 mir::ProjectionElem::OpaqueCast(ty) => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 4dd80d34ea703..c23867be3a10d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -623,19 +623,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             mir::Rvalue::UnaryOp(op, ref operand) => {
                 let operand = self.codegen_operand(bx, operand);
-                let lloperand = operand.immediate();
                 let is_float = operand.layout.ty.is_floating_point();
-                let llval = match op {
-                    mir::UnOp::Not => bx.not(lloperand),
+                let (val, layout) = match op {
+                    mir::UnOp::Not => {
+                        let llval = bx.not(operand.immediate());
+                        (OperandValue::Immediate(llval), operand.layout)
+                    }
                     mir::UnOp::Neg => {
-                        if is_float {
-                            bx.fneg(lloperand)
+                        let llval = if is_float {
+                            bx.fneg(operand.immediate())
+                        } else {
+                            bx.neg(operand.immediate())
+                        };
+                        (OperandValue::Immediate(llval), operand.layout)
+                    }
+                    mir::UnOp::PtrMetadata => {
+                        debug_assert!(operand.layout.ty.is_unsafe_ptr());
+                        let (_, meta) = operand.val.pointer_parts();
+                        assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
+                        if let Some(meta) = meta {
+                            (OperandValue::Immediate(meta), operand.layout.field(self.cx, 1))
                         } else {
-                            bx.neg(lloperand)
+                            (OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit))
                         }
                     }
                 };
-                OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout }
+                debug_assert!(
+                    val.is_expected_variant_for_type(self.cx, layout),
+                    "Made wrong variant {val:?} for type {layout:?}",
+                );
+                OperandRef { val, layout }
             }
 
             mir::Rvalue::Discriminant(ref place) => {
@@ -718,8 +735,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let values = op.val.immediates_or_place().left_or_else(|p| {
                         bug!("Field {field_idx:?} is {p:?} making {layout:?}");
                     });
-                    inputs.extend(values);
                     let scalars = self.value_kind(op.layout).scalars().unwrap();
+                    debug_assert_eq!(values.len(), scalars.len());
+                    inputs.extend(values);
                     input_scalars.extend(scalars);
                 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index 62979af8a601d..9a98677a84482 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -174,7 +174,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
         unimplemented!()
     }
 
-    fn init_frame_extra(
+    fn init_frame(
         _ecx: &mut InterpCx<'tcx, Self>,
         _frame: interpret::Frame<'tcx, Self::Provenance>,
     ) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>>
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index d13ba4a2b95bf..79a161d3f03d7 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -643,7 +643,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
     }
 
     #[inline(always)]
-    fn init_frame_extra(
+    fn init_frame(
         ecx: &mut InterpCx<'tcx, Self>,
         frame: Frame<'tcx>,
     ) -> InterpResult<'tcx, Frame<'tcx>> {
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 737a70f335d08..19414c72c6a42 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -207,7 +207,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         assert!(cast_to.ty.is_unsafe_ptr());
         // Handle casting any ptr to raw ptr (might be a fat ptr).
         if cast_to.size == src.layout.size {
-            // Thin or fat pointer that just hast the ptr kind of target type changed.
+            // Thin or fat pointer that just has the ptr kind of target type changed.
             return Ok(ImmTy::from_immediate(**src, cast_to));
         } else {
             // Casting the metadata away from a fat ptr.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 5cd50a928704d..7c2100fcbe38a 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -819,7 +819,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             tracing_span: SpanGuard::new(),
             extra: (),
         };
-        let frame = M::init_frame_extra(self, pre_frame)?;
+        let frame = M::init_frame(self, pre_frame)?;
         self.stack_mut().push(frame);
 
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 5713e7bd82b3f..4ae0aca5a0c09 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -329,27 +329,41 @@ pub trait Machine<'tcx>: Sized {
         ptr: Pointer<Self::Provenance>,
     ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
 
-    /// Called to adjust allocations to the Provenance and AllocExtra of this machine.
+    /// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
     ///
     /// If `alloc` contains pointers, then they are all pointing to globals.
     ///
-    /// The way we construct allocations is to always first construct it without extra and then add
-    /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for
-    /// globals, and allocations created by Miri during evaluation.
-    ///
-    /// `kind` is the kind of the allocation being adjusted; it can be `None` when
-    /// it's a global and `GLOBAL_KIND` is `None`.
-    ///
     /// This should avoid copying if no work has to be done! If this returns an owned
     /// allocation (because a copy had to be done to adjust things), machine memory will
     /// cache the result. (This relies on `AllocMap::get_or` being able to add the
     /// owned allocation to the map even when the map is shared.)
-    fn adjust_allocation<'b>(
+    fn adjust_global_allocation<'b>(
         ecx: &InterpCx<'tcx, Self>,
         id: AllocId,
-        alloc: Cow<'b, Allocation>,
-        kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
+        alloc: &'b Allocation,
+    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
+    {
+        // The default implementation does a copy; CTFE machines have a more efficient implementation
+        // based on their particular choice for `Provenance`, `AllocExtra`, and `Bytes`.
+        let kind = Self::GLOBAL_KIND
+            .expect("if GLOBAL_KIND is None, adjust_global_allocation must be overwritten");
+        let alloc = alloc.adjust_from_tcx(&ecx.tcx, |ptr| ecx.global_root_pointer(ptr))?;
+        let extra =
+            Self::init_alloc_extra(ecx, id, MemoryKind::Machine(kind), alloc.size(), alloc.align)?;
+        Ok(Cow::Owned(alloc.with_extra(extra)))
+    }
+
+    /// Initialize the extra state of an allocation.
+    ///
+    /// This is guaranteed to be called exactly once on all allocations that are accessed by the
+    /// program.
+    fn init_alloc_extra(
+        ecx: &InterpCx<'tcx, Self>,
+        id: AllocId,
+        kind: MemoryKind<Self::MemoryKind>,
+        size: Size,
+        align: Align,
+    ) -> InterpResult<'tcx, Self::AllocExtra>;
 
     /// Return a "root" pointer for the given allocation: the one that is used for direct
     /// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
@@ -473,7 +487,7 @@ pub trait Machine<'tcx>: Sized {
     }
 
     /// Called immediately before a new stack frame gets pushed.
-    fn init_frame_extra(
+    fn init_frame(
         ecx: &mut InterpCx<'tcx, Self>,
         frame: Frame<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>;
@@ -590,13 +604,23 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
     }
 
     #[inline(always)]
-    fn adjust_allocation<'b>(
+    fn adjust_global_allocation<'b>(
         _ecx: &InterpCx<$tcx, Self>,
         _id: AllocId,
-        alloc: Cow<'b, Allocation>,
-        _kind: Option<MemoryKind<Self::MemoryKind>>,
+        alloc: &'b Allocation,
     ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
-        Ok(alloc)
+        // Overwrite default implementation: no need to adjust anything.
+        Ok(Cow::Borrowed(alloc))
+    }
+
+    fn init_alloc_extra(
+        _ecx: &InterpCx<$tcx, Self>,
+        _id: AllocId,
+        _kind: MemoryKind<Self::MemoryKind>,
+        _size: Size,
+        _align: Align,
+    ) -> InterpResult<$tcx, Self::AllocExtra> {
+        Ok(())
     }
 
     fn extern_static_pointer(
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 40bbfaa92c6fd..521f28b7123ea 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -239,7 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     pub fn allocate_raw_ptr(
         &mut self,
-        alloc: Allocation,
+        alloc: Allocation<M::Provenance, (), M::Bytes>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let id = self.tcx.reserve_alloc_id();
@@ -248,8 +248,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             M::GLOBAL_KIND.map(MemoryKind::Machine),
             "dynamically allocating global memory"
         );
-        let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
-        self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
+        // We have set things up so we don't need to call `adjust_from_tcx` here,
+        // so we avoid copying the entire allocation contents.
+        let extra = M::init_alloc_extra(self, id, kind, alloc.size(), alloc.align)?;
+        let alloc = alloc.with_extra(extra);
+        self.memory.alloc_map.insert(id, (kind, alloc));
         M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
     }
 
@@ -583,11 +586,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         };
         M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?;
         // We got tcx memory. Let the machine initialize its "extra" stuff.
-        M::adjust_allocation(
+        M::adjust_global_allocation(
             self,
             id, // always use the ID we got as input, not the "hidden" one.
-            Cow::Borrowed(alloc.inner()),
-            M::GLOBAL_KIND.map(MemoryKind::Machine),
+            alloc.inner(),
         )
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index d23f0c4d45b08..6d005dfcd8648 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use tracing::trace;
 
-use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine};
+use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta};
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
@@ -415,11 +415,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         use rustc_middle::mir::UnOp::*;
 
         let layout = val.layout;
-        let val = val.to_scalar();
         trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
 
         match layout.ty.kind() {
             ty::Bool => {
+                let val = val.to_scalar();
                 let val = val.to_bool()?;
                 let res = match un_op {
                     Not => !val,
@@ -428,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 Ok(ImmTy::from_bool(res, *self.tcx))
             }
             ty::Float(fty) => {
+                let val = val.to_scalar();
                 // No NaN adjustment here, `-` is a bitwise operation!
                 let res = match (un_op, fty) {
                     (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
@@ -436,8 +437,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 };
                 Ok(ImmTy::from_scalar(res, layout))
             }
-            _ => {
-                assert!(layout.ty.is_integral());
+            _ if layout.ty.is_integral() => {
+                let val = val.to_scalar();
                 let val = val.to_bits(layout.size)?;
                 let res = match un_op {
                     Not => self.truncate(!val, layout), // bitwise negation, then truncate
@@ -450,9 +451,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         // Truncate to target type.
                         self.truncate(res, layout)
                     }
+                    _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
                 };
                 Ok(ImmTy::from_uint(res, layout))
             }
+            ty::RawPtr(..) => {
+                assert_eq!(un_op, PtrMetadata);
+                let (_, meta) = val.to_scalar_and_meta();
+                Ok(match meta {
+                    MemPlaceMeta::Meta(scalar) => {
+                        let ty = un_op.ty(*self.tcx, val.layout.ty);
+                        let layout = self.layout_of(ty)?;
+                        ImmTy::from_scalar(scalar, layout)
+                    }
+                    MemPlaceMeta::None => {
+                        let unit_layout = self.layout_of(self.tcx.types.unit)?;
+                        ImmTy::uninit(unit_layout)
+                    }
+                })
+            }
+            _ => {
+                bug!("Unexpected unary op argument {val:?}")
+            }
         }
     }
 }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 2bd58680eef53..08b97b4953e97 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -804,6 +804,39 @@ fn print_crate_info(
                     println_info!("{cfg}");
                 }
             }
+            CheckCfg => {
+                let mut check_cfgs: Vec<String> = Vec::with_capacity(410);
+
+                // INSTABILITY: We are sorting the output below.
+                #[allow(rustc::potential_query_instability)]
+                for (name, expected_values) in &sess.psess.check_config.expecteds {
+                    use crate::config::ExpectedValues;
+                    match expected_values {
+                        ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")),
+                        ExpectedValues::Some(values) => {
+                            check_cfgs.extend(values.iter().map(|value| {
+                                if let Some(value) = value {
+                                    format!("{name}=\"{value}\"")
+                                } else {
+                                    name.to_string()
+                                }
+                            }))
+                        }
+                    }
+                }
+
+                check_cfgs.sort_unstable();
+                if !sess.psess.check_config.exhaustive_names {
+                    if !sess.psess.check_config.exhaustive_values {
+                        println_info!("any()=any()");
+                    } else {
+                        println_info!("any()");
+                    }
+                }
+                for check_cfg in check_cfgs {
+                    println_info!("{check_cfg}");
+                }
+            }
             CallingConventions => {
                 let mut calling_conventions = rustc_target::spec::abi::all_names();
                 calling_conventions.sort_unstable();
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 8506b8d75f957..f7989aeab41bb 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::is_val_statically_known
         | sym::ptr_mask
         | sym::aggregate_raw_ptr
+        | sym::ptr_metadata
         | sym::ub_checks
         | sym::fadd_algebraic
         | sym::fsub_algebraic
@@ -576,6 +577,7 @@ pub fn check_intrinsic_type(
             // This type check is not particularly useful, but the `where` bounds
             // on the definition in `core` do the heavy lifting for checking it.
             sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)),
+            sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)),
 
             sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index ebdc558282a91..93726ce2b3eb1 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1158,7 +1158,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
             let sig = self
                 .at(cause, self.param_env)
-                .trace(prev_ty, new_ty)
                 .lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
                 .map(|ok| self.register_infer_ok_obligations(ok))?;
 
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 16057b6ad9dc1..17e6d6250ad5e 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -48,11 +48,6 @@ pub struct At<'a, 'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
 }
 
-pub struct Trace<'a, 'tcx> {
-    at: At<'a, 'tcx>,
-    trace: TypeTrace<'tcx>,
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     #[inline]
     pub fn at<'a>(
@@ -109,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     /// call like `foo(x)`, where `foo: fn(i32)`, you might have
     /// `sup(i32, x)`, since the "expected" type is the type that
     /// appears in the signature.
-    ///
-    /// See [`At::trace`] and [`Trace::sub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn sup<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -121,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).sup(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .sup()
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
     /// Makes `expected <: actual`.
-    ///
-    /// See [`At::trace`] and [`Trace::sub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn sub<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -137,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).sub(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .sub()
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
-    /// Makes `expected <: actual`.
-    ///
-    /// See [`At::trace`] and [`Trace::eq`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
+    /// Makes `expected == actual`.
     pub fn eq<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -153,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).eq(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .equate(StructurallyRelateAliases::No)
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
+    }
+
+    /// Equates `expected` and `found` while structurally relating aliases.
+    /// This should only be used inside of the next generation trait solver
+    /// when relating rigid aliases.
+    pub fn eq_structurally_relating_aliases<T>(
+        self,
+        expected: T,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
+    where
+        T: ToTrace<'tcx>,
+    {
+        assert!(self.infcx.next_trait_solver());
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            DefineOpaqueTypes::Yes,
+        );
+        fields
+            .equate(StructurallyRelateAliases::Yes)
+            .relate(expected, actual)
+            .map(|_| InferOk { value: (), obligations: fields.obligations })
     }
 
     pub fn relate<T>(
@@ -185,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     /// this can result in an error (e.g., if asked to compute LUB of
     /// u32 and i32), it is meaningful to call one of them the
     /// "expected type".
-    ///
-    /// See [`At::trace`] and [`Trace::lub`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn lub<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -197,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).lub(define_opaque_types, expected, actual)
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
+        fields
+            .lub()
+            .relate(expected, actual)
+            .map(|value| InferOk { value, obligations: fields.obligations })
     }
 
     /// Computes the greatest-lower-bound, or mutual subtype, of two
     /// values. As with `lub` order doesn't matter, except for error
     /// cases.
-    ///
-    /// See [`At::trace`] and [`Trace::glb`] for a version of
-    /// this method that only requires `T: Relate<'tcx>`
     pub fn glb<T>(
         self,
         define_opaque_types: DefineOpaqueTypes,
@@ -215,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        self.trace(expected, actual).glb(define_opaque_types, expected, actual)
-    }
-
-    /// Sets the "trace" values that will be used for
-    /// error-reporting, but doesn't actually perform any operation
-    /// yet (this is useful when you want to set the trace using
-    /// distinct values from those you wish to operate upon).
-    pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx>
-    where
-        T: ToTrace<'tcx>,
-    {
-        let trace = ToTrace::to_trace(self.cause, true, expected, actual);
-        Trace { at: self, trace }
-    }
-}
-
-impl<'a, 'tcx> Trace<'a, 'tcx> {
-    /// Makes `a <: b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .sub()
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Makes `a :> b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn sup<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .sup()
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Makes `a == b`.
-    #[instrument(skip(self), level = "debug")]
-    pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .equate(StructurallyRelateAliases::No)
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    /// Equates `a` and `b` while structurally relating aliases. This should only
-    /// be used inside of the next generation trait solver when relating rigid aliases.
-    #[instrument(skip(self), level = "debug")]
-    pub fn eq_structurally_relating_aliases<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        debug_assert!(at.infcx.next_trait_solver());
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes);
-        fields
-            .equate(StructurallyRelateAliases::Yes)
-            .relate(a, b)
-            .map(move |_| InferOk { value: (), obligations: fields.obligations })
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
-        fields
-            .lub()
-            .relate(a, b)
-            .map(move |t| InferOk { value: t, obligations: fields.obligations })
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
-    where
-        T: Relate<'tcx>,
-    {
-        let Trace { at, trace } = self;
-        let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
+        let mut fields = CombineFields::new(
+            self.infcx,
+            ToTrace::to_trace(self.cause, true, expected, actual),
+            self.param_env,
+            define_opaque_types,
+        );
         fields
             .glb()
-            .relate(a, b)
-            .map(move |t| InferOk { value: t, obligations: fields.obligations })
+            .relate(expected, actual)
+            .map(|value| InferOk { value, obligations: fields.obligations })
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 6f603d9b612eb..c8bb6cf5f9b4c 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -836,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> {
             .collect()
     }
 
-    fn combine_fields<'a>(
-        &'a self,
-        trace: TypeTrace<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        define_opaque_types: DefineOpaqueTypes,
-    ) -> CombineFields<'a, 'tcx> {
-        CombineFields {
-            infcx: self,
-            trace,
-            param_env,
-            obligations: PredicateObligations::new(),
-            define_opaque_types,
-        }
-    }
-
     pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
     where
         T: at::ToTrace<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 7e7d4f43c7cca..6b41e4506846b 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -42,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> {
     pub define_opaque_types: DefineOpaqueTypes,
 }
 
+impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
+    pub fn new(
+        infcx: &'infcx InferCtxt<'tcx>,
+        trace: TypeTrace<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        define_opaque_types: DefineOpaqueTypes,
+    ) -> Self {
+        Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] }
+    }
+}
+
 impl<'tcx> InferCtxt<'tcx> {
     pub fn super_combine_tys<R>(
         &self,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 791e87735f40b..b0f8a047b82f9 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -266,19 +266,6 @@ impl AllocRange {
 
 // The constructors are all without extra; the extra gets added by a machine hook later.
 impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
-    /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support
-    pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self {
-        let size = Size::from_bytes(bytes.len());
-        Self {
-            bytes,
-            provenance: ProvenanceMap::new(),
-            init_mask: InitMask::new(size, true),
-            align,
-            mutability,
-            extra: (),
-        }
-    }
-
     /// Creates an allocation initialized by the given bytes
     pub fn from_bytes<'a>(
         slice: impl Into<Cow<'a, [u8]>>,
@@ -342,18 +329,30 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
             Err(x) => x,
         }
     }
+
+    /// Add the extra.
+    pub fn with_extra<Extra>(self, extra: Extra) -> Allocation<Prov, Extra, Bytes> {
+        Allocation {
+            bytes: self.bytes,
+            provenance: self.provenance,
+            init_mask: self.init_mask,
+            align: self.align,
+            mutability: self.mutability,
+            extra,
+        }
+    }
 }
 
 impl Allocation {
     /// Adjust allocation from the ones in `tcx` to a custom Machine instance
-    /// with a different `Provenance`, `Extra` and `Byte` type.
-    pub fn adjust_from_tcx<Prov: Provenance, Extra, Bytes: AllocBytes, Err>(
-        self,
+    /// with a different `Provenance` and `Byte` type.
+    pub fn adjust_from_tcx<Prov: Provenance, Bytes: AllocBytes, Err>(
+        &self,
         cx: &impl HasDataLayout,
-        extra: Extra,
         mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
-    ) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
-        let mut bytes = self.bytes;
+    ) -> Result<Allocation<Prov, (), Bytes>, Err> {
+        // Copy the data.
+        let mut bytes = Bytes::from_bytes(Cow::Borrowed(&*self.bytes), self.align);
         // Adjust provenance of pointers stored in this allocation.
         let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
         let ptr_size = cx.data_layout().pointer_size.bytes_usize();
@@ -369,12 +368,12 @@ impl Allocation {
         }
         // Create allocation.
         Ok(Allocation {
-            bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align),
+            bytes,
             provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
-            init_mask: self.init_mask,
+            init_mask: self.init_mask.clone(),
             align: self.align,
             mutability: self.mutability,
-            extra,
+            extra: self.extra,
         })
     }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2d4852114332b..ebe77a1abfd8b 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1434,6 +1434,13 @@ pub enum UnOp {
     Not,
     /// The `-` operator for negation
     Neg,
+    /// Get the metadata `M` from a `*const/mut impl Pointee<Metadata = M>`.
+    ///
+    /// For example, this will give a `()` from `*const i32`, a `usize` from
+    /// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`.
+    ///
+    /// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic.
+    PtrMetadata,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index a122cffdb876a..126387db1d9c5 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> {
                 let rhs_ty = rhs.ty(local_decls, tcx);
                 op.ty(tcx, lhs_ty, rhs_ty)
             }
-            Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
+            Rvalue::UnaryOp(op, ref operand) => {
+                let arg_ty = operand.ty(local_decls, tcx);
+                op.ty(tcx, arg_ty)
+            }
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
                 tcx.types.usize
@@ -282,6 +285,27 @@ impl<'tcx> BinOp {
     }
 }
 
+impl<'tcx> UnOp {
+    pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
+        match self {
+            UnOp::Not | UnOp::Neg => arg_ty,
+            UnOp::PtrMetadata => {
+                let pointee_ty = arg_ty
+                    .builtin_deref(true)
+                    .unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}"));
+                if pointee_ty.is_trivially_sized(tcx) {
+                    tcx.types.unit
+                } else {
+                    let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
+                        bug!("No metadata_type lang item while looking at {arg_ty:?}")
+                    };
+                    Ty::new_projection(tcx, metadata_def_id, [pointee_ty])
+                }
+            }
+        }
+    }
+}
+
 impl BorrowKind {
     pub fn to_mutbl_lossy(self) -> hir::Mutability {
         match self {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3c0f2578284ae..83790db992600 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 let formatted_op = match op {
                     UnOp::Not => "!",
                     UnOp::Neg => "-",
+                    UnOp::PtrMetadata => "PtrMetadata",
                 };
                 let parenthesized = match ct.kind() {
+                    _ if op == UnOp::PtrMetadata => true,
                     ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op,
                     ty::ConstKind::Expr(_) => true,
                     _ => false,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 6f8cfc3af4473..de748b9c85d17 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
                 Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
             },
             @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
+            @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
             @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 221301b2ceb04..3ffc447217d7d 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -316,6 +316,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
 
                         terminator.kind = TerminatorKind::Goto { target };
                     }
+                    sym::ptr_metadata => {
+                        let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else {
+                            span_bug!(
+                                terminator.source_info.span,
+                                "Wrong number of arguments for ptr_metadata intrinsic",
+                            );
+                        };
+                        let target = target.unwrap();
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                *destination,
+                                Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
+                            ))),
+                        });
+                        terminator.kind = TerminatorKind::Goto { target };
+                    }
                     _ => {}
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index e37f90ae7f400..7ec59cc983f53 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> {
             Rvalue::UnaryOp(op, operand) => {
                 match op {
                     // These operations can never fail.
-                    UnOp::Neg | UnOp::Not => {}
+                    UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {}
                 }
 
                 self.validate_operand(operand)?;
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 8d7547d03e8e1..851e16559580e 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1109,6 +1109,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             ty::Int(..) | ty::Uint(..) | ty::Bool
                         );
                     }
+                    UnOp::PtrMetadata => {
+                        if !matches!(self.mir_phase, MirPhase::Runtime(_)) {
+                            // It would probably be fine to support this in earlier phases,
+                            // but at the time of writing it's only ever introduced from intrinsic lowering,
+                            // so earlier things can just `bug!` on it.
+                            self.fail(location, "PtrMetadata should be in runtime MIR only");
+                        }
+
+                        check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..));
+                    }
                 }
             }
             Rvalue::ShallowInitBox(operand, _) => {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 51b87c5a9b038..6bbde26db3443 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let determined_imports = mem::take(&mut self.determined_imports);
         let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
 
+        let mut glob_error = false;
         for (is_indeterminate, import) in determined_imports
             .iter()
             .map(|i| (false, i))
@@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             self.import_dummy_binding(*import, is_indeterminate);
 
             if let Some(err) = unresolved_import_error {
+                glob_error |= import.is_glob();
+
                 if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
                     if source.name == kw::SelfLower {
                         // Silence `unresolved import` error if E0429 is already emitted
@@ -563,7 +566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 {
                     // In the case of a new import line, throw a diagnostic message
                     // for the previous line.
-                    self.throw_unresolved_import_error(errors);
+                    self.throw_unresolved_import_error(errors, glob_error);
                     errors = vec![];
                 }
                 if seen_spans.insert(err.span) {
@@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         if !errors.is_empty() {
-            self.throw_unresolved_import_error(errors);
+            self.throw_unresolved_import_error(errors, glob_error);
             return;
         }
 
@@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         }
 
-        if !errors.is_empty() {
-            self.throw_unresolved_import_error(errors);
-        }
+        self.throw_unresolved_import_error(errors, glob_error);
     }
 
     pub(crate) fn check_hidden_glob_reexports(
@@ -672,7 +673,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
-    fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) {
+    fn throw_unresolved_import_error(
+        &mut self,
+        errors: Vec<(Import<'_>, UnresolvedImportError)>,
+        glob_error: bool,
+    ) {
         if errors.is_empty() {
             return;
         }
@@ -751,7 +756,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         }
 
-        diag.emit();
+        let guar = diag.emit();
+        if glob_error {
+            self.glob_error = Some(guar);
+        }
     }
 
     /// Attempts to resolve the given import, returning:
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 08326d1ef57ec..0655484ad851c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     }
 
     #[inline]
-    /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
+    /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or
+    // an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found"
+    // errors. We silence them all.
     fn should_report_errs(&self) -> bool {
         !(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
+            && !self.r.glob_error.is_some()
     }
 
     // Resolve in alternative namespaces if resolution in the primary namespace fails.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f4c5ad8f6721a..9557b0f5ebc08 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
-use rustc_errors::{Applicability, Diag, ErrCode};
+use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
@@ -1048,6 +1048,7 @@ pub struct Resolver<'a, 'tcx> {
 
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
+    glob_error: Option<ErrorGuaranteed>,
     visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
     used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ast_transform_scopes: FxHashMap::default(),
 
             glob_map: Default::default(),
+            glob_error: None,
             visibilities_for_hashing: Default::default(),
             used_imports: FxHashSet::default(),
             maybe_unused_trait_imports: Default::default(),
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index c90da966e7081..0287085ad60ef 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -773,6 +773,7 @@ pub enum PrintKind {
     TargetLibdir,
     CrateName,
     Cfg,
+    CheckCfg,
     CallingConventions,
     TargetList,
     TargetCPUs,
@@ -1443,7 +1444,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "",
             "print",
             "Compiler information to print on stdout",
-            "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
+            "[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\
              target-list|target-cpus|target-features|relocation-models|code-models|\
              tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
              stack-protector-strategies|link-args|deployment-target]",
@@ -1859,6 +1860,7 @@ fn collect_print_requests(
         ("all-target-specs-json", PrintKind::AllTargetSpecs),
         ("calling-conventions", PrintKind::CallingConventions),
         ("cfg", PrintKind::Cfg),
+        ("check-cfg", PrintKind::CheckCfg),
         ("code-models", PrintKind::CodeModels),
         ("crate-name", PrintKind::CrateName),
         ("deployment-target", PrintKind::DeploymentTarget),
@@ -1908,6 +1910,16 @@ fn collect_print_requests(
                     );
                 }
             }
+            Some((_, PrintKind::CheckCfg)) => {
+                if unstable_opts.unstable_options {
+                    PrintKind::CheckCfg
+                } else {
+                    early_dcx.early_fatal(
+                        "the `-Z unstable-options` flag must also be passed to \
+                         enable the check-cfg print option",
+                    );
+                }
+            }
             Some(&(_, print_kind)) => print_kind,
             None => {
                 let prints =
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 6b73c1ebd1cac..6ec710f97d16a 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -10,7 +10,7 @@ use rustc_span::Symbol;
 use stable_mir::abi::Layout;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
-use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety};
+use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp};
 use stable_mir::ty::{
     Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
     DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
@@ -582,6 +582,18 @@ impl RustcInternal for BinOp {
     }
 }
 
+impl RustcInternal for UnOp {
+    type T<'tcx> = rustc_middle::mir::UnOp;
+
+    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        match self {
+            UnOp::Not => rustc_middle::mir::UnOp::Not,
+            UnOp::Neg => rustc_middle::mir::UnOp::Neg,
+            UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata,
+        }
+    }
+}
+
 impl<T> RustcInternal for &T
 where
     T: RustcInternal,
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 7afe46f2cbe1c..fa7b2a30ba6cf 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
 use stable_mir::compiler_interface::Context;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::{BinOp, Body, Place};
+use stable_mir::mir::{BinOp, Body, Place, UnOp};
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -700,6 +700,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
         ty.stable(&mut *tables)
     }
+
+    fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let arg_internal = arg.internal(&mut *tables, tcx);
+        let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal);
+        ty.stable(&mut *tables)
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index d89caabab3e1a..a1a5c09ef0af4 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
         match self {
             UnOp::Not => stable_mir::mir::UnOp::Not,
             UnOp::Neg => stable_mir::mir::UnOp::Neg,
+            UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata,
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ace4dff46aa0a..90da220b3f549 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1179,6 +1179,7 @@ symbols! {
         mir_make_place,
         mir_move,
         mir_offset,
+        mir_ptr_metadata,
         mir_retag,
         mir_return,
         mir_return_to,
@@ -1433,6 +1434,7 @@ symbols! {
         ptr_guaranteed_cmp,
         ptr_is_null,
         ptr_mask,
+        ptr_metadata,
         ptr_null,
         ptr_null_mut,
         ptr_offset_from,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 4977807aa6cf2..690c1797f2395 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -363,7 +363,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         for (&orig, response) in iter::zip(original_values, var_values.var_values) {
             let InferOk { value: (), obligations } = infcx
                 .at(&cause, param_env)
-                .trace(orig, response)
                 .eq_structurally_relating_aliases(orig, response)
                 .unwrap();
             assert!(obligations.is_empty());
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 98ba3feeca132..b18b59d9a752e 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -776,7 +776,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             let InferOk { value: (), obligations } = self
                 .infcx
                 .at(&ObligationCause::dummy(), param_env)
-                .trace(term, ctor_term)
                 .eq_structurally_relating_aliases(term, ctor_term)?;
             debug_assert!(obligations.is_empty());
             self.relate(param_env, alias, variance, rigid_ctor)
@@ -796,11 +795,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         rhs: T,
     ) -> Result<(), NoSolution> {
         let cause = ObligationCause::dummy();
-        let InferOk { value: (), obligations } = self
-            .infcx
-            .at(&cause, param_env)
-            .trace(lhs, rhs)
-            .eq_structurally_relating_aliases(lhs, rhs)?;
+        let InferOk { value: (), obligations } =
+            self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?;
         assert!(obligations.is_empty());
         Ok(())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 07fcf109fdaa2..629f6f394af37 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -566,10 +566,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                             {
                                 if let Ok(new_obligations) = infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .trace(c1, c2)
                                     // Can define opaque types as this is only reachable with
                                     // `generic_const_exprs`
-                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
+                                    .eq(
+                                        DefineOpaqueTypes::Yes,
+                                        ty::AliasTerm::from(a),
+                                        ty::AliasTerm::from(b),
+                                    )
                                 {
                                     return ProcessResult::Changed(mk_pending(
                                         new_obligations.into_obligations(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 696b1c1511531..7aec4e1987ed9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -910,10 +910,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 if let Ok(InferOk { obligations, value: () }) = self
                                     .infcx
                                     .at(&obligation.cause, obligation.param_env)
-                                    .trace(c1, c2)
                                     // Can define opaque types as this is only reachable with
                                     // `generic_const_exprs`
-                                    .eq(DefineOpaqueTypes::Yes, a.args, b.args)
+                                    .eq(
+                                        DefineOpaqueTypes::Yes,
+                                        ty::AliasTerm::from(a),
+                                        ty::AliasTerm::from(b),
+                                    )
                                 {
                                     return self.evaluate_predicates_recursively(
                                         previous_stack,
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 58447f6d6a31d..e9112d232cbd6 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -94,7 +94,7 @@ fn check_binop(op: mir::BinOp) -> bool {
 fn check_unop(op: mir::UnOp) -> bool {
     use mir::UnOp::*;
     match op {
-        Not | Neg => true,
+        Not | Neg | PtrMetadata => true,
     }
 }
 
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 4dd64228bbadb..858ce5301d84c 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -8,7 +8,7 @@ use std::cell::Cell;
 use crate::abi::{FnAbi, Layout, LayoutShape};
 use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
-use crate::mir::{BinOp, Body, Place};
+use crate::mir::{BinOp, Body, Place, UnOp};
 use crate::target::MachineInfo;
 use crate::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -226,6 +226,9 @@ pub trait Context {
 
     /// Get the resulting type of binary operation.
     fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
+
+    /// Get the resulting type of unary operation.
+    fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index a1432acf93cb9..4c779ae96a81b 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -346,6 +346,15 @@ impl BinOp {
 pub enum UnOp {
     Not,
     Neg,
+    PtrMetadata,
+}
+
+impl UnOp {
+    /// Return the type of this operation for the given input Ty.
+    /// This function does not perform type checking, and it currently doesn't handle SIMD.
+    pub fn ty(&self, arg_ty: Ty) -> Ty {
+        with(|ctx| ctx.unop_ty(*self, arg_ty))
+    }
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -580,7 +589,10 @@ impl Rvalue {
                 let ty = op.ty(lhs_ty, rhs_ty);
                 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
             }
-            Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => operand.ty(locals),
+            Rvalue::UnaryOp(op, operand) => {
+                let arg_ty = operand.ty(locals)?;
+                Ok(op.ty(arg_ty))
+            }
             Rvalue::Discriminant(place) => {
                 let place_ty = place.ty(locals)?;
                 place_ty
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 5a2a4c5ae6ebe..89e0b67099519 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2821,6 +2821,21 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
     type Metadata = <P as ptr::Pointee>::Metadata;
 }
 
+/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`.
+///
+/// This is used to implement functions like `ptr::metadata`.
+#[rustc_nounwind]
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_intrinsic]
+#[rustc_intrinsic_must_be_overridden]
+#[cfg(not(bootstrap))]
+pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
+    // To implement a fallback we'd have to assume the layout of the pointer,
+    // but the whole point of this intrinsic is that we shouldn't do that.
+    unreachable!()
+}
+
 // Some functions are defined here because they accidentally got made
 // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
 // (`transmute` also falls into this category, but it cannot be wrapped due to the
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 02665b2676cc1..fa5bb28adff94 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -360,6 +360,10 @@ define!("mir_assume", fn Assume(operand: bool));
 define!("mir_deinit", fn Deinit<T>(place: T));
 define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
 define!("mir_len", fn Len<T>(place: T) -> usize);
+define!(
+    "mir_ptr_metadata",
+    fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
+);
 define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T);
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 6dfeb66694d34..8d75bd2e74c75 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -3,6 +3,8 @@
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::intrinsics::aggregate_raw_ptr;
+#[cfg(not(bootstrap))]
+use crate::intrinsics::ptr_metadata;
 use crate::marker::Freeze;
 
 /// Provides the pointer metadata type of any pointed-to type.
@@ -94,10 +96,17 @@ pub trait Thin = Pointee<Metadata = ()>;
 #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
 #[inline]
 pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
-    // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
-    // and PtrComponents<T> have the same memory layouts. Only std can make this
-    // guarantee.
-    unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
+    #[cfg(bootstrap)]
+    {
+        // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
+        // and PtrComponents<T> have the same memory layouts. Only std can make this
+        // guarantee.
+        unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
+    }
+    #[cfg(not(bootstrap))]
+    {
+        ptr_metadata(ptr)
+    }
 }
 
 /// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
@@ -132,6 +141,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
 }
 
 #[repr(C)]
+#[cfg(bootstrap)]
 union PtrRepr<T: ?Sized> {
     const_ptr: *const T,
     mut_ptr: *mut T,
@@ -139,15 +149,18 @@ union PtrRepr<T: ?Sized> {
 }
 
 #[repr(C)]
+#[cfg(bootstrap)]
 struct PtrComponents<T: ?Sized> {
     data_pointer: *const (),
     metadata: <T as Pointee>::Metadata,
 }
 
 // Manual impl needed to avoid `T: Copy` bound.
+#[cfg(bootstrap)]
 impl<T: ?Sized> Copy for PtrComponents<T> {}
 
 // Manual impl needed to avoid `T: Clone` bound.
+#[cfg(bootstrap)]
 impl<T: ?Sized> Clone for PtrComponents<T> {
     fn clone(&self) -> Self {
         *self
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 7b55c2bf8a813..e8d05c2483de2 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -1171,3 +1171,15 @@ fn test_ptr_from_raw_parts_in_const() {
     assert_eq!(EMPTY_SLICE_PTR.addr(), 123);
     assert_eq!(EMPTY_SLICE_PTR.len(), 456);
 }
+
+#[test]
+fn test_ptr_metadata_in_const() {
+    use std::fmt::Debug;
+
+    const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]);
+    const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]);
+    const DYN_META: DynMetadata<dyn Debug> = std::ptr::metadata::<dyn Debug>(&[0_u8; 42]);
+    assert_eq!(ARRAY_META, ());
+    assert_eq!(SLICE_META, 3);
+    assert_eq!(DYN_META.size_of(), 42);
+}
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index dfa05671ab0f1..62a268facb638 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1431,7 +1431,7 @@ fn metadata_access_times() {
     assert_eq!(check!(a.modified()), check!(a.modified()));
     assert_eq!(check!(b.accessed()), check!(b.modified()));
 
-    if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
+    if cfg!(target_vendor = "apple") || cfg!(target_os = "windows") {
         check!(a.created());
         check!(b.created());
     }
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 26c49257ad00d..2e5bd85327a19 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -491,6 +491,14 @@ mod imp {
     }
 }
 
+// This is intentionally not enabled on iOS/tvOS/watchOS/visionOS, as it uses
+// several symbols that might lead to rejections from the App Store, namely
+// `sigaction`, `sigaltstack`, `sysctlbyname`, `mmap`, `munmap` and `mprotect`.
+//
+// This might be overly cautious, though it is also what Swift does (and they
+// usually have fewer qualms about forwards compatibility, since the runtime
+// is shipped with the OS):
+// <https://github.com/apple/swift/blob/swift-5.10-RELEASE/stdlib/public/runtime/CrashHandlerMacOS.cpp>
 #[cfg(not(any(
     target_os = "linux",
     target_os = "freebsd",
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 38c48bd9570d9..30b3edfd3aed5 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1028,6 +1028,14 @@ tool_doc!(
     is_library = true,
     crates = ["bootstrap"]
 );
+tool_doc!(
+    RunMakeSupport,
+    "run_make_support",
+    "src/tools/run-make-support",
+    rustc_tool = false,
+    is_library = true,
+    crates = ["run_make_support"]
+);
 
 #[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 045cde56f4119..b3d8465cda988 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -888,6 +888,7 @@ impl<'a> Builder<'a> {
                 doc::Tidy,
                 doc::Bootstrap,
                 doc::Releases,
+                doc::RunMakeSupport,
             ),
             Kind::Dist => describe!(
                 dist::Docs,
diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs
index b6e7aec1756b6..90bcff59a647c 100644
--- a/src/bootstrap/src/utils/dylib.rs
+++ b/src/bootstrap/src/utils/dylib.rs
@@ -5,7 +5,7 @@
 pub fn dylib_path_var() -> &'static str {
     if cfg!(target_os = "windows") {
         "PATH"
-    } else if cfg!(target_os = "macos") {
+    } else if cfg!(target_vendor = "apple") {
         "DYLD_LIBRARY_PATH"
     } else if cfg!(target_os = "haiku") {
         "LIBRARY_PATH"
diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
new file mode 100644
index 0000000000000..e55165b537404
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
@@ -0,0 +1,25 @@
+# `print=check-cfg`
+
+The tracking issue for this feature is: [#XXXXXX](https://github.com/rust-lang/rust/issues/XXXXXX).
+
+------------------------
+
+This option of the `--print` flag print the list of expected cfgs.
+
+This is related to the `--check-cfg` flag which allows specifying arbitrary expected
+names and values.
+
+This print option works similarly to `--print=cfg` (modulo check-cfg specifics):
+ - *check_cfg syntax*: *output of --print=check-cfg*
+ - `cfg(windows)`: `windows`
+ - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"`
+ - `cfg(feature, values(none(), ""))`: `feature` and `feature=""`
+ - `cfg(feature, values(any()))`: `feature=any()`
+ - `cfg(any())`: `any()`
+ - *nothing*: `any()=any()`
+
+To be used like this:
+
+```bash
+rustc --print=check-cfg -Zunstable-options lib.rs
+```
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index c7c807d3e6846..dc5818201b6d2 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -747,6 +747,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-aarch64",
     "ignore-aarch64-unknown-linux-gnu",
     "ignore-android",
+    "ignore-apple",
     "ignore-arm",
     "ignore-avr",
     "ignore-beta",
@@ -829,7 +830,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-x32",
     "ignore-x86",
     "ignore-x86_64",
-    "ignore-x86_64-apple-darwin",
     "ignore-x86_64-unknown-linux-gnu",
     "incremental",
     "known-bug",
@@ -876,6 +876,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-32bit",
     "only-64bit",
     "only-aarch64",
+    "only-apple",
     "only-arm",
     "only-avr",
     "only-beta",
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index df8c804705029..510043e3bfd8f 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -159,6 +159,12 @@ pub(super) fn parse_cfg_name_directive<'a>(
         message: "when the architecture is part of the Thumb family"
     }
 
+    condition! {
+        name: "apple",
+        condition: config.target.contains("apple"),
+        message: "when the target vendor is Apple"
+    }
+
     // Technically the locally built compiler uses the "dev" channel rather than the "nightly"
     // channel, even though most people don't know or won't care about it. To avoid confusion, we
     // treat the "dev" channel as the "nightly" channel when processing the directive.
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 02c9d384ab7e4..e8ceff847224f 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -98,7 +98,7 @@ fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> {
         AuxType::Lib => Some(format!("lib{}.rlib", lib)),
         AuxType::Dylib => Some(if cfg!(windows) {
             format!("{}.dll", lib)
-        } else if cfg!(target_os = "macos") {
+        } else if cfg!(target_vendor = "apple") {
             format!("lib{}.dylib", lib)
         } else {
             format!("lib{}.so", lib)
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 8f9425eb07167..09a7f0395cfb9 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -57,7 +57,7 @@ impl PathBufExt for PathBuf {
 pub fn dylib_env_var() -> &'static str {
     if cfg!(windows) {
         "PATH"
-    } else if cfg!(target_os = "macos") {
+    } else if cfg!(target_vendor = "apple") {
         "DYLD_LIBRARY_PATH"
     } else if cfg!(target_os = "haiku") {
         "LIBRARY_PATH"
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 8e8e1182bfffe..06af72dadbd38 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -862,14 +862,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if tcx.is_foreign_item(def_id) {
                 throw_unsup_format!("foreign thread-local statics are not supported");
             }
-            let allocation = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
-            let mut allocation = allocation.inner().clone();
+            let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
+            // We make a full copy of this allocation.
+            let mut alloc = alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?;
             // This allocation will be deallocated when the thread dies, so it is not in read-only memory.
-            allocation.mutability = Mutability::Mut;
+            alloc.mutability = Mutability::Mut;
             // Create a fresh allocation with this content.
-            let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?;
-            this.machine.threads.set_thread_local_alloc(def_id, new_alloc);
-            Ok(new_alloc)
+            let ptr = this.allocate_raw_ptr(alloc, MiriMemoryKind::Tls.into())?;
+            this.machine.threads.set_thread_local_alloc(def_id, ptr);
+            Ok(ptr)
         }
     }
 
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index fc1a655c1232f..c9b390eb67e1d 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1,7 +1,6 @@
 //! Global machine state as well as implementation of the interpreter engine
 //! `Machine` trait.
 
-use std::borrow::Cow;
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
 use std::fmt;
@@ -1086,40 +1085,33 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         }
     }
 
-    fn adjust_allocation<'b>(
+    fn init_alloc_extra(
         ecx: &MiriInterpCx<'tcx>,
         id: AllocId,
-        alloc: Cow<'b, Allocation>,
-        kind: Option<MemoryKind>,
-    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
-    {
-        let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
+        kind: MemoryKind,
+        size: Size,
+        align: Align,
+    ) -> InterpResult<'tcx, Self::AllocExtra> {
         if ecx.machine.tracked_alloc_ids.contains(&id) {
-            ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
-                id,
-                alloc.size(),
-                alloc.align,
-                kind,
-            ));
+            ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id, size, align, kind));
         }
 
-        let alloc = alloc.into_owned();
         let borrow_tracker = ecx
             .machine
             .borrow_tracker
             .as_ref()
-            .map(|bt| bt.borrow_mut().new_allocation(id, alloc.size(), kind, &ecx.machine));
+            .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine));
 
-        let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| {
+        let data_race = ecx.machine.data_race.as_ref().map(|data_race| {
             data_race::AllocState::new_allocation(
                 data_race,
                 &ecx.machine.threads,
-                alloc.size(),
+                size,
                 kind,
                 ecx.machine.current_span(),
             )
         });
-        let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
+        let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
 
         // If an allocation is leaked, we want to report a backtrace to indicate where it was
         // allocated. We don't need to record a backtrace for allocations which are allowed to
@@ -1130,17 +1122,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             Some(ecx.generate_stacktrace())
         };
 
-        let alloc: Allocation<Provenance, Self::AllocExtra, Self::Bytes> = alloc.adjust_from_tcx(
-            &ecx.tcx,
-            AllocExtra {
-                borrow_tracker,
-                data_race: race_alloc,
-                weak_memory: buffer_alloc,
-                backtrace,
-            },
-            |ptr| ecx.global_root_pointer(ptr),
-        )?;
-
         if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
             ecx.machine
                 .allocation_spans
@@ -1148,7 +1129,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                 .insert(id, (ecx.machine.current_span(), None));
         }
 
-        Ok(Cow::Owned(alloc))
+        Ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace })
     }
 
     fn adjust_alloc_root_pointer(
@@ -1357,7 +1338,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     #[inline(always)]
-    fn init_frame_extra(
+    fn init_frame(
         ecx: &mut InterpCx<'tcx, Self>,
         frame: Frame<'tcx, Provenance>,
     ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs
new file mode 100644
index 0000000000000..ff23f1e729e87
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Zmiri-disable-validation
+#![feature(core_intrinsics, custom_mir)]
+use std::intrinsics::mir::*;
+
+// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
+// rather than getting UB from the typed load or parameter passing.
+
+#[custom_mir(dialect = "runtime")]
+pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
+    mir!({
+        RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+        Return()
+    })
+}
+
+fn main() {
+    let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
+    unsafe {
+        (*p.as_mut_ptr().cast::<[usize; 2]>())[1] = 4;
+        let _meta = deref_meta(p.as_ptr().cast());
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr
new file mode 100644
index 0000000000000..61e1541d1ee4a
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+  --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
+   |
+LL |         RET = PtrMetadata(*p);
+   |         ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
+   |
+LL |         let _meta = deref_meta(p.as_ptr().cast());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs
new file mode 100644
index 0000000000000..65f74c0acdd6d
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Zmiri-disable-validation
+#![feature(core_intrinsics, custom_mir)]
+use std::intrinsics::mir::*;
+
+// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
+// rather than getting UB from the typed load or parameter passing.
+
+#[custom_mir(dialect = "runtime")]
+pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
+    mir!({
+        RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+        Return()
+    })
+}
+
+fn main() {
+    let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
+    unsafe {
+        (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
+        let _meta = deref_meta(p.as_ptr().cast());
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
new file mode 100644
index 0000000000000..de559263a326d
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr
@@ -0,0 +1,35 @@
+warning: integer-to-pointer cast
+  --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
+   |
+LL |         (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
+   |
+   = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
+   = help: which means that Miri might miss pointer bugs in this program.
+   = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
+   = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
+   = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
+   = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
+
+error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+  --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
+   |
+LL |         RET = PtrMetadata(*p);
+   |         ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
+   |
+LL |         let _meta = deref_meta(p.as_ptr().cast());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs
new file mode 100644
index 0000000000000..ad2e9fc800eb9
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs
@@ -0,0 +1,23 @@
+//@compile-flags: -Zmiri-disable-validation
+#![feature(core_intrinsics, custom_mir)]
+use std::intrinsics::mir::*;
+
+// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
+// rather than getting UB from the typed load or parameter passing.
+
+#[custom_mir(dialect = "runtime")]
+pub unsafe fn deref_meta(p: *const *const i32) -> () {
+    mir!({
+        RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
+        Return()
+    })
+}
+
+fn main() {
+    // Even though the meta is the trivially-valid `()`, this is still UB
+
+    let p = std::mem::MaybeUninit::<*const i32>::uninit();
+    unsafe {
+        let _meta = deref_meta(p.as_ptr());
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr
new file mode 100644
index 0000000000000..3ab2643afa728
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+  --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
+   |
+LL |         RET = PtrMetadata(*p);
+   |         ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC
+note: inside `main`
+  --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
+   |
+LL |         let _meta = deref_meta(p.as_ptr());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
index 0dda5aadce20a..89289a25d50a3 100644
--- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
+++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-permissive-provenance
-#![feature(core_intrinsics, layout_for_ptr)]
+#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)]
 //! Tests for various intrinsics that do not fit anywhere else.
 
 use std::intrinsics;
@@ -57,4 +57,10 @@ fn main() {
     // Make sure that even if the discriminant is stored together with data, the intrinsic returns
     // only the discriminant, nothing about the data.
     assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
+
+    let () = intrinsics::ptr_metadata(&[1, 2, 3]);
+    let len = intrinsics::ptr_metadata(&[1, 2, 3][..]);
+    assert_eq!(len, 3);
+    let dyn_meta = intrinsics::ptr_metadata(&[1, 2, 3] as &dyn std::fmt::Debug);
+    assert_eq!(dyn_meta.size_of(), 12);
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 35d7b65bec085..a75d036d31f62 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -362,7 +362,7 @@ macro_rules! impl_common_helpers {
                 self
             }
 
-            /// Inspect what the underlying [`Command`][::std::process::Command] is up to the
+            /// Inspect what the underlying [`Command`] is up to the
             /// current construction.
             pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
             where
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 1c83b630861cd..b424ae3f42107 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -203,7 +203,7 @@ impl Rustc {
         self
     }
 
-    /// Get the [`Output`][::std::process::Output] of the finished process.
+    /// Get the [`Output`] of the finished process.
     #[track_caller]
     pub fn command_output(&mut self) -> ::std::process::Output {
         // let's make sure we piped all the input and outputs
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index 9c77f1ca4624e..61d7448a6bfe7 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -94,7 +94,7 @@ impl Rustdoc {
         self
     }
 
-    /// Get the [`Output`][::std::process::Output] of the finished process.
+    /// Get the [`Output`] of the finished process.
     #[track_caller]
     pub fn command_output(&mut self) -> ::std::process::Output {
         // let's make sure we piped all the input and outputs
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 9ca27834cf720..75cd2b4c77317 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -144,7 +144,6 @@ run-make/lto-linkage-used-attr/Makefile
 run-make/lto-no-link-whole-rlib/Makefile
 run-make/lto-readonly-lib/Makefile
 run-make/lto-smoke-c/Makefile
-run-make/lto-smoke/Makefile
 run-make/macos-deployment-target/Makefile
 run-make/macos-fat-archive/Makefile
 run-make/manual-crate-name/Makefile
@@ -156,7 +155,6 @@ run-make/min-global-align/Makefile
 run-make/mingw-export-call-convention/Makefile
 run-make/mismatching-target-triples/Makefile
 run-make/missing-crate-dependency/Makefile
-run-make/mixing-deps/Makefile
 run-make/mixing-formats/Makefile
 run-make/mixing-libs/Makefile
 run-make/msvc-opt-minsize/Makefile
@@ -238,7 +236,6 @@ run-make/short-ice/Makefile
 run-make/silly-file-names/Makefile
 run-make/simd-ffi/Makefile
 run-make/simple-dylib/Makefile
-run-make/simple-rlib/Makefile
 run-make/split-debuginfo/Makefile
 run-make/stable-symbol-names/Makefile
 run-make/static-dylib-by-default/Makefile
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 881b4f84173ca..398a6fd0fbaaa 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2122,7 +2122,6 @@ ui/issues/issue-33687.rs
 ui/issues/issue-33770.rs
 ui/issues/issue-3389.rs
 ui/issues/issue-33941.rs
-ui/issues/issue-33992.rs
 ui/issues/issue-34047.rs
 ui/issues/issue-34074.rs
 ui/issues/issue-34209.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 055d620361fb8..cce0fb2c1a25b 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: u32 = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1676;
+const ISSUES_ENTRY_LIMIT: u32 = 1674;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
index 8e32d170244a7..1f15f1a318a6a 100644
--- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
+++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs
@@ -1,6 +1,6 @@
 //@ revisions: all strong basic none missing
 //@ assembly-output: emit-asm
-//@ ignore-macos slightly different policy on stack protection of arrays
+//@ ignore-apple slightly different policy on stack protection of arrays
 //@ ignore-msvc stack check code uses different function names
 //@ ignore-nvptx64 stack protector is not supported
 //@ ignore-wasm32-bare
@@ -17,12 +17,9 @@
 // See comments on https://github.com/rust-lang/rust/issues/114903.
 
 #![crate_type = "lib"]
-
 #![allow(incomplete_features)]
-
 #![feature(unsized_locals, unsized_fn_params)]
 
-
 // CHECK-LABEL: emptyfn:
 #[no_mangle]
 pub fn emptyfn() {
diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs
index 9cf54ae14a169..849f34e72e51e 100644
--- a/tests/assembly/x86_64-array-pair-load-store-merge.rs
+++ b/tests/assembly/x86_64-array-pair-load-store-merge.rs
@@ -2,7 +2,7 @@
 //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
 //@ only-x86_64
 //@ ignore-sgx
-//@ ignore-macos (manipulates rsp too)
+//@ ignore-apple (manipulates rsp too)
 
 // Depending on various codegen choices, this might end up copying
 // a `<2 x i8>`, an `i16`, or two `i8`s.
diff --git a/tests/assembly/x86_64-function-return.rs b/tests/assembly/x86_64-function-return.rs
index 64eb05062cbc4..7cfdf5bce0c1e 100644
--- a/tests/assembly/x86_64-function-return.rs
+++ b/tests/assembly/x86_64-function-return.rs
@@ -9,7 +9,7 @@
 //@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern
 //@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep
 //@ only-x86_64
-//@ ignore-x86_64-apple-darwin Symbol is called `___x86_return_thunk` (Darwin's extra underscore)
+//@ ignore-apple Symbol is called `___x86_return_thunk` (Darwin's extra underscore)
 //@ ignore-sgx Tests incompatible with LVI mitigations
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs
index f15defeaca8b5..30d518c0bcb83 100644
--- a/tests/codegen/gdb_debug_script_load.rs
+++ b/tests/codegen/gdb_debug_script_load.rs
@@ -1,6 +1,6 @@
 //
 //@ ignore-windows
-//@ ignore-macos
+//@ ignore-apple
 //@ ignore-wasm
 //@ ignore-emscripten
 
diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs
index b352cbdb75573..acc4f35d90543 100644
--- a/tests/codegen/instrument-coverage/testprog.rs
+++ b/tests/codegen/instrument-coverage/testprog.rs
@@ -11,7 +11,7 @@
 //@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun
 //@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat'
 
-//@ [DARWIN] only-macos
+//@ [DARWIN] only-apple
 //@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support
 //@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names
 //@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts
@@ -49,7 +49,7 @@ where
 
 pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
 where
-    F: FnOnce(&T)
+    F: FnOnce(&T),
 {
     if should_wrap {
         wrapper(&inner)
diff --git a/tests/codegen/intrinsics/ptr_metadata.rs b/tests/codegen/intrinsics/ptr_metadata.rs
new file mode 100644
index 0000000000000..f4bf5a1f5f173
--- /dev/null
+++ b/tests/codegen/intrinsics/ptr_metadata.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -O -C no-prepopulate-passes -Z inline-mir
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::ptr_metadata;
+
+// CHECK-LABEL: @thin_metadata(
+#[no_mangle]
+pub fn thin_metadata(p: *const ()) {
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    ptr_metadata(p)
+}
+
+// CHECK-LABEL: @slice_metadata(
+#[no_mangle]
+pub fn slice_metadata(p: *const [u8]) -> usize {
+    // CHECK: start
+    // CHECK-NEXT: ret i64 %p.1
+    ptr_metadata(p)
+}
+
+// CHECK-LABEL: @dyn_byte_offset(
+#[no_mangle]
+pub unsafe fn dyn_byte_offset(
+    p: *const dyn std::fmt::Debug,
+    n: usize,
+) -> *const dyn std::fmt::Debug {
+    // CHECK: %[[Q:.+]] = getelementptr inbounds i8, ptr %p.0, i64 %n
+    // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0
+    // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1
+    // CHECK: ret { ptr, ptr } %[[TEMP2]]
+    p.byte_add(n)
+}
diff --git a/tests/codegen/issues/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs
index c99f0b73038bd..972b8490d18f9 100644
--- a/tests/codegen/issues/issue-44056-macos-tls-align.rs
+++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs
@@ -1,5 +1,5 @@
 //
-//@ only-macos
+//@ only-apple
 //@ compile-flags: -O
 
 #![crate_type = "rlib"]
diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs
index c1933b2b3904e..12b24c90229ec 100644
--- a/tests/codegen/mainsubprogram.rs
+++ b/tests/codegen/mainsubprogram.rs
@@ -2,7 +2,7 @@
 // before 4.0, formerly backported to the Rust LLVM fork.
 
 //@ ignore-windows
-//@ ignore-macos
+//@ ignore-apple
 //@ ignore-wasi
 
 //@ compile-flags: -g -C no-prepopulate-passes
@@ -10,5 +10,4 @@
 // CHECK-LABEL: @main
 // CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
index 84d680b9bff91..20741791db5cf 100644
--- a/tests/codegen/mainsubprogramstart.rs
+++ b/tests/codegen/mainsubprogramstart.rs
@@ -1,5 +1,5 @@
 //@ ignore-windows
-//@ ignore-macos
+//@ ignore-apple
 //@ ignore-wasi wasi codegens the main symbol differently
 
 //@ compile-flags: -g -C no-prepopulate-passes
diff --git a/tests/codegen/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs
index 1263eaf206f78..87d31073d5ae1 100644
--- a/tests/codegen/pgo-counter-bias.rs
+++ b/tests/codegen/pgo-counter-bias.rs
@@ -1,6 +1,6 @@
 // Test that __llvm_profile_counter_bias does not get internalized by lto.
 
-//@ ignore-macos -runtime-counter-relocation not honored on Mach-O
+//@ ignore-apple -runtime-counter-relocation not honored on Mach-O
 //@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat
 //@ needs-profiler-support
 //@ no-prefer-dynamic
diff --git a/tests/mir-opt/building/custom/operators.g.runtime.after.mir b/tests/mir-opt/building/custom/operators.g.runtime.after.mir
new file mode 100644
index 0000000000000..a0ad7d0f93f4e
--- /dev/null
+++ b/tests/mir-opt/building/custom/operators.g.runtime.after.mir
@@ -0,0 +1,13 @@
+// MIR for `g` after runtime
+
+fn g(_1: *const i32, _2: *const [i32]) -> () {
+    let mut _0: ();
+    let mut _3: ();
+    let mut _4: usize;
+
+    bb0: {
+        _3 = PtrMetadata(_1);
+        _4 = PtrMetadata(_2);
+        return;
+    }
+}
diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs
index eb97bcc73b7e1..ff0e8dcbb4156 100644
--- a/tests/mir-opt/building/custom/operators.rs
+++ b/tests/mir-opt/building/custom/operators.rs
@@ -30,3 +30,13 @@ pub fn f(a: i32, b: bool) -> i32 {
         Return()
     })
 }
+
+// EMIT_MIR operators.g.runtime.after.mir
+#[custom_mir(dialect = "runtime")]
+pub fn g(p: *const i32, q: *const [i32]) {
+    mir!({
+        let a = PtrMetadata(p);
+        let b = PtrMetadata(q);
+        Return()
+    })
+}
diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff
new file mode 100644
index 0000000000000..d256058c05ee6
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff
@@ -0,0 +1,63 @@
+- // MIR for `get_metadata` before LowerIntrinsics
++ // MIR for `get_metadata` after LowerIntrinsics
+  
+  fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () {
+      debug a => _1;
+      debug b => _2;
+      debug c => _3;
+      let mut _0: ();
+      let _4: ();
+      let mut _5: *const i32;
+      let mut _7: *const [u8];
+      let mut _9: *const dyn std::fmt::Debug;
+      scope 1 {
+          debug _unit => _4;
+          let _6: usize;
+          scope 2 {
+              debug _usize => _6;
+              let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>;
+              scope 3 {
+                  debug _vtable => _8;
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable];
++         _4 = PtrMetadata(move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = _2;
+-         _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable];
++         _6 = PtrMetadata(move _7);
++         goto -> bb2;
+      }
+  
+      bb2: {
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = _3;
+-         _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable];
++         _8 = PtrMetadata(move _9);
++         goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+          StorageDead(_6);
+          StorageDead(_4);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff
new file mode 100644
index 0000000000000..d256058c05ee6
--- /dev/null
+++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff
@@ -0,0 +1,63 @@
+- // MIR for `get_metadata` before LowerIntrinsics
++ // MIR for `get_metadata` after LowerIntrinsics
+  
+  fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () {
+      debug a => _1;
+      debug b => _2;
+      debug c => _3;
+      let mut _0: ();
+      let _4: ();
+      let mut _5: *const i32;
+      let mut _7: *const [u8];
+      let mut _9: *const dyn std::fmt::Debug;
+      scope 1 {
+          debug _unit => _4;
+          let _6: usize;
+          scope 2 {
+              debug _usize => _6;
+              let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>;
+              scope 3 {
+                  debug _vtable => _8;
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = _1;
+-         _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable];
++         _4 = PtrMetadata(move _5);
++         goto -> bb1;
+      }
+  
+      bb1: {
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = _2;
+-         _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable];
++         _6 = PtrMetadata(move _7);
++         goto -> bb2;
+      }
+  
+      bb2: {
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = _3;
+-         _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable];
++         _8 = PtrMetadata(move _9);
++         goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+          StorageDead(_6);
+          StorageDead(_4);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 180bfd0a92462..2569f4f4de5df 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -258,3 +258,12 @@ pub fn make_pointers(a: *const u8, b: *mut (), n: usize) {
     let _slice_const: *const [u16] = aggregate_raw_ptr(a, n);
     let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n);
 }
+
+// EMIT_MIR lower_intrinsics.get_metadata.LowerIntrinsics.diff
+pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug) {
+    use std::intrinsics::ptr_metadata;
+
+    let _unit = ptr_metadata(a);
+    let _usize = ptr_metadata(b);
+    let _vtable = ptr_metadata(c);
+}
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
index db0c84bd560fd..ea4ed2713056f 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
@@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         }
         scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
             let mut _5: *const ();
-            let mut _7: usize;
+            let mut _6: usize;
             scope 5 (inlined std::ptr::metadata::<[u32]>) {
-                let mut _6: std::ptr::metadata::PtrRepr<[u32]>;
             }
             scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
             }
@@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         StorageDead(_3);
         StorageLive(_5);
         _5 = _4 as *const () (PtrToPtr);
-        StorageLive(_7);
         StorageLive(_6);
-        _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
-        _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
+        _6 = PtrMetadata(_1);
+        _0 = *const [u32] from (_5, _6);
         StorageDead(_6);
-        _0 = *const [u32] from (_5, _7);
-        StorageDead(_7);
         StorageDead(_5);
         StorageDead(_4);
         return;
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
index db0c84bd560fd..ea4ed2713056f 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
@@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         }
         scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
             let mut _5: *const ();
-            let mut _7: usize;
+            let mut _6: usize;
             scope 5 (inlined std::ptr::metadata::<[u32]>) {
-                let mut _6: std::ptr::metadata::PtrRepr<[u32]>;
             }
             scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) {
             }
@@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         StorageDead(_3);
         StorageLive(_5);
         _5 = _4 as *const () (PtrToPtr);
-        StorageLive(_7);
         StorageLive(_6);
-        _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 };
-        _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize);
+        _6 = PtrMetadata(_1);
+        _0 = *const [u32] from (_5, _6);
         StorageDead(_6);
-        _0 = *const [u32] from (_5, _7);
-        StorageDead(_7);
         StorageDead(_5);
         StorageDead(_4);
         return;
diff --git a/tests/run-make/c-dynamic-dylib/Makefile b/tests/run-make/c-dynamic-dylib/Makefile
index 0d40964048678..39561b28222ca 100644
--- a/tests/run-make/c-dynamic-dylib/Makefile
+++ b/tests/run-make/c-dynamic-dylib/Makefile
@@ -4,7 +4,7 @@
 # ignore-cross-compile
 include ../tools.mk
 
-# ignore-macos
+# ignore-apple
 #
 # This hits an assertion in the linker on older versions of osx apparently
 
diff --git a/tests/run-make/c-dynamic-rlib/Makefile b/tests/run-make/c-dynamic-rlib/Makefile
index a64e89cc0dc40..7b05e3d91a098 100644
--- a/tests/run-make/c-dynamic-rlib/Makefile
+++ b/tests/run-make/c-dynamic-rlib/Makefile
@@ -4,7 +4,7 @@
 # ignore-cross-compile
 include ../tools.mk
 
-# ignore-macos
+# ignore-apple
 #
 # This hits an assertion in the linker on older versions of osx apparently
 
diff --git a/tests/run-make/emit-stack-sizes/Makefile b/tests/run-make/emit-stack-sizes/Makefile
index f636ebd28f2ea..b546fcba5121e 100644
--- a/tests/run-make/emit-stack-sizes/Makefile
+++ b/tests/run-make/emit-stack-sizes/Makefile
@@ -1,10 +1,10 @@
 include ../tools.mk
 
 # ignore-windows
-# ignore-macos
+# ignore-apple
 #
 # This feature only works when the output object format is ELF so we ignore
-# macOS and Windows
+# Apple and Windows
 
 # check that the .stack_sizes section is generated
 all:
diff --git a/tests/run-make/fpic/Makefile b/tests/run-make/fpic/Makefile
index c38dd8d6e8c4b..d3754d17372ff 100644
--- a/tests/run-make/fpic/Makefile
+++ b/tests/run-make/fpic/Makefile
@@ -2,7 +2,7 @@
 include ../tools.mk
 
 # ignore-windows
-# ignore-macos
+# ignore-apple
 
 # Test for #39529.
 # `-z text` causes ld to error if there are any non-PIC sections
diff --git a/tests/run-make/link-framework/Makefile b/tests/run-make/link-framework/Makefile
index f33347ac7f8f5..96d832ad4a832 100644
--- a/tests/run-make/link-framework/Makefile
+++ b/tests/run-make/link-framework/Makefile
@@ -1,4 +1,4 @@
-# only-macos
+# only-apple
 #
 # Check that linking to a framework actually makes it to the linker.
 
diff --git a/tests/run-make/lto-smoke/Makefile b/tests/run-make/lto-smoke/Makefile
deleted file mode 100644
index 13a09fce73404..0000000000000
--- a/tests/run-make/lto-smoke/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all: noparam bool_true bool_false thin fat
-
-noparam:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs -C lto
-	$(call RUN,main)
-
-bool_true:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs -C lto=yes
-	$(call RUN,main)
-
-
-bool_false:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs -C lto=off
-	$(call RUN,main)
-
-thin:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs -C lto=thin
-	$(call RUN,main)
-
-fat:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs -C lto=fat
-	$(call RUN,main)
-
diff --git a/tests/run-make/lto-smoke/rmake.rs b/tests/run-make/lto-smoke/rmake.rs
new file mode 100644
index 0000000000000..692945135cd3d
--- /dev/null
+++ b/tests/run-make/lto-smoke/rmake.rs
@@ -0,0 +1,16 @@
+// A simple smoke test to check that link time optimization
+// (LTO) is accepted by the compiler, and that
+// passing its various flags still results in successful compilation.
+// See https://github.com/rust-lang/rust/issues/10741
+
+//@ ignore-cross-compile
+
+use run_make_support::rustc;
+
+fn main() {
+    let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"];
+    for flag in lto_flags {
+        rustc().input("lib.rs").run();
+        rustc().input("main.rs").arg(flag).run();
+    }
+}
diff --git a/tests/run-make/macos-fat-archive/Makefile b/tests/run-make/macos-fat-archive/Makefile
index b6582c809e8b4..0feb39a23cb54 100644
--- a/tests/run-make/macos-fat-archive/Makefile
+++ b/tests/run-make/macos-fat-archive/Makefile
@@ -1,4 +1,4 @@
-# only-macos
+# only-apple
 
 include ../tools.mk
 
diff --git a/tests/run-make/mixing-deps/Makefile b/tests/run-make/mixing-deps/Makefile
deleted file mode 100644
index c2a5a2a0abbed..0000000000000
--- a/tests/run-make/mixing-deps/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) both.rs -C prefer-dynamic
-	$(RUSTC) dylib.rs -C prefer-dynamic
-	$(RUSTC) prog.rs
-	$(call RUN,prog)
diff --git a/tests/run-make/mixing-deps/rmake.rs b/tests/run-make/mixing-deps/rmake.rs
new file mode 100644
index 0000000000000..fb31bbef9d19e
--- /dev/null
+++ b/tests/run-make/mixing-deps/rmake.rs
@@ -0,0 +1,13 @@
+// This test invokes the main function in prog.rs, which has dependencies
+// in both an rlib and a dylib. This test checks that these different library
+// types can be successfully mixed.
+//@ ignore-cross-compile
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("both.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("dylib.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("prog.rs").run();
+    run("prog");
+}
diff --git a/tests/run-make/native-link-modifier-verbatim-linker/Makefile b/tests/run-make/native-link-modifier-verbatim-linker/Makefile
index 256dc2d0664ee..47ed2a1429185 100644
--- a/tests/run-make/native-link-modifier-verbatim-linker/Makefile
+++ b/tests/run-make/native-link-modifier-verbatim-linker/Makefile
@@ -1,5 +1,5 @@
 # ignore-cross-compile
-# ignore-macos
+# ignore-apple
 
 include ../tools.mk
 
diff --git a/tests/run-make/print-check-cfg/lib.rs b/tests/run-make/print-check-cfg/lib.rs
new file mode 100644
index 0000000000000..c09e4c98dffde
--- /dev/null
+++ b/tests/run-make/print-check-cfg/lib.rs
@@ -0,0 +1 @@
+// empty crate
diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs
new file mode 100644
index 0000000000000..554884b7d579b
--- /dev/null
+++ b/tests/run-make/print-check-cfg/rmake.rs
@@ -0,0 +1,106 @@
+//! This checks the output of `--print=check-cfg`
+
+extern crate run_make_support;
+
+use std::collections::HashSet;
+use std::iter::FromIterator;
+use std::ops::Deref;
+
+use run_make_support::rustc;
+
+fn main() {
+    check(
+        /*args*/ &[],
+        /*has_any*/ false,
+        /*has_any_any*/ true,
+        /*contains*/ &[],
+    );
+    check(
+        /*args*/ &["--check-cfg=cfg()"],
+        /*has_any*/ false,
+        /*has_any_any*/ false,
+        /*contains*/ &["unix", "miri"],
+    );
+    check(
+        /*args*/ &["--check-cfg=cfg(any())"],
+        /*has_any*/ true,
+        /*has_any_any*/ false,
+        /*contains*/ &["windows", "test"],
+    );
+    check(
+        /*args*/ &["--check-cfg=cfg(feature)"],
+        /*has_any*/ false,
+        /*has_any_any*/ false,
+        /*contains*/ &["unix", "miri", "feature"],
+    );
+    check(
+        /*args*/ &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#],
+        /*has_any*/ false,
+        /*has_any_any*/ false,
+        /*contains*/ &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""],
+    );
+    check(
+        /*args*/ &[
+            r#"--check-cfg=cfg(feature, values(any()))"#,
+            r#"--check-cfg=cfg(feature, values("tmp"))"#
+        ],
+        /*has_any*/ false,
+        /*has_any_any*/ false,
+        /*contains*/ &["unix", "miri", "feature=any()"],
+    );
+    check(
+        /*args*/ &[
+            r#"--check-cfg=cfg(has_foo, has_bar)"#,
+            r#"--check-cfg=cfg(feature, values("tmp"))"#,
+            r#"--check-cfg=cfg(feature, values("tmp"))"#
+        ],
+        /*has_any*/ false,
+        /*has_any_any*/ false,
+        /*contains*/ &["has_foo", "has_bar", "feature=\"tmp\""],
+    );
+}
+
+fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) {
+    let output = rustc()
+        .input("lib.rs")
+        .arg("-Zunstable-options")
+        .arg("--print=check-cfg")
+        .args(&*args)
+        .run();
+
+    let stdout = String::from_utf8(output.stdout).unwrap();
+
+    let mut found_any = false;
+    let mut found_any_any = false;
+    let mut found = HashSet::<String>::new();
+    let mut recorded = HashSet::<String>::new();
+
+    for l in stdout.lines() {
+        assert!(l == l.trim());
+        if l == "any()" {
+            found_any = true;
+        } else if l == "any()=any()" {
+            found_any_any = true;
+        } else if let Some((left, right)) = l.split_once('=') {
+            if right != "any()" && right != "" {
+                assert!(right.starts_with("\""));
+                assert!(right.ends_with("\""));
+            }
+            assert!(!left.contains("\""));
+        } else {
+            assert!(!l.contains("\""));
+        }
+        assert!(recorded.insert(l.to_string()), "{}", &l);
+        if contains.contains(&l) {
+            assert!(found.insert(l.to_string()), "{}", &l);
+        }
+    }
+
+    let should_found = HashSet::<String>::from_iter(contains.iter().map(|s| s.to_string()));
+    let diff: Vec<_> = should_found.difference(&found).collect();
+
+    assert_eq!(found_any, has_any);
+    assert_eq!(found_any_any, has_any_any);
+    assert_eq!(found_any_any, recorded.len() == 1);
+    assert!(diff.is_empty(), "{:?} != {:?} (~ {:?})", &should_found, &found, &diff);
+}
diff --git a/tests/run-make/simple-rlib/Makefile b/tests/run-make/simple-rlib/Makefile
deleted file mode 100644
index 28df61a15478d..0000000000000
--- a/tests/run-make/simple-rlib/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-all:
-	$(RUSTC) bar.rs --crate-type=rlib
-	$(RUSTC) foo.rs
-	$(call RUN,foo)
diff --git a/tests/run-make/simple-rlib/bar.rs b/tests/run-make/simple-rlib/bar.rs
deleted file mode 100644
index c5c0bc606cd69..0000000000000
--- a/tests/run-make/simple-rlib/bar.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub fn bar() {}
diff --git a/tests/run-make/simple-rlib/foo.rs b/tests/run-make/simple-rlib/foo.rs
deleted file mode 100644
index 8d68535e3b647..0000000000000
--- a/tests/run-make/simple-rlib/foo.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-extern crate bar;
-
-fn main() {
-    bar::bar();
-}
diff --git a/tests/run-make/used-cdylib-macos/Makefile b/tests/run-make/used-cdylib-macos/Makefile
index 38a4c31c7b3af..bdf914a1ca950 100644
--- a/tests/run-make/used-cdylib-macos/Makefile
+++ b/tests/run-make/used-cdylib-macos/Makefile
@@ -1,9 +1,9 @@
 include ../tools.mk
 
-# only-macos
+# only-apple
 #
 # This checks that `#[used]` passes through to the linker on
-# darwin. This is subject to change in the future, see
+# Apple targets. This is subject to change in the future, see
 # https://github.com/rust-lang/rust/pull/93718 for discussion
 
 all:
diff --git a/tests/run-pass-valgrind/exit-flushes.rs b/tests/run-pass-valgrind/exit-flushes.rs
index fa9196a3eecbe..c2072cf0bf834 100644
--- a/tests/run-pass-valgrind/exit-flushes.rs
+++ b/tests/run-pass-valgrind/exit-flushes.rs
@@ -1,6 +1,6 @@
 //@ ignore-wasm32 no subprocess support
 //@ ignore-sgx no processes
-//@ ignore-macos this needs valgrind 3.11 or higher; see
+//@ ignore-apple this needs valgrind 3.11 or higher; see
 // https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679
 
 use std::env;
@@ -11,8 +11,7 @@ fn main() {
         print!("hello!");
         exit(0);
     } else {
-        let out = Command::new(env::args().next().unwrap()).arg("foo")
-                          .output().unwrap();
+        let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap();
         assert!(out.status.success());
         assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!");
         assert_eq!(String::from_utf8(out.stderr).unwrap(), "");
diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs
index 5451b72d97925..70343b0599ac3 100644
--- a/tests/ui/abi/stack-probes-lto.rs
+++ b/tests/ui/abi/stack-probes-lto.rs
@@ -10,5 +10,9 @@
 //@ compile-flags: -C lto
 //@ no-prefer-dynamic
 //@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino
+//@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-visionos Stack probes are enabled, but the SIGSEGV handler isn't
 
 include!("stack-probes.rs");
diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs
index 32d4d6cd31e68..22304257593fe 100644
--- a/tests/ui/abi/stack-probes.rs
+++ b/tests/ui/abi/stack-probes.rs
@@ -8,6 +8,10 @@
 //@ ignore-sgx no processes
 //@ ignore-fuchsia no exception handler registered for segfault
 //@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino
+//@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't
+//@ ignore-visionos Stack probes are enabled, but the SIGSEGV handler isn't
 
 use std::env;
 use std::mem::MaybeUninit;
diff --git a/tests/ui/backtrace/apple-no-dsymutil.rs b/tests/ui/backtrace/apple-no-dsymutil.rs
index 9924cd13b0a79..e5aeced25ca35 100644
--- a/tests/ui/backtrace/apple-no-dsymutil.rs
+++ b/tests/ui/backtrace/apple-no-dsymutil.rs
@@ -2,7 +2,7 @@
 
 //@ compile-flags:-Cstrip=none
 //@ compile-flags:-g -Csplit-debuginfo=unpacked
-//@ only-macos
+//@ only-apple
 
 use std::process::Command;
 use std::str;
diff --git a/tests/ui/deployment-target/macos-target.rs b/tests/ui/deployment-target/macos-target.rs
index be2c32e28141b..197edd024746e 100644
--- a/tests/ui/deployment-target/macos-target.rs
+++ b/tests/ui/deployment-target/macos-target.rs
@@ -1,4 +1,4 @@
-//@ only-macos
+//@ only-apple
 //@ compile-flags: --print deployment-target
 //@ normalize-stdout-test: "\d+\." -> "$$CURRENT_MAJOR_VERSION."
 //@ normalize-stdout-test: "\d+" -> "$$CURRENT_MINOR_VERSION"
diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.rs b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs
new file mode 100644
index 0000000000000..304e0c132e50a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs
@@ -0,0 +1,3 @@
+//@ compile-flags: --print=check-cfg
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr
new file mode 100644
index 0000000000000..62ee44b94a489
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the check-cfg print option
+
diff --git a/tests/ui/imports/auxiliary/simple-rlib.rs b/tests/ui/imports/auxiliary/simple-rlib.rs
new file mode 100644
index 0000000000000..28a6273840f6c
--- /dev/null
+++ b/tests/ui/imports/auxiliary/simple-rlib.rs
@@ -0,0 +1,2 @@
+#![crate_type = "rlib"]
+pub fn bar() {}
diff --git a/tests/ui/imports/import-from-missing-star-2.rs b/tests/ui/imports/import-from-missing-star-2.rs
new file mode 100644
index 0000000000000..cb341b0b0ca42
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-2.rs
@@ -0,0 +1,12 @@
+mod foo {
+    use spam::*; //~ ERROR unresolved import `spam` [E0432]
+}
+
+fn main() {
+    // Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
+    // might have caused it.
+    foo::bar();
+    // FIXME: these two should *fail* because they can't be fixed by fixing the glob import in `foo`
+    ham(); // should error but doesn't
+    eggs(); // should error but doesn't
+}
diff --git a/tests/ui/imports/import-from-missing-star-2.stderr b/tests/ui/imports/import-from-missing-star-2.stderr
new file mode 100644
index 0000000000000..ea3876248c93f
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-2.stderr
@@ -0,0 +1,11 @@
+error[E0432]: unresolved import `spam`
+  --> $DIR/import-from-missing-star-2.rs:2:9
+   |
+LL |     use spam::*;
+   |         ^^^^ maybe a missing crate `spam`?
+   |
+   = help: consider adding `extern crate spam` to use the `spam` crate
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/import-from-missing-star-3.rs b/tests/ui/imports/import-from-missing-star-3.rs
new file mode 100644
index 0000000000000..bec51fd47b375
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-3.rs
@@ -0,0 +1,43 @@
+mod foo {
+    use spam::*; //~ ERROR unresolved import `spam` [E0432]
+
+    fn x() {
+        // Expect these to pass because the compiler knows there's a failed `*` import that might
+        // fix it.
+        eggs();
+        foo::bar();
+    }
+}
+
+mod bar {
+    fn z() {}
+    fn x() {
+        // Expect these to pass because the compiler knows there's a failed `*` import that might
+        // fix it.
+        foo::bar();
+        z();
+        // FIXME: should error but doesn't because as soon as there's a single glob import error, we
+        // silence all resolve errors.
+        eggs();
+    }
+}
+
+mod baz {
+    fn x() {
+        use spam::*; //~ ERROR unresolved import `spam` [E0432]
+        fn qux() {}
+        qux();
+        // Expect this to pass because the compiler knows there's a local failed `*` import that
+        // might have caused it.
+        eggs();
+        // Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
+        // might have caused it.
+        foo::bar();
+    }
+}
+
+fn main() {
+    // FIXME: should error but doesn't because as soon as there's a single glob import error, we
+    // silence all resolve errors.
+    ham();
+}
diff --git a/tests/ui/imports/import-from-missing-star-3.stderr b/tests/ui/imports/import-from-missing-star-3.stderr
new file mode 100644
index 0000000000000..1fe5d4f19a97d
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-3.stderr
@@ -0,0 +1,19 @@
+error[E0432]: unresolved import `spam`
+  --> $DIR/import-from-missing-star-3.rs:2:9
+   |
+LL |     use spam::*;
+   |         ^^^^ maybe a missing crate `spam`?
+   |
+   = help: consider adding `extern crate spam` to use the `spam` crate
+
+error[E0432]: unresolved import `spam`
+  --> $DIR/import-from-missing-star-3.rs:27:13
+   |
+LL |         use spam::*;
+   |             ^^^^ maybe a missing crate `spam`?
+   |
+   = help: consider adding `extern crate spam` to use the `spam` crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/import-from-missing-star.rs b/tests/ui/imports/import-from-missing-star.rs
new file mode 100644
index 0000000000000..cb21e16ba6773
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star.rs
@@ -0,0 +1,10 @@
+use spam::*; //~ ERROR unresolved import `spam` [E0432]
+
+fn main() {
+    // Expect these to pass because the compiler knows there's a failed `*` import that might have
+    // caused it.
+    ham();
+    eggs();
+    // Even this case, as we might have expected `spam::foo` to exist.
+    foo::bar();
+}
diff --git a/tests/ui/imports/import-from-missing-star.stderr b/tests/ui/imports/import-from-missing-star.stderr
new file mode 100644
index 0000000000000..f8e295078047f
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star.stderr
@@ -0,0 +1,11 @@
+error[E0432]: unresolved import `spam`
+  --> $DIR/import-from-missing-star.rs:1:5
+   |
+LL | use spam::*;
+   |     ^^^^ maybe a missing crate `spam`?
+   |
+   = help: consider adding `extern crate spam` to use the `spam` crate
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/issue-31212.rs b/tests/ui/imports/issue-31212.rs
index 556f0d18f9f22..fe69c5af2706f 100644
--- a/tests/ui/imports/issue-31212.rs
+++ b/tests/ui/imports/issue-31212.rs
@@ -6,5 +6,5 @@ mod foo {
 }
 
 fn main() {
-    foo::f(); //~ ERROR cannot find function `f` in module `foo`
+    foo::f(); // cannot find function `f` in module `foo`, but silenced
 }
diff --git a/tests/ui/imports/issue-31212.stderr b/tests/ui/imports/issue-31212.stderr
index 0bb56b361cbbf..5bba791fd020f 100644
--- a/tests/ui/imports/issue-31212.stderr
+++ b/tests/ui/imports/issue-31212.stderr
@@ -4,13 +4,6 @@ error[E0432]: unresolved import `self::*`
 LL |     pub use self::*;
    |             ^^^^^^^ cannot glob-import a module into itself
 
-error[E0425]: cannot find function `f` in module `foo`
-  --> $DIR/issue-31212.rs:9:10
-   |
-LL |     foo::f();
-   |          ^ not found in `foo`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0425, E0432.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/imports/simple-rlib-import.rs b/tests/ui/imports/simple-rlib-import.rs
new file mode 100644
index 0000000000000..6eab7ba04cfaf
--- /dev/null
+++ b/tests/ui/imports/simple-rlib-import.rs
@@ -0,0 +1,12 @@
+// A simple test, where foo.rs has a dependency
+// on the rlib (a static Rust-specific library format) bar.rs. If the test passes,
+// rlibs can be built and linked into another file successfully..
+
+//@ aux-crate:bar=simple-rlib.rs
+//@ run-pass
+
+extern crate bar;
+
+fn main() {
+    bar::bar();
+}
diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs
index 4856da553a80d..138273aadd2f1 100644
--- a/tests/ui/intrinsics/intrinsic-alignment.rs
+++ b/tests/ui/intrinsics/intrinsic-alignment.rs
@@ -10,20 +10,21 @@ mod rusti {
     }
 }
 
-#[cfg(any(target_os = "android",
-          target_os = "dragonfly",
-          target_os = "emscripten",
-          target_os = "freebsd",
-          target_os = "fuchsia",
-          target_os = "hurd",
-          target_os = "illumos",
-          target_os = "linux",
-          target_os = "macos",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "vxworks",
-          target_os = "nto",
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "fuchsia",
+    target_os = "hurd",
+    target_os = "illumos",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "solaris",
+    target_os = "vxworks",
+    target_os = "nto",
+    target_vendor = "apple",
 ))]
 mod m {
     #[cfg(target_arch = "x86")]
diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr
index 0a032aabdfe8a..70b4a394dd022 100644
--- a/tests/ui/invalid-compile-flags/print.stderr
+++ b/tests/ui/invalid-compile-flags/print.stderr
@@ -1,4 +1,4 @@
 error: unknown print request: `yyyy`
   |
-  = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
+  = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
 
diff --git a/tests/ui/issues/issue-45731.rs b/tests/ui/issues/issue-45731.rs
index 8e483d08cb516..49335362dd0f7 100644
--- a/tests/ui/issues/issue-45731.rs
+++ b/tests/ui/issues/issue-45731.rs
@@ -2,10 +2,10 @@
 #![allow(unused_variables)]
 //@ compile-flags:--test -g
 
-#[cfg(target_os = "macos")]
+#[cfg(target_vendor = "apple")]
 #[test]
 fn simple_test() {
-    use std::{env, panic, fs};
+    use std::{env, fs, panic};
 
     // Find our dSYM and replace the DWARF binary with an empty file
     let mut dsym_path = env::current_exe().unwrap();
@@ -13,8 +13,13 @@ fn simple_test() {
     assert!(dsym_path.pop()); // Pop executable
     dsym_path.push(format!("{}.dSYM/Contents/Resources/DWARF/{0}", executable_name));
     {
-        let file = fs::OpenOptions::new().read(false).write(true).truncate(true).create(false)
-            .open(&dsym_path).unwrap();
+        let file = fs::OpenOptions::new()
+            .read(false)
+            .write(true)
+            .truncate(true)
+            .create(false)
+            .open(&dsym_path)
+            .unwrap();
     }
 
     env::set_var("RUST_BACKTRACE", "1");
diff --git a/tests/ui/link-section.rs b/tests/ui/link-section.rs
index 9299b4d08b231..1a791b88ef957 100644
--- a/tests/ui/link-section.rs
+++ b/tests/ui/link-section.rs
@@ -1,32 +1,32 @@
 //@ run-pass
 
 #![allow(non_upper_case_globals)]
-#[cfg(not(target_os = "macos"))]
-#[link_section=".moretext"]
+#[cfg(not(target_vendor = "apple"))]
+#[link_section = ".moretext"]
 fn i_live_in_more_text() -> &'static str {
     "knock knock"
 }
 
-#[cfg(not(target_os = "macos"))]
-#[link_section=".imm"]
+#[cfg(not(target_vendor = "apple"))]
+#[link_section = ".imm"]
 static magic: usize = 42;
 
-#[cfg(not(target_os = "macos"))]
-#[link_section=".mut"]
+#[cfg(not(target_vendor = "apple"))]
+#[link_section = ".mut"]
 static mut frobulator: usize = 0xdeadbeef;
 
-#[cfg(target_os = "macos")]
-#[link_section="__TEXT,__moretext"]
+#[cfg(target_vendor = "apple")]
+#[link_section = "__TEXT,__moretext"]
 fn i_live_in_more_text() -> &'static str {
     "knock knock"
 }
 
-#[cfg(target_os = "macos")]
-#[link_section="__RODATA,__imm"]
+#[cfg(target_vendor = "apple")]
+#[link_section = "__RODATA,__imm"]
 static magic: usize = 42;
 
-#[cfg(target_os = "macos")]
-#[link_section="__DATA,__mut"]
+#[cfg(target_vendor = "apple")]
+#[link_section = "__DATA,__mut"]
 static mut frobulator: usize = 0xdeadbeef;
 
 pub fn main() {
diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs
index 824adf62206da..08f4394db21f3 100644
--- a/tests/ui/linkage-attr/framework.rs
+++ b/tests/ui/linkage-attr/framework.rs
@@ -1,5 +1,5 @@
 // Check that linking frameworks on Apple platforms works.
-//@ only-macos
+//@ only-apple
 //@ revisions: omit link weak both
 //@ [omit]build-fail
 //@ [link]run-pass
diff --git a/tests/ui/osx-frameworks.rs b/tests/ui/linkage-attr/kind-framework.rs
similarity index 58%
rename from tests/ui/osx-frameworks.rs
rename to tests/ui/linkage-attr/kind-framework.rs
index b0d7a3a9c07af..c2f90809e03a0 100644
--- a/tests/ui/osx-frameworks.rs
+++ b/tests/ui/linkage-attr/kind-framework.rs
@@ -1,4 +1,4 @@
-//@ ignore-macos this is supposed to succeed on osx
+//@ ignore-apple this is supposed to succeed on Apple platforms (though it won't necessarily link)
 
 #[link(name = "foo", kind = "framework")]
 extern "C" {}
diff --git a/tests/ui/osx-frameworks.stderr b/tests/ui/linkage-attr/kind-framework.stderr
similarity index 89%
rename from tests/ui/osx-frameworks.stderr
rename to tests/ui/linkage-attr/kind-framework.stderr
index 8582b8123bfe1..93dacd68e294b 100644
--- a/tests/ui/osx-frameworks.stderr
+++ b/tests/ui/linkage-attr/kind-framework.stderr
@@ -1,5 +1,5 @@
 error[E0455]: link kind `framework` is only supported on Apple targets
-  --> $DIR/osx-frameworks.rs:3:29
+  --> $DIR/kind-framework.rs:3:29
    |
 LL | #[link(name = "foo", kind = "framework")]
    |                             ^^^^^^^^^^^
diff --git a/tests/ui/issues/issue-33992.rs b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
similarity index 96%
rename from tests/ui/issues/issue-33992.rs
rename to tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
index 495751436e127..a169997927ebf 100644
--- a/tests/ui/issues/issue-33992.rs
+++ b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ ignore-windows
-//@ ignore-macos
+//@ ignore-apple
 //@ ignore-wasm32 common linkage not implemented right now
 
 #![feature(linkage)]
diff --git a/tests/ui/linkage-attr/linkage1.rs b/tests/ui/linkage-attr/linkage1.rs
index 2edb80bf1b025..19bf601d9d205 100644
--- a/tests/ui/linkage-attr/linkage1.rs
+++ b/tests/ui/linkage-attr/linkage1.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ ignore-windows
-//@ ignore-macos
+//@ ignore-apple
 //@ ignore-emscripten doesn't support this linkage
 //@ ignore-sgx weak linkage not permitted
 //@ aux-build:linkage1.rs
diff --git a/tests/ui/issues/issue-18804/auxiliary/lib.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/auxiliary/lib.rs
similarity index 100%
rename from tests/ui/issues/issue-18804/auxiliary/lib.rs
rename to tests/ui/linkage-attr/propagate-generic-issue-18804/auxiliary/lib.rs
diff --git a/tests/ui/issues/issue-18804/main.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs
similarity index 91%
rename from tests/ui/issues/issue-18804/main.rs
rename to tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs
index d83fe697470b3..56a9358cce3cf 100644
--- a/tests/ui/issues/issue-18804/main.rs
+++ b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs
@@ -4,7 +4,7 @@
 
 //@ ignore-emscripten no weak symbol support
 //@ ignore-windows no extern_weak linkage
-//@ ignore-macos no extern_weak linkage
+//@ ignore-apple no extern_weak linkage
 
 //@ aux-build:lib.rs
 
diff --git a/tests/ui/manual/manual-link-framework.rs b/tests/ui/manual/manual-link-framework.rs
index 06fd76f68df14..43cdda0a4e6ac 100644
--- a/tests/ui/manual/manual-link-framework.rs
+++ b/tests/ui/manual/manual-link-framework.rs
@@ -1,7 +1,5 @@
-//@ ignore-macos
-//@ ignore-ios
+//@ ignore-apple
 //@ compile-flags:-l framework=foo
 //@ error-pattern: library kind `framework` is only supported on Apple targets
 
-fn main() {
-}
+fn main() {}
diff --git a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
index 11e4929f12e0a..ce6644e675869 100644
--- a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
+++ b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
@@ -5,12 +5,11 @@
 //@ no-prefer-dynamic
 //@ ignore-wasm32 no processes
 //@ ignore-sgx no processes
-//@ ignore-macos
 
 extern crate exit_success_if_unwind;
 
-use std::process::Command;
 use std::env;
+use std::process::Command;
 
 fn main() {
     let mut args = env::args_os();
@@ -25,7 +24,6 @@ fn main() {
     let mut cmd = Command::new(env::args_os().next().unwrap());
     cmd.arg("foo");
 
-
     // ARMv6 hanges while printing the backtrace, see #41004
     if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") {
         cmd.env("RUST_BACKTRACE", "0");
diff --git a/tests/ui/panic-runtime/abort.rs b/tests/ui/panic-runtime/abort.rs
index 22bd2ecfb00e7..caf0243ebdb26 100644
--- a/tests/ui/panic-runtime/abort.rs
+++ b/tests/ui/panic-runtime/abort.rs
@@ -4,10 +4,9 @@
 //@ no-prefer-dynamic
 //@ ignore-wasm32 no processes
 //@ ignore-sgx no processes
-//@ ignore-macos
 
-use std::process::Command;
 use std::env;
+use std::process::Command;
 
 struct Bomb;
 
@@ -23,7 +22,6 @@ fn main() {
 
     if let Some(s) = args.next() {
         if &*s == "foo" {
-
             let _bomb = Bomb;
 
             panic!("try to catch me");
diff --git a/tests/ui/panic-runtime/link-to-abort.rs b/tests/ui/panic-runtime/link-to-abort.rs
index 2a7052616f2c7..a4013f2a6cf70 100644
--- a/tests/ui/panic-runtime/link-to-abort.rs
+++ b/tests/ui/panic-runtime/link-to-abort.rs
@@ -2,7 +2,6 @@
 
 //@ compile-flags:-C panic=abort
 //@ no-prefer-dynamic
-//@ ignore-macos
 
 #![feature(panic_abort)]
 
diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs
index a62398df8b80b..c5300635ad924 100644
--- a/tests/ui/runtime/out-of-stack.rs
+++ b/tests/ui/runtime/out-of-stack.rs
@@ -7,6 +7,10 @@
 //@ ignore-sgx no processes
 //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590)
 //@ ignore-nto no stack overflow handler used (no alternate stack available)
+//@ ignore-ios stack overflow handlers aren't enabled
+//@ ignore-tvos stack overflow handlers aren't enabled
+//@ ignore-watchos stack overflow handlers aren't enabled
+//@ ignore-visionos stack overflow handlers aren't enabled
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
index d8343704f12b9..0183bdba11193 100644
--- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
+++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs
@@ -1,4 +1,4 @@
-//@ ignore-macos: cycle error does not appear on apple
+//@ ignore-apple: cycle error does not appear on apple
 
 use std::sync::Mutex;
 
diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs
index 72601bb16fffa..8ea72fdf45c88 100644
--- a/tests/ui/structs-enums/rec-align-u64.rs
+++ b/tests/ui/structs-enums/rec-align-u64.rs
@@ -30,21 +30,21 @@ struct Outer {
     t: Inner
 }
 
-
-#[cfg(any(target_os = "android",
-          target_os = "dragonfly",
-          target_os = "emscripten",
-          target_os = "freebsd",
-          target_os = "fuchsia",
-          target_os = "hurd",
-          target_os = "illumos",
-          target_os = "linux",
-          target_os = "macos",
-          target_os = "netbsd",
-          target_os = "openbsd",
-          target_os = "solaris",
-          target_os = "vxworks",
-          target_os = "nto",
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "fuchsia",
+    target_os = "hurd",
+    target_os = "illumos",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "solaris",
+    target_os = "vxworks",
+    target_os = "nto",
+    target_vendor = "apple",
 ))]
 mod m {
     #[cfg(target_arch = "x86")]