From 917d2eb78ac514bf3e3a41b38cb148bf918a0b8d Mon Sep 17 00:00:00 2001
From: Curtis D'Alves <curtis.dalves@ibm.com>
Date: Thu, 20 Feb 2025 14:31:19 -0500
Subject: [PATCH 01/27] add verbatim linker to AIXLinker

---
 compiler/rustc_codegen_ssa/src/back/linker.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e3ace01c1eb5..432bb692fb1e 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1643,9 +1643,9 @@ impl<'a> Linker for AixLinker<'a> {
         }
     }
 
-    fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
+    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
         self.hint_dynamic();
-        self.link_or_cc_arg(format!("-l{name}"));
+        self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
     }
 
     fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
@@ -1656,7 +1656,7 @@ impl<'a> Linker for AixLinker<'a> {
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.link_or_cc_arg(format!("-l{name}"));
+            self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
         } else {
             let mut arg = OsString::from("-bkeepfile:");
             arg.push(find_native_static_library(name, verbatim, self.sess));

From a54bfcf52b1b7ec105358c12987435cb88da4668 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Fri, 21 Feb 2025 17:23:49 +0000
Subject: [PATCH 02/27] Use safe FFI for various functions in codegen_llvm

---
 compiler/rustc_codegen_llvm/src/builder.rs  | 8 ++------
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +-
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 677a9cd3e90e..2b84c01a2d8d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -100,9 +100,7 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     }
 
     fn ret_void(&mut self) {
-        unsafe {
-            llvm::LLVMBuildRetVoid(self.llbuilder);
-        }
+        llvm::LLVMBuildRetVoid(self.llbuilder);
     }
 
     fn ret(&mut self, v: &'ll Value) {
@@ -293,9 +291,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn ret_void(&mut self) {
-        unsafe {
-            llvm::LLVMBuildRetVoid(self.llbuilder);
-        }
+        llvm::LLVMBuildRetVoid(self.llbuilder);
     }
 
     fn ret(&mut self, v: &'ll Value) {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index da91e6edbcfb..fa4adfd0b43e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1204,7 +1204,7 @@ unsafe extern "C" {
     pub(crate) fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>;
 
     // Terminators
-    pub(crate) fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
+    pub(crate) safe fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
     pub(crate) fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value;
     pub(crate) fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value;
     pub(crate) fn LLVMBuildCondBr<'a>(

From d4379d2afda292f0a2986fa32bd0b967d83c7e0a Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 08:07:11 +0000
Subject: [PATCH 03/27] Remove an unnecessary lifetime

---
 compiler/rustc_codegen_gcc/src/common.rs        | 4 ++--
 compiler/rustc_codegen_gcc/src/consts.rs        | 6 +++---
 compiler/rustc_codegen_llvm/src/common.rs       | 4 ++--
 compiler/rustc_codegen_ssa/src/mir/place.rs     | 2 +-
 compiler/rustc_codegen_ssa/src/traits/consts.rs | 4 ++--
 compiler/rustc_codegen_ssa/src/traits/mod.rs    | 2 +-
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 20a3482aaa27..0ee13498ccad 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -59,7 +59,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool {
     typ.get_pointee().is_some()
 }
 
-impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
     fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
         if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
     }
@@ -263,7 +263,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
         const_alloc_to_gcc(self, alloc)
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index fb0ca31c5433..c514b7a428bc 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -302,9 +302,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-pub fn const_alloc_to_gcc<'gcc, 'tcx>(
-    cx: &CodegenCx<'gcc, 'tcx>,
-    alloc: ConstAllocation<'tcx>,
+pub fn const_alloc_to_gcc<'gcc>(
+    cx: &CodegenCx<'gcc, '_>,
+    alloc: ConstAllocation<'_>,
 ) -> RValue<'gcc> {
     let alloc = alloc.inner();
     let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index f17d98fa242b..5f5a3570ebdd 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -118,7 +118,7 @@ impl<'ll> CodegenCx<'ll, '_> {
     }
 }
 
-impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
     fn const_null(&self, t: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMConstNull(t) }
     }
@@ -350,7 +350,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value {
         const_alloc_to_llvm(self, alloc, /*static*/ false)
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index edd09b9c3c5f..b1b4270234e3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         Self::alloca(bx, ptr_layout)
     }
 
-    pub fn len<Cx: ConstCodegenMethods<'tcx, Value = V>>(&self, cx: &Cx) -> V {
+    pub fn len<Cx: ConstCodegenMethods<Value = V>>(&self, cx: &Cx) -> V {
         if let FieldsShape::Array { count, .. } = self.layout.fields {
             if self.layout.is_unsized() {
                 assert_eq!(count, 0);
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 5cfb56ebacee..5db7e072ca53 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -3,7 +3,7 @@ use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
 
 use super::BackendTypes;
 
-pub trait ConstCodegenMethods<'tcx>: BackendTypes {
+pub trait ConstCodegenMethods: BackendTypes {
     // Constant constructors
     fn const_null(&self, t: Self::Type) -> Self::Value;
     /// Generate an uninitialized value (matching uninitialized memory in MIR).
@@ -38,7 +38,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes {
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
 
-    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value;
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 90fcfbe4da7a..239857a4298d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + PartialEq + fmt::Debug;
 pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
     + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
     + TypeCodegenMethods<'tcx>
-    + ConstCodegenMethods<'tcx>
+    + ConstCodegenMethods
     + StaticCodegenMethods
     + DebugInfoCodegenMethods<'tcx>
     + AsmCodegenMethods<'tcx>

From bfd88cead0dd79717f123ad7e9a26ecad88653cb Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 08:15:31 +0000
Subject: [PATCH 04/27] Avoid some duplication between SimpleCx and CodegenCx

---
 compiler/rustc_codegen_llvm/src/builder.rs    |  54 ++++------
 .../src/builder/autodiff.rs                   |   2 +-
 compiler/rustc_codegen_llvm/src/context.rs    | 100 ++++++++++--------
 compiler/rustc_codegen_llvm/src/type_.rs      |  26 +++--
 4 files changed, 94 insertions(+), 88 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 2b84c01a2d8d..aaddde2e15a1 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -30,7 +30,7 @@ use tracing::{debug, instrument};
 
 use crate::abi::FnAbiLlvmExt;
 use crate::common::Funclet;
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, FullCx, GenericCx, SCx};
 use crate::llvm::{
     self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True,
 };
@@ -40,15 +40,15 @@ use crate::value::Value;
 use crate::{attributes, llvm_util};
 
 #[must_use]
-pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SimpleCx<'ll>>> {
+pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow<SCx<'ll>>> {
     pub llbuilder: &'ll mut llvm::Builder<'ll>,
-    pub cx: &'a CX,
+    pub cx: &'a GenericCx<'ll, CX>,
 }
 
-pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>;
-pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>;
+pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>;
+pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, FullCx<'ll, 'tcx>>;
 
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
     fn drop(&mut self) {
         unsafe {
             llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@@ -87,14 +87,15 @@ impl<'a, 'll> SBuilder<'a, 'll> {
         };
         call
     }
+}
 
-    fn with_scx(scx: &'a SimpleCx<'ll>) -> Self {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+    fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self {
         // Create a fresh builder from the simple context.
-        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) };
-        SBuilder { llbuilder, cx: scx }
+        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) };
+        GenericBuilder { llbuilder, cx: scx }
     }
-}
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+
     pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
     }
@@ -108,16 +109,17 @@ impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
             llvm::LLVMBuildRet(self.llbuilder, v);
         }
     }
-}
-impl<'a, 'll> SBuilder<'a, 'll> {
-    fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> {
-        let bx = SBuilder::with_scx(cx);
+
+    fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
+        let bx = Self::with_cx(cx);
         unsafe {
             llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
         }
         bx
     }
+}
 
+impl<'a, 'll> SBuilder<'a, 'll> {
     fn check_call<'b>(
         &mut self,
         typ: &str,
@@ -1472,26 +1474,12 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
 }
 
 impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
-    fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> {
-        let bx = Builder::with_cx(cx);
-        unsafe {
-            llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
-        }
-        bx
-    }
-
-    fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
-        // Create a fresh builder from the crate context.
-        let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
-        Builder { llbuilder, cx }
-    }
-
     pub(crate) fn llfn(&self) -> &'ll Value {
         unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) }
     }
 }
 
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     fn position_at_start(&mut self, llbb: &'ll BasicBlock) {
         unsafe {
             llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
@@ -1521,7 +1509,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         }
     }
 }
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) }
     }
@@ -1666,7 +1654,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         Cow::Owned(casted_args)
     }
 }
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
     }
@@ -1690,7 +1678,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
     }
 }
-impl<'a, 'll, CX: Borrow<SimpleCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     pub(crate) fn phi(
         &mut self,
         ty: &'ll Type,
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 2c7899975e3e..78a9b168e87c 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -286,7 +286,7 @@ pub(crate) fn differentiate<'ll>(
     }
 
     let diag_handler = cgcx.create_dcx();
-    let cx = SimpleCx { llmod: module.module_llvm.llmod(), llcx: module.module_llvm.llcx };
+    let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx);
 
     // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag?
     if !diff_items.is_empty()
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index e7952bc95e7f..8dce03328576 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1,6 +1,7 @@
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::ffi::{CStr, c_char, c_uint};
+use std::marker::PhantomData;
 use std::ops::Deref;
 use std::str;
 
@@ -43,18 +44,18 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
 /// However, there are various cx related functions which we want to be available to the builder and
 /// other compiler pieces. Here we define a small subset which has enough information and can be
 /// moved around more freely.
-pub(crate) struct SimpleCx<'ll> {
+pub(crate) struct SCx<'ll> {
     pub llmod: &'ll llvm::Module,
     pub llcx: &'ll llvm::Context,
 }
 
-impl<'ll> Borrow<SimpleCx<'ll>> for CodegenCx<'ll, '_> {
-    fn borrow(&self) -> &SimpleCx<'ll> {
+impl<'ll> Borrow<SCx<'ll>> for FullCx<'ll, '_> {
+    fn borrow(&self) -> &SCx<'ll> {
         &self.scx
     }
 }
 
-impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> Deref for FullCx<'ll, 'tcx> {
     type Target = SimpleCx<'ll>;
 
     #[inline]
@@ -63,10 +64,25 @@ impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> {
     }
 }
 
+pub(crate) struct GenericCx<'ll, T: Borrow<SCx<'ll>>>(T, PhantomData<SCx<'ll>>);
+
+impl<'ll, T: Borrow<SCx<'ll>>> Deref for GenericCx<'ll, T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+pub(crate) type SimpleCx<'ll> = GenericCx<'ll, SCx<'ll>>;
+
 /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM
 /// `llvm::Context` so that several codegen units may be processed in parallel.
 /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
-pub(crate) struct CodegenCx<'ll, 'tcx> {
+pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>;
+
+pub(crate) struct FullCx<'ll, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub scx: SimpleCx<'ll>,
     pub use_dll_storage_attrs: bool,
@@ -581,31 +597,34 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits());
 
-        CodegenCx {
-            tcx,
-            scx: SimpleCx { llcx, llmod },
-            use_dll_storage_attrs,
-            tls_model,
-            codegen_unit,
-            instances: Default::default(),
-            vtables: Default::default(),
-            const_str_cache: Default::default(),
-            const_globals: Default::default(),
-            statics_to_rauw: RefCell::new(Vec::new()),
-            used_statics: RefCell::new(Vec::new()),
-            compiler_used_statics: RefCell::new(Vec::new()),
-            type_lowering: Default::default(),
-            scalar_lltypes: Default::default(),
-            isize_ty,
-            coverage_cx,
-            dbg_cx,
-            eh_personality: Cell::new(None),
-            eh_catch_typeinfo: Cell::new(None),
-            rust_try_fn: Cell::new(None),
-            intrinsics: Default::default(),
-            local_gen_sym_counter: Cell::new(0),
-            renamed_statics: Default::default(),
-        }
+        GenericCx(
+            FullCx {
+                tcx,
+                scx: SimpleCx::new(llmod, llcx),
+                use_dll_storage_attrs,
+                tls_model,
+                codegen_unit,
+                instances: Default::default(),
+                vtables: Default::default(),
+                const_str_cache: Default::default(),
+                const_globals: Default::default(),
+                statics_to_rauw: RefCell::new(Vec::new()),
+                used_statics: RefCell::new(Vec::new()),
+                compiler_used_statics: RefCell::new(Vec::new()),
+                type_lowering: Default::default(),
+                scalar_lltypes: Default::default(),
+                isize_ty,
+                coverage_cx,
+                dbg_cx,
+                eh_personality: Cell::new(None),
+                eh_catch_typeinfo: Cell::new(None),
+                rust_try_fn: Cell::new(None),
+                intrinsics: Default::default(),
+                local_gen_sym_counter: Cell::new(0),
+                renamed_statics: Default::default(),
+            },
+            PhantomData,
+        )
     }
 
     pub(crate) fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
@@ -628,7 +647,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         llvm::set_section(g, c"llvm.metadata");
     }
 }
+
 impl<'ll> SimpleCx<'ll> {
+    pub(crate) fn new(llmod: &'ll llvm::Module, llcx: &'ll llvm::Context) -> Self {
+        Self(SCx { llmod, llcx }, PhantomData)
+    }
+
     pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
         common::val_ty(v)
     }
@@ -1203,25 +1227,13 @@ impl CodegenCx<'_, '_> {
         name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
         name
     }
-
-    /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
-    pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
-        unsafe {
-            let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
-            llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
-        }
-    }
 }
 
-// This is a duplication of the set_metadata function above. However, so far it's the only one
-// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it
-// for the Builder.
-impl SimpleCx<'_> {
-    #[allow(unused)]
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
     pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
         unsafe {
-            let node = llvm::LLVMMetadataAsValue(&self.llcx, md);
+            let node = llvm::LLVMMetadataAsValue(self.llcx(), md);
             llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index d61ce4175627..4cd30973a73c 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -1,3 +1,4 @@
+use std::borrow::Borrow;
 use std::{fmt, ptr};
 
 use libc::{c_char, c_uint};
@@ -11,7 +12,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::callconv::{CastTarget, FnAbi};
 
 use crate::abi::{FnAbiLlvmExt, LlvmType};
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, GenericCx, SCx};
 pub(crate) use crate::llvm::Type;
 use crate::llvm::{Bool, False, Metadata, True};
 use crate::type_of::LayoutLlvmExt;
@@ -36,29 +37,29 @@ impl fmt::Debug for Type {
 }
 
 impl<'ll> CodegenCx<'ll, '_> {}
-impl<'ll> SimpleCx<'ll> {
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
         let name = SmallCStr::new(name);
-        unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
+        unsafe { llvm::LLVMStructCreateNamed(self.llcx(), name.as_ptr()) }
     }
 
     pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
         unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
     }
     pub(crate) fn type_void(&self) -> &'ll Type {
-        unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) }
     }
     pub(crate) fn type_token(&self) -> &'ll Type {
-        unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) }
     }
 
     pub(crate) fn type_metadata(&self) -> &'ll Type {
-        unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) }
     }
 
     ///x Creates an integer type with the given number of bits, e.g., i24
     pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
-        unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) }
+        unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) }
     }
 
     pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
@@ -121,19 +122,24 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         self.type_array(self.type_from_integer(unit), size / unit_size)
     }
 }
-impl<'ll> SimpleCx<'ll> {
+
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
+    pub(crate) fn llcx(&self) -> &'ll llvm::Context {
+        (**self).borrow().llcx
+    }
+
     pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
         unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
     }
 
     pub(crate) fn type_i1(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt1TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) }
     }
 
     pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type {
         unsafe {
             llvm::LLVMStructTypeInContext(
-                self.llcx,
+                self.llcx(),
                 els.as_ptr(),
                 els.len() as c_uint,
                 packed as Bool,

From 75356b74370d21045099cb2a1ad81dc7a3c2579f Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 11:06:25 +0000
Subject: [PATCH 05/27] Generalize `BackendTypes` over `GenericCx`

---
 compiler/rustc_codegen_llvm/src/builder.rs | 22 +++++++++++-----------
 compiler/rustc_codegen_llvm/src/common.rs  |  5 ++++-
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index aaddde2e15a1..1f7372e5cc5c 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -167,17 +167,17 @@ impl<'a, 'll> SBuilder<'a, 'll> {
 // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
 const UNNAMED: *const c_char = c"".as_ptr();
 
-impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> {
-    type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
-    type Metadata = <CodegenCx<'ll, 'tcx> as BackendTypes>::Metadata;
-    type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function;
-    type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
-    type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type;
-    type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
-
-    type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope;
-    type DILocation = <CodegenCx<'ll, 'tcx> as BackendTypes>::DILocation;
-    type DIVariable = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIVariable;
+impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericBuilder<'_, 'll, CX> {
+    type Value = <GenericCx<'ll, CX> as BackendTypes>::Value;
+    type Metadata = <GenericCx<'ll, CX> as BackendTypes>::Metadata;
+    type Function = <GenericCx<'ll, CX> as BackendTypes>::Function;
+    type BasicBlock = <GenericCx<'ll, CX> as BackendTypes>::BasicBlock;
+    type Type = <GenericCx<'ll, CX> as BackendTypes>::Type;
+    type Funclet = <GenericCx<'ll, CX> as BackendTypes>::Funclet;
+
+    type DIScope = <GenericCx<'ll, CX> as BackendTypes>::DIScope;
+    type DILocation = <GenericCx<'ll, CX> as BackendTypes>::DILocation;
+    type DIVariable = <GenericCx<'ll, CX> as BackendTypes>::DIVariable;
 }
 
 impl abi::HasDataLayout for Builder<'_, '_, '_> {
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 5f5a3570ebdd..7af2815e64cc 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -1,5 +1,7 @@
 //! Code that is useful in various codegen modules.
 
+use std::borrow::Borrow;
+
 use libc::{c_char, c_uint};
 use rustc_abi as abi;
 use rustc_abi::Primitive::Pointer;
@@ -18,6 +20,7 @@ use tracing::debug;
 
 use crate::consts::const_alloc_to_llvm;
 pub(crate) use crate::context::CodegenCx;
+use crate::context::{GenericCx, SCx};
 use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True};
 use crate::type_::Type;
 use crate::value::Value;
@@ -81,7 +84,7 @@ impl<'ll> Funclet<'ll> {
     }
 }
 
-impl<'ll> BackendTypes for CodegenCx<'ll, '_> {
+impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> {
     type Value = &'ll Value;
     type Metadata = &'ll Metadata;
     // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.

From 840e31b29f93a5e0569d05c8879468877a9991d4 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Mon, 24 Feb 2025 11:31:43 +0000
Subject: [PATCH 06/27] Generalize BaseTypeCodegenMethods

---
 compiler/rustc_codegen_gcc/src/type_.rs       |  2 +-
 .../src/builder/autodiff.rs                   |  3 +-
 compiler/rustc_codegen_llvm/src/context.rs    | 19 +++++++------
 compiler/rustc_codegen_llvm/src/type_.rs      | 28 +++++++++++--------
 compiler/rustc_codegen_ssa/src/back/write.rs  |  3 ++
 .../rustc_codegen_ssa/src/traits/type_.rs     |  9 ++----
 6 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index cb08723431a9..4e0a250b5509 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -123,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     }
 }
 
-impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> {
     fn type_i8(&self) -> Type<'gcc> {
         self.i8_type
     }
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 78a9b168e87c..1e12d1a1cb3e 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -286,7 +286,8 @@ pub(crate) fn differentiate<'ll>(
     }
 
     let diag_handler = cgcx.create_dcx();
-    let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx);
+
+    let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size);
 
     // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag?
     if !diff_items.is_empty()
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 8dce03328576..6a7c042e03af 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -5,7 +5,7 @@ use std::marker::PhantomData;
 use std::ops::Deref;
 use std::str;
 
-use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
+use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx};
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
 use rustc_codegen_ssa::common::TypeKind;
@@ -47,6 +47,7 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
 pub(crate) struct SCx<'ll> {
     pub llmod: &'ll llvm::Module,
     pub llcx: &'ll llvm::Context,
+    pub isize_ty: &'ll Type,
 }
 
 impl<'ll> Borrow<SCx<'ll>> for FullCx<'ll, '_> {
@@ -120,8 +121,6 @@ pub(crate) struct FullCx<'ll, 'tcx> {
     /// Mapping of scalar types to llvm types.
     pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>,
 
-    pub isize_ty: &'ll Type,
-
     /// Extra per-CGU codegen state needed when coverage instrumentation is enabled.
     pub coverage_cx: Option<coverageinfo::CguCoverageContext<'ll, 'tcx>>,
     pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
@@ -595,12 +594,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             None
         };
 
-        let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits());
-
         GenericCx(
             FullCx {
                 tcx,
-                scx: SimpleCx::new(llmod, llcx),
+                scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size),
                 use_dll_storage_attrs,
                 tls_model,
                 codegen_unit,
@@ -613,7 +610,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
                 compiler_used_statics: RefCell::new(Vec::new()),
                 type_lowering: Default::default(),
                 scalar_lltypes: Default::default(),
-                isize_ty,
                 coverage_cx,
                 dbg_cx,
                 eh_personality: Cell::new(None),
@@ -649,8 +645,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 }
 
 impl<'ll> SimpleCx<'ll> {
-    pub(crate) fn new(llmod: &'ll llvm::Module, llcx: &'ll llvm::Context) -> Self {
-        Self(SCx { llmod, llcx }, PhantomData)
+    pub(crate) fn new(
+        llmod: &'ll llvm::Module,
+        llcx: &'ll llvm::Context,
+        pointer_size: Size,
+    ) -> Self {
+        let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits());
+        Self(SCx { llmod, llcx, isize_ty }, PhantomData)
     }
 
     pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 4cd30973a73c..b89ce90d1a1d 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         (**self).borrow().llcx
     }
 
+    pub(crate) fn isize_ty(&self) -> &'ll Type {
+        (**self).borrow().isize_ty
+    }
+
     pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
         unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
     }
@@ -148,45 +152,45 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     }
 }
 
-impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> {
     fn type_i8(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt8TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt8TypeInContext(self.llcx()) }
     }
 
     fn type_i16(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt16TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt16TypeInContext(self.llcx()) }
     }
 
     fn type_i32(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt32TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt32TypeInContext(self.llcx()) }
     }
 
     fn type_i64(&self) -> &'ll Type {
-        unsafe { llvm::LLVMInt64TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) }
     }
 
     fn type_i128(&self) -> &'ll Type {
-        unsafe { llvm::LLVMIntTypeInContext(self.llcx, 128) }
+        unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) }
     }
 
     fn type_isize(&self) -> &'ll Type {
-        self.isize_ty
+        self.isize_ty()
     }
 
     fn type_f16(&self) -> &'ll Type {
-        unsafe { llvm::LLVMHalfTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMHalfTypeInContext(self.llcx()) }
     }
 
     fn type_f32(&self) -> &'ll Type {
-        unsafe { llvm::LLVMFloatTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMFloatTypeInContext(self.llcx()) }
     }
 
     fn type_f64(&self) -> &'ll Type {
-        unsafe { llvm::LLVMDoubleTypeInContext(self.llcx) }
+        unsafe { llvm::LLVMDoubleTypeInContext(self.llcx()) }
     }
 
     fn type_f128(&self) -> &'ll Type {
-        unsafe { llvm::LLVMFP128TypeInContext(self.llcx) }
+        unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) }
     }
 
     fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
@@ -202,7 +206,7 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type {
-        unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) }
+        unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) }
     }
 
     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index f008bd12ed8f..f6f5f851d3c2 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::{fs, io, mem, str, thread};
 
+use rustc_abi::Size;
 use rustc_ast::attr;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -351,6 +352,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub target_is_like_aix: bool,
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
     pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
+    pub pointer_size: Size,
 
     /// All commandline args used to invoke the compiler, with @file args fully expanded.
     /// This will only be used within debug info, e.g. in the pdb file on windows
@@ -1212,6 +1214,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         split_debuginfo: tcx.sess.split_debuginfo(),
         split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind,
         parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend,
+        pointer_size: tcx.data_layout.pointer_size,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index c178ebc596e1..7e32d956ee63 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -9,7 +9,7 @@ use super::misc::MiscCodegenMethods;
 use crate::common::TypeKind;
 use crate::mir::place::PlaceRef;
 
-pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes {
+pub trait BaseTypeCodegenMethods: BackendTypes {
     fn type_i8(&self) -> Self::Type;
     fn type_i16(&self) -> Self::Type;
     fn type_i32(&self) -> Self::Type;
@@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes {
 }
 
 pub trait DerivedTypeCodegenMethods<'tcx>:
-    BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
+    BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
     fn type_int(&self) -> Self::Type {
         match &self.sess().target.c_int_width[..] {
@@ -100,10 +100,7 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
 }
 
 impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where
-    Self: BaseTypeCodegenMethods<'tcx>
-        + MiscCodegenMethods<'tcx>
-        + HasTyCtxt<'tcx>
-        + HasTypingEnv<'tcx>
+    Self: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
 }
 

From 396baa750e51a0e40fb0b803bfa6399a35e604a2 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 11:14:21 +0000
Subject: [PATCH 07/27] Make allocator shim creation mostly use safe code

---
 compiler/rustc_codegen_llvm/src/allocator.rs | 156 +++++++++----------
 compiler/rustc_codegen_llvm/src/builder.rs   |   8 +-
 compiler/rustc_codegen_llvm/src/declare.rs   |  17 +-
 compiler/rustc_codegen_llvm/src/lib.rs       |   7 +-
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs  |   2 +-
 5 files changed, 94 insertions(+), 96 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 66723cbf8820..e614115f64b9 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{
     ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
     alloc_error_handler_name, default_fn_name, global_fn_name,
 };
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 
-use crate::common::AsCCharPtr;
-use crate::llvm::{self, Context, False, Module, True, Type};
-use crate::{ModuleLlvm, attributes, debuginfo};
+use crate::builder::SBuilder;
+use crate::declare::declare_simple_fn;
+use crate::llvm::{self, False, True, Type};
+use crate::{SimpleCx, attributes, debuginfo};
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
-    module_llvm: &mut ModuleLlvm,
+    cx: SimpleCx<'_>,
     module_name: &str,
     kind: AllocatorKind,
     alloc_error_handler_kind: AllocatorKind,
 ) {
-    let llcx = &*module_llvm.llcx;
-    let llmod = module_llvm.llmod();
-    let usize = unsafe {
-        match tcx.sess.target.pointer_width {
-            16 => llvm::LLVMInt16TypeInContext(llcx),
-            32 => llvm::LLVMInt32TypeInContext(llcx),
-            64 => llvm::LLVMInt64TypeInContext(llcx),
-            tws => bug!("Unsupported target word size for int: {}", tws),
-        }
+    let usize = match tcx.sess.target.pointer_width {
+        16 => cx.type_i16(),
+        32 => cx.type_i32(),
+        64 => cx.type_i64(),
+        tws => bug!("Unsupported target word size for int: {}", tws),
     };
-    let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) };
-    let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) };
+    let i8 = cx.type_i8();
+    let i8p = cx.type_ptr();
 
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
@@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen(
             let from_name = global_fn_name(method.name);
             let to_name = default_fn_name(method.name);
 
-            create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false);
+            create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false);
         }
     }
 
     // rust alloc error handler
     create_wrapper_function(
         tcx,
-        llcx,
-        llmod,
+        &cx,
         "__rust_alloc_error_handler",
         alloc_error_handler_name(alloc_error_handler_kind),
         &[usize, usize], // size, align
@@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen(
     unsafe {
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        let ll_g = cx.declare_global(name, i8);
         llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::set_initializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        let ll_g = cx.declare_global(name, i8);
         llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::set_initializer(ll_g, llval);
     }
 
     if tcx.sess.opts.debuginfo != DebugInfo::None {
-        let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
+        let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
         debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
         dbg_cx.finalize(tcx.sess);
     }
@@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen(
 
 fn create_wrapper_function(
     tcx: TyCtxt<'_>,
-    llcx: &Context,
-    llmod: &Module,
+    cx: &SimpleCx<'_>,
     from_name: &str,
     to_name: &str,
     args: &[&Type],
     output: Option<&Type>,
     no_return: bool,
 ) {
-    unsafe {
-        let ty = llvm::LLVMFunctionType(
-            output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)),
-            args.as_ptr(),
-            args.len() as c_uint,
-            False,
-        );
-        let llfn = llvm::LLVMRustGetOrInsertFunction(
-            llmod,
-            from_name.as_c_char_ptr(),
-            from_name.len(),
-            ty,
-        );
-        let no_return = if no_return {
-            // -> ! DIFlagNoReturn
-            let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
-            attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
-            Some(no_return)
-        } else {
-            None
-        };
-
-        llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
-
-        if tcx.sess.must_emit_unwind_tables() {
-            let uwtable =
-                attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
-            attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
-        }
+    let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void()));
+    let llfn = declare_simple_fn(
+        &cx,
+        from_name,
+        llvm::CallConv::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        ty,
+    );
+    let no_return = if no_return {
+        // -> ! DIFlagNoReturn
+        let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
+        Some(no_return)
+    } else {
+        None
+    };
 
-        let callee =
-            llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty);
-        if let Some(no_return) = no_return {
-            // -> ! DIFlagNoReturn
-            attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
-        }
-        llvm::set_visibility(callee, llvm::Visibility::Hidden);
-
-        let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
-
-        let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
-        llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
-        let args = args
-            .iter()
-            .enumerate()
-            .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
-            .collect::<Vec<_>>();
-        let ret = llvm::LLVMBuildCallWithOperandBundles(
-            llbuilder,
-            ty,
-            callee,
-            args.as_ptr(),
-            args.len() as c_uint,
-            [].as_ptr(),
-            0 as c_uint,
-            c"".as_ptr(),
-        );
-        llvm::LLVMSetTailCall(ret, True);
-        if output.is_some() {
-            llvm::LLVMBuildRet(llbuilder, ret);
-        } else {
-            llvm::LLVMBuildRetVoid(llbuilder);
-        }
-        llvm::LLVMDisposeBuilder(llbuilder);
+    if tcx.sess.must_emit_unwind_tables() {
+        let uwtable =
+            attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
+        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
+    }
+
+    let callee = declare_simple_fn(
+        &cx,
+        to_name,
+        llvm::CallConv::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::Hidden,
+        ty,
+    );
+    if let Some(no_return) = no_return {
+        // -> ! DIFlagNoReturn
+        attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
+    }
+    llvm::set_visibility(callee, llvm::Visibility::Hidden);
+
+    let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
+
+    let mut bx = SBuilder::build(&cx, llbb);
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| llvm::get_param(llfn, i as c_uint))
+        .collect::<Vec<_>>();
+    let ret = bx.call(ty, callee, &args, None);
+    llvm::LLVMSetTailCall(ret, True);
+    if output.is_some() {
+        bx.ret(ret);
+    } else {
+        bx.ret_void()
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 1f7372e5cc5c..aab63324f426 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -57,7 +57,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> Drop for GenericBuilder<'a, 'll, CX> {
 }
 
 impl<'a, 'll> SBuilder<'a, 'll> {
-    fn call(
+    pub(crate) fn call(
         &mut self,
         llty: &'ll Type,
         llfn: &'ll Value,
@@ -100,17 +100,17 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
         unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) }
     }
 
-    fn ret_void(&mut self) {
+    pub(crate) fn ret_void(&mut self) {
         llvm::LLVMBuildRetVoid(self.llbuilder);
     }
 
-    fn ret(&mut self, v: &'ll Value) {
+    pub(crate) fn ret(&mut self, v: &'ll Value) {
         unsafe {
             llvm::LLVMBuildRet(self.llbuilder, v);
         }
     }
 
-    fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
+    pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
         let bx = Self::with_cx(cx);
         unsafe {
             llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb);
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index e79662ebc647..2419ec1f8885 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -11,6 +11,8 @@
 //! * Use define_* family of methods when you might be defining the Value.
 //! * When in doubt, define.
 
+use std::borrow::Borrow;
+
 use itertools::Itertools;
 use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
 use rustc_data_structures::fx::FxIndexSet;
@@ -22,7 +24,7 @@ use tracing::debug;
 
 use crate::abi::FnAbiLlvmExt;
 use crate::common::AsCCharPtr;
-use crate::context::{CodegenCx, SimpleCx};
+use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx};
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::Visibility;
 use crate::type_::Type;
@@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
     llfn
 }
 
-impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     /// Declare a global value.
     ///
     /// If there’s a value with the same name already declared, the function will
     /// return its Value instead.
     pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
         debug!("declare_global(name={:?})", name);
-        unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) }
+        unsafe {
+            llvm::LLVMRustGetOrInsertGlobal(
+                (**self).borrow().llmod,
+                name.as_c_char_ptr(),
+                name.len(),
+                ty,
+            )
+        }
     }
+}
 
+impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     /// Declare a C ABI function.
     ///
     /// Only use this for foreign function ABIs and glue. For Rust functions use
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index e9e1b644f183..a15ec6000bca 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -29,6 +29,7 @@ use std::mem::ManuallyDrop;
 
 use back::owned_target_machine::OwnedTargetMachine;
 use back::write::{create_informational_target_machine, create_target_machine};
+use context::SimpleCx;
 use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
 pub(crate) use llvm_util::target_features_cfg;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -116,9 +117,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         kind: AllocatorKind,
         alloc_error_handler_kind: AllocatorKind,
     ) -> ModuleLlvm {
-        let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        let cx =
+            SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size);
         unsafe {
-            allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
+            allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind);
         }
         module_llvm
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index fa4adfd0b43e..2738fee64cf9 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1147,7 +1147,7 @@ unsafe extern "C" {
     pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
     pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
     pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
-    pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
+    pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
 
     // Operations on attributes
     pub(crate) fn LLVMCreateStringAttribute(

From 29440b84a9f1eb216ce3c937bbd9cc126078a437 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 12:23:45 +0000
Subject: [PATCH 08/27] Remove an unused lifetime param

---
 compiler/rustc_codegen_gcc/src/abi.rs            | 2 +-
 compiler/rustc_codegen_llvm/src/abi.rs           | 2 +-
 compiler/rustc_codegen_ssa/src/traits/abi.rs     | 2 +-
 compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 717baebcd8cd..9fe6baa3d257 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -16,7 +16,7 @@ use crate::context::CodegenCx;
 use crate::intrinsic::ArgAbiExt;
 use crate::type_of::LayoutGccExt;
 
-impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+impl AbiBuilderMethods for Builder<'_, '_, '_> {
     fn get_param(&mut self, index: usize) -> Self::Value {
         let func = self.current_func();
         let param = func.get_param(index as i32);
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 8c75125e009b..710593381513 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -654,7 +654,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
     }
 }
 
-impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
+impl AbiBuilderMethods for Builder<'_, '_, '_> {
     fn get_param(&mut self, index: usize) -> Self::Value {
         llvm::get_param(self.llfn(), index as c_uint)
     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs
index 60d8f2a9ece4..49c51caa996e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/abi.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs
@@ -1,5 +1,5 @@
 use super::BackendTypes;
 
-pub trait AbiBuilderMethods<'tcx>: BackendTypes {
+pub trait AbiBuilderMethods: BackendTypes {
     fn get_param(&mut self, index: usize) -> Self::Value;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 99fd6b6510ff..5f91133d5b47 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -40,7 +40,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     + CoverageInfoBuilderMethods<'tcx>
     + DebugInfoBuilderMethods
     + ArgAbiBuilderMethods<'tcx>
-    + AbiBuilderMethods<'tcx>
+    + AbiBuilderMethods
     + IntrinsicCallBuilderMethods<'tcx>
     + AsmBuilderMethods<'tcx>
     + StaticBuilderMethods

From 241c83f0c7877815b592a276bb13af57fbb8d7fc Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 14:28:50 +0000
Subject: [PATCH 09/27] Deduplicate more functions between `SimpleCx` and
 `CodegenCx`

---
 compiler/rustc_codegen_llvm/src/builder.rs | 53 ++--------------------
 compiler/rustc_codegen_llvm/src/context.rs |  5 --
 2 files changed, 4 insertions(+), 54 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index aab63324f426..17579ebe72c4 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -119,49 +119,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
     }
 }
 
-impl<'a, 'll> SBuilder<'a, 'll> {
-    fn check_call<'b>(
-        &mut self,
-        typ: &str,
-        fn_ty: &'ll Type,
-        llfn: &'ll Value,
-        args: &'b [&'ll Value],
-    ) -> Cow<'b, [&'ll Value]> {
-        assert!(
-            self.cx.type_kind(fn_ty) == TypeKind::Function,
-            "builder::{typ} not passed a function, but {fn_ty:?}"
-        );
-
-        let param_tys = self.cx.func_params_types(fn_ty);
-
-        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
-            .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
-
-        if all_args_match {
-            return Cow::Borrowed(args);
-        }
-
-        let casted_args: Vec<_> = iter::zip(param_tys, args)
-            .enumerate()
-            .map(|(i, (expected_ty, &actual_val))| {
-                let actual_ty = self.cx.val_ty(actual_val);
-                if expected_ty != actual_ty {
-                    debug!(
-                        "type mismatch in function call of {:?}. \
-                            Expected {:?} for param {}, got {:?}; injecting bitcast",
-                        llfn, expected_ty, i, actual_ty
-                    );
-                    self.bitcast(actual_val, expected_ty)
-                } else {
-                    actual_val
-                }
-            })
-            .collect();
-
-        Cow::Owned(casted_args)
-    }
-}
-
 /// Empty string, to be used where LLVM expects an instruction name, indicating
 /// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
 // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
@@ -1610,9 +1567,7 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
         let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) };
         ret.expect("LLVM does not have support for catchret")
     }
-}
 
-impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn check_call<'b>(
         &mut self,
         typ: &str,
@@ -1627,7 +1582,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         let param_tys = self.cx.func_params_types(fn_ty);
 
-        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.val_ty(v)))
+        let all_args_match = iter::zip(&param_tys, args.iter().map(|&v| self.cx.val_ty(v)))
             .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
 
         if all_args_match {
@@ -1637,7 +1592,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         let casted_args: Vec<_> = iter::zip(param_tys, args)
             .enumerate()
             .map(|(i, (expected_ty, &actual_val))| {
-                let actual_ty = self.val_ty(actual_val);
+                let actual_ty = self.cx.val_ty(actual_val);
                 if expected_ty != actual_ty {
                     debug!(
                         "type mismatch in function call of {:?}. \
@@ -1653,12 +1608,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         Cow::Owned(casted_args)
     }
-}
-impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
+
     pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
     }
 }
+
 impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
         let (ty, f) = self.cx.get_intrinsic(intrinsic);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 6a7c042e03af..c3f8f60eb5ec 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -8,7 +8,6 @@ use std::str;
 use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx};
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
-use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::errors as ssa_errors;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
@@ -682,10 +681,6 @@ impl<'ll> SimpleCx<'ll> {
             llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
         })
     }
-
-    pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind {
-        unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
-    }
 }
 
 impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {

From f16f64b15a51789984d9014e92e86fb3a2fe8ce0 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 14:33:55 +0000
Subject: [PATCH 10/27] Remove inherent function that has a trait method
 duplicate of a commonly imported trait

---
 compiler/rustc_codegen_llvm/src/asm.rs           |  7 +------
 .../rustc_codegen_llvm/src/builder/autodiff.rs   |  1 +
 compiler/rustc_codegen_llvm/src/context.rs       | 16 +++++++---------
 .../src/coverageinfo/mapgen/covfun.rs            |  2 +-
 4 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index be5673eddf93..5fc99ced9937 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1,6 +1,5 @@
 use std::assert_matches::assert_matches;
 
-use libc::{c_char, c_uint};
 use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
@@ -512,11 +511,7 @@ pub(crate) fn inline_asm_call<'ll>(
             // Store mark in a metadata node so we can map LLVM errors
             // back to source locations. See #17552.
             let key = "srcloc";
-            let kind = llvm::LLVMGetMDKindIDInContext(
-                bx.llcx,
-                key.as_ptr().cast::<c_char>(),
-                key.len() as c_uint,
-            );
+            let kind = bx.get_md_kind_id(key);
 
             // `srcloc` contains one 64-bit integer for each line of assembly code,
             // where the lower 32 bits hold the lo byte position and the upper 32 bits
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 1e12d1a1cb3e..71705ecb4d0f 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -3,6 +3,7 @@ use std::ptr;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::back::write::ModuleConfig;
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_errors::FatalError;
 use tracing::{debug, trace};
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index c3f8f60eb5ec..a4e88e5a23f7 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -32,7 +32,7 @@ use smallvec::SmallVec;
 
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
-use crate::common::{self, AsCCharPtr};
+use crate::common::AsCCharPtr;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
 use crate::llvm::{Metadata, MetadataType};
 use crate::type_::Type;
@@ -652,24 +652,22 @@ impl<'ll> SimpleCx<'ll> {
         let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits());
         Self(SCx { llmod, llcx, isize_ty }, PhantomData)
     }
+}
 
-    pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type {
-        common::val_ty(v)
-    }
-
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
-        unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
+        unsafe { llvm::LLVMMetadataAsValue(self.llcx(), metadata) }
     }
 
     pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
         let name = SmallCStr::new(name);
-        unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) }
+        unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) }
     }
 
     pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 {
         unsafe {
             llvm::LLVMGetMDKindIDInContext(
-                self.llcx,
+                self.llcx(),
                 name.as_ptr() as *const c_char,
                 name.len() as c_uint,
             )
@@ -678,7 +676,7 @@ impl<'ll> SimpleCx<'ll> {
 
     pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
         Some(unsafe {
-            llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
+            llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
         })
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index c53ea6d46661..80e54bf045e2 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -8,7 +8,7 @@ use std::ffi::CString;
 
 use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
-    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+    BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods,
 };
 use rustc_middle::mir::coverage::{
     BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,

From 3565603d2522cb96f52b74dba3d64f5869a5ad4c Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 14:45:16 +0000
Subject: [PATCH 11/27] Use a safe wrapper around an LLVM FFI function

---
 compiler/rustc_codegen_llvm/src/asm.rs       |  2 +-
 compiler/rustc_codegen_llvm/src/consts.rs    |  2 +-
 compiler/rustc_codegen_llvm/src/context.rs   | 11 ++++++++---
 compiler/rustc_codegen_llvm/src/intrinsic.rs |  4 ++--
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs  |  2 +-
 5 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 5fc99ced9937..6f344e1ea2e2 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -533,7 +533,7 @@ pub(crate) fn inline_asm_call<'ll>(
                 ))
             }));
             let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len());
-            let md = llvm::LLVMMetadataAsValue(&bx.llcx, md);
+            let md = bx.get_metadata_value(md);
             llvm::LLVMSetMetadata(call, kind, md);
 
             Some(call)
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 330e8a8f4069..0dec0d869b0a 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -490,7 +490,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                         llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
                     let data = [section, alloc];
                     let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
-                    let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
+                    let val = self.get_metadata_value(meta);
                     llvm::LLVMAddNamedMetadataOperand(
                         self.llmod,
                         c"wasm.custom_sections".as_ptr(),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index a4e88e5a23f7..c8a55d5c03ac 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -656,7 +656,7 @@ impl<'ll> SimpleCx<'ll> {
 
 impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
-        unsafe { llvm::LLVMMetadataAsValue(self.llcx(), metadata) }
+        llvm::LLVMMetadataAsValue(self.llcx(), metadata)
     }
 
     pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
@@ -1225,9 +1225,14 @@ impl CodegenCx<'_, '_> {
 
 impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
-    pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) {
+    pub(crate) fn set_metadata<'a>(
+        &self,
+        val: &'a Value,
+        kind_id: MetadataType,
+        md: &'ll Metadata,
+    ) {
+        let node = self.get_metadata_value(md);
         unsafe {
-            let node = llvm::LLVMMetadataAsValue(self.llcx(), md);
             llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index dfbb5bc1731d..5e9f7f26f486 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -649,7 +649,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
     fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value {
         // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
         // optimization pass replaces calls to this intrinsic with code to test type membership.
-        let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) };
+        let typeid = self.get_metadata_value(typeid);
         self.call_intrinsic("llvm.type.test", &[pointer, typeid])
     }
 
@@ -659,7 +659,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         vtable_byte_offset: u64,
         typeid: &'ll Metadata,
     ) -> Self::Value {
-        let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) };
+        let typeid = self.get_metadata_value(typeid);
         let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
         let type_checked_load =
             self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 2738fee64cf9..7dc50eb68499 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1680,7 +1680,7 @@ unsafe extern "C" {
         Packed: Bool,
     );
 
-    pub(crate) fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
+    pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
     pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
 

From 553828c6f48adcf3f2443bf1972909db518e3c89 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Mon, 24 Feb 2025 14:38:55 +0000
Subject: [PATCH 12/27] Mark more LLVM FFI as safe

---
 compiler/rustc_codegen_llvm/src/asm.rs        | 93 ++++++++++---------
 compiler/rustc_codegen_llvm/src/builder.rs    |  4 +-
 compiler/rustc_codegen_llvm/src/context.rs    | 10 +-
 .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs |  3 +-
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs   | 16 +++-
 5 files changed, 68 insertions(+), 58 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 6f344e1ea2e2..6e931aa0bc76 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -482,12 +482,13 @@ pub(crate) fn inline_asm_call<'ll>(
 
     debug!("Asm Output Type: {:?}", output);
     let fty = bx.cx.type_func(&argtys, output);
-    unsafe {
-        // Ask LLVM to verify that the constraints are well-formed.
-        let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len());
-        debug!("constraint verification result: {:?}", constraints_ok);
-        if constraints_ok {
-            let v = llvm::LLVMRustInlineAsm(
+    // Ask LLVM to verify that the constraints are well-formed.
+    let constraints_ok =
+        unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) };
+    debug!("constraint verification result: {:?}", constraints_ok);
+    if constraints_ok {
+        let v = unsafe {
+            llvm::LLVMRustInlineAsm(
                 fty,
                 asm.as_c_char_ptr(),
                 asm.len(),
@@ -497,50 +498,50 @@ pub(crate) fn inline_asm_call<'ll>(
                 alignstack,
                 dia,
                 can_throw,
-            );
-
-            let call = if !labels.is_empty() {
-                assert!(catch_funclet.is_none());
-                bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
-            } else if let Some((catch, funclet)) = catch_funclet {
-                bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
-            } else {
-                bx.call(fty, None, None, v, inputs, None, None)
-            };
+            )
+        };
 
-            // Store mark in a metadata node so we can map LLVM errors
-            // back to source locations. See #17552.
-            let key = "srcloc";
-            let kind = bx.get_md_kind_id(key);
+        let call = if !labels.is_empty() {
+            assert!(catch_funclet.is_none());
+            bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
+        } else if let Some((catch, funclet)) = catch_funclet {
+            bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None)
+        } else {
+            bx.call(fty, None, None, v, inputs, None, None)
+        };
 
-            // `srcloc` contains one 64-bit integer for each line of assembly code,
-            // where the lower 32 bits hold the lo byte position and the upper 32 bits
-            // hold the hi byte position.
-            let mut srcloc = vec![];
-            if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
-                // LLVM inserts an extra line to add the ".intel_syntax", so add
-                // a dummy srcloc entry for it.
-                //
-                // Don't do this if we only have 1 line span since that may be
-                // due to the asm template string coming from a macro. LLVM will
-                // default to the first srcloc for lines that don't have an
-                // associated srcloc.
-                srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
-            }
-            srcloc.extend(line_spans.iter().map(|span| {
-                llvm::LLVMValueAsMetadata(bx.const_u64(
-                    u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32),
-                ))
-            }));
-            let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len());
-            let md = bx.get_metadata_value(md);
-            llvm::LLVMSetMetadata(call, kind, md);
+        // Store mark in a metadata node so we can map LLVM errors
+        // back to source locations. See #17552.
+        let key = "srcloc";
+        let kind = bx.get_md_kind_id(key);
 
-            Some(call)
-        } else {
-            // LLVM has detected an issue with our constraints, bail out
-            None
+        // `srcloc` contains one 64-bit integer for each line of assembly code,
+        // where the lower 32 bits hold the lo byte position and the upper 32 bits
+        // hold the hi byte position.
+        let mut srcloc = vec![];
+        if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
+            // LLVM inserts an extra line to add the ".intel_syntax", so add
+            // a dummy srcloc entry for it.
+            //
+            // Don't do this if we only have 1 line span since that may be
+            // due to the asm template string coming from a macro. LLVM will
+            // default to the first srcloc for lines that don't have an
+            // associated srcloc.
+            srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
         }
+        srcloc.extend(line_spans.iter().map(|span| {
+            llvm::LLVMValueAsMetadata(
+                bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
+            )
+        }));
+        let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
+        let md = bx.get_metadata_value(md);
+        llvm::LLVMSetMetadata(call, kind, md);
+
+        Some(call)
+    } else {
+        // LLVM has detected an issue with our constraints, bail out
+        None
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 17579ebe72c4..7e8b2467989d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -311,8 +311,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // This function handles switch instructions with more than 2 targets and it needs to
         // emit branch weights metadata instead of using the intrinsic.
         // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic.
-        let cold_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(1)) };
-        let hot_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)) };
+        let cold_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(1));
+        let hot_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(2000));
         let weight =
             |is_cold: bool| -> &Metadata { if is_cold { cold_weight } else { hot_weight } };
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index c8a55d5c03ac..ecef54d31659 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -34,7 +34,7 @@ use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
 use crate::common::AsCCharPtr;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
-use crate::llvm::{Metadata, MetadataType};
+use crate::llvm::Metadata;
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util};
@@ -664,7 +664,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) }
     }
 
-    pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 {
+    pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId {
         unsafe {
             llvm::LLVMGetMDKindIDInContext(
                 self.llcx(),
@@ -1228,13 +1228,11 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn set_metadata<'a>(
         &self,
         val: &'a Value,
-        kind_id: MetadataType,
+        kind_id: impl Into<llvm::MetadataKindId>,
         md: &'ll Metadata,
     ) {
         let node = self.get_metadata_value(md);
-        unsafe {
-            llvm::LLVMSetMetadata(val, kind_id as c_uint, node);
-        }
+        llvm::LLVMSetMetadata(val, kind_id.into(), node);
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 3c2c6964a3d7..ac8d4e572837 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -3,13 +3,14 @@
 
 use libc::{c_char, c_uint};
 
+use super::MetadataKindId;
 use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
 use crate::llvm::Bool;
 
 #[link(name = "llvm-wrapper", kind = "static")]
 unsafe extern "C" {
     // Enzyme
-    pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
+    pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool;
     pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
     pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
     pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 7dc50eb68499..6801f21aa77c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -976,6 +976,16 @@ pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void);
 pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
 pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void;
 
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct MetadataKindId(c_uint);
+
+impl From<MetadataType> for MetadataKindId {
+    fn from(value: MetadataType) -> Self {
+        Self(value as c_uint)
+    }
+}
+
 unsafe extern "C" {
     // Create and destroy contexts.
     pub(crate) fn LLVMContextDispose(C: &'static mut Context);
@@ -983,7 +993,7 @@ unsafe extern "C" {
         C: &Context,
         Name: *const c_char,
         SLen: c_uint,
-    ) -> c_uint;
+    ) -> MetadataKindId;
 
     // Create modules.
     pub(crate) fn LLVMModuleCreateWithNameInContext(
@@ -1051,9 +1061,9 @@ unsafe extern "C" {
     pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
     pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
     pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
-    pub(crate) fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+    pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value);
     pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
-    pub(crate) fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
+    pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
 
     // Operations on constants of any type
     pub(crate) fn LLVMConstNull(Ty: &Type) -> &Value;

From b5562c04e73590c8eefa67400aba022ff7b61f25 Mon Sep 17 00:00:00 2001
From: Noratrieb <48135649+Noratrieb@users.noreply.github.com>
Date: Mon, 3 Mar 2025 20:14:16 +0100
Subject: [PATCH 13/27] Remove i586-pc-windows-msvc

See MCP 840.

I left a specialized error message that should help users that hit this
in the wild (for example, because they use it in their CI).
---
 compiler/rustc_target/src/spec/mod.rs                 | 11 +++++++++--
 .../src/spec/targets/i586_pc_windows_msvc.rs          |  9 ---------
 src/ci/github-actions/jobs.yml                        |  2 +-
 src/doc/rustc/src/platform-support.md                 |  1 -
 src/tools/build-manifest/src/main.rs                  |  1 -
 .../stack-protector/stack-protector-target-support.rs |  6 +-----
 tests/assembly/targets/targets-pe.rs                  |  3 ---
 7 files changed, 11 insertions(+), 22 deletions(-)
 delete mode 100644 compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs

diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index cc8162a2f27e..1edc66bb9f96 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1915,7 +1915,6 @@ supported_targets! {
     ("i686-pc-windows-msvc", i686_pc_windows_msvc),
     ("i686-uwp-windows-msvc", i686_uwp_windows_msvc),
     ("i686-win7-windows-msvc", i686_win7_windows_msvc),
-    ("i586-pc-windows-msvc", i586_pc_windows_msvc),
     ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc),
     ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc),
 
@@ -3503,7 +3502,15 @@ impl Target {
                     return load_file(&p);
                 }
 
-                Err(format!("Could not find specification for target {target_tuple:?}"))
+                // Leave in a specialized error message for the removed target.
+                // FIXME: If you see this and it's been a few months after this has been released,
+                // you can probably remove it.
+                if target_tuple == "i586-pc-windows-msvc" {
+                    Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\
+                        Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into())
+                } else {
+                    Err(format!("Could not find specification for target {target_tuple:?}"))
+                }
             }
             TargetTuple::TargetJson { ref contents, .. } => {
                 let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
deleted file mode 100644
index 394e6f9e6bf6..000000000000
--- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use crate::spec::Target;
-
-pub(crate) fn target() -> Target {
-    let mut base = super::i686_pc_windows_msvc::target();
-    base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target
-    base.cpu = "pentium".into();
-    base.llvm_target = "i586-pc-windows-msvc".into();
-    base
-}
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index bbcc01a0c299..aff374654dc7 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -591,7 +591,7 @@ auto:
       RUST_CONFIGURE_ARGS: >-
         --build=i686-pc-windows-msvc
         --host=i686-pc-windows-msvc
-        --target=i686-pc-windows-msvc,i586-pc-windows-msvc
+        --target=i686-pc-windows-msvc
         --enable-full-tools
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index c4e5c1aac2f5..487fb94c229e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -162,7 +162,6 @@ target | std | notes
 [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
 [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
 [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
-`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI]
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index cd5ca74f8ade..dfc8f3bc7e0d 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[
     "bpfeb-unknown-none",
     "bpfel-unknown-none",
     "i386-apple-ios",
-    "i586-pc-windows-msvc",
     "i586-unknown-linux-gnu",
     "i586-unknown-linux-musl",
     "i586-unknown-redox",
diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs
index e9ba0f9ba899..a937256a60f8 100644
--- a/tests/assembly/stack-protector/stack-protector-target-support.rs
+++ b/tests/assembly/stack-protector/stack-protector-target-support.rs
@@ -3,7 +3,7 @@
 //
 //@ add-core-stubs
 //@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23
-//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33     r35 r36 r37 r38 r39 r40 r41 r42 r43 r44
+//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33         r36 r37 r38 r39 r40 r41 r42 r43 r44
 //@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65
 //@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85
 //@ assembly-output: emit-asm
@@ -73,9 +73,6 @@
 //@ [r32] needs-llvm-components: arm
 //@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf
 //@ [r33] needs-llvm-components: arm
-
-//@ [r35] compile-flags: --target i586-pc-windows-msvc
-//@ [r35] needs-llvm-components: x86
 //@ [r36] compile-flags: --target i586-unknown-linux-gnu
 //@ [r36] needs-llvm-components: x86
 //@ [r37] compile-flags: --target i586-unknown-linux-musl
@@ -195,7 +192,6 @@ pub fn foo() {
     // r3: calll @__security_check_cookie
     // r7: callq __security_check_cookie
     // r13: bl __security_check_cookie
-    // r35: calll @__security_check_cookie
 
     // cuda doesn't support stack-smash protection
     // r49-NOT: __security_check_cookie
diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs
index f895b79ba507..de29b9af5020 100644
--- a/tests/assembly/targets/targets-pe.rs
+++ b/tests/assembly/targets/targets-pe.rs
@@ -25,9 +25,6 @@
 //@ revisions: bpfel_unknown_none
 //@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none
 //@ [bpfel_unknown_none] needs-llvm-components: bpf
-//@ revisions: i586_pc_windows_msvc
-//@ [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc
-//@ [i586_pc_windows_msvc] needs-llvm-components: x86
 //@ revisions: i686_pc_windows_gnu
 //@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu
 //@ [i686_pc_windows_gnu] needs-llvm-components: x86

From cf95a4d24b9deade97dd818920ce1d031211d2c8 Mon Sep 17 00:00:00 2001
From: Arjun Ramesh <arjunr2@andrew.cmu.edu>
Date: Tue, 2 Jul 2024 18:19:42 -0400
Subject: [PATCH 14/27] Target definition for `wasm32-wali-linux-musl` to
 support the Wasm Linux Interface

This commit does not patch libc, stdarch, or cc
---
 .../rustc_target/src/spec/base/linux_wasm.rs  | 159 ++++++++++++++++++
 compiler/rustc_target/src/spec/base/mod.rs    |   1 +
 compiler/rustc_target/src/spec/mod.rs         |   1 +
 .../spec/targets/wasm32_wali_linux_musl.rs    |  29 ++++
 library/core/src/ffi/primitives.rs            |   5 +-
 library/unwind/src/libunwind.rs               |   3 +
 src/bootstrap/configure.py                    |   5 +
 src/bootstrap/src/core/build_steps/compile.rs |  48 ++++--
 src/bootstrap/src/core/sanity.rs              |   1 +
 src/doc/rustc/src/SUMMARY.md                  |   1 +
 src/doc/rustc/src/platform-support.md         |   1 +
 .../src/platform-support/wasm32-wali-linux.md |  98 +++++++++++
 tests/assembly/targets/targets-elf.rs         |   3 +
 tests/run-make/musl-default-linking/rmake.rs  |  15 +-
 14 files changed, 351 insertions(+), 19 deletions(-)
 create mode 100644 compiler/rustc_target/src/spec/base/linux_wasm.rs
 create mode 100644 compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
 create mode 100644 src/doc/rustc/src/platform-support/wasm32-wali-linux.md

diff --git a/compiler/rustc_target/src/spec/base/linux_wasm.rs b/compiler/rustc_target/src/spec/base/linux_wasm.rs
new file mode 100644
index 000000000000..a8c137c22a97
--- /dev/null
+++ b/compiler/rustc_target/src/spec/base/linux_wasm.rs
@@ -0,0 +1,159 @@
+//! This target is a confluence of Linux and Wasm models, inheriting most
+//! aspects from their respective base targets
+
+use crate::spec::{
+    Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel,
+    add_link_args, crt_objects, cvs,
+};
+
+pub(crate) fn opts() -> TargetOptions {
+    macro_rules! args {
+        ($prefix:literal) => {
+            &[
+                // By default LLD only gives us one page of stack (64k) which is a
+                // little small. Default to a larger stack closer to other PC platforms
+                // (1MB) and users can always inject their own link-args to override this.
+                concat!($prefix, "-z"),
+                concat!($prefix, "stack-size=1048576"),
+                // By default LLD's memory layout is:
+                //
+                // 1. First, a blank page
+                // 2. Next, all static data
+                // 3. Finally, the main stack (which grows down)
+                //
+                // This has the unfortunate consequence that on stack overflows you
+                // corrupt static data and can cause some exceedingly weird bugs. To
+                // help detect this a little sooner we instead request that the stack is
+                // placed before static data.
+                //
+                // This means that we'll generate slightly larger binaries as references
+                // to static data will take more bytes in the ULEB128 encoding, but
+                // stack overflow will be guaranteed to trap as it underflows instead of
+                // corrupting static data.
+                concat!($prefix, "--stack-first"),
+                // FIXME we probably shouldn't pass this but instead pass an explicit list
+                // of symbols we'll allow to be undefined. We don't currently have a
+                // mechanism of knowing, however, which symbols are intended to be imported
+                // from the environment and which are intended to be imported from other
+                // objects linked elsewhere. This is a coarse approximation but is sure to
+                // hide some bugs and frustrate someone at some point, so we should ideally
+                // work towards a world where we can explicitly list symbols that are
+                // supposed to be imported and have all other symbols generate errors if
+                // they remain undefined.
+                concat!($prefix, "--allow-undefined"),
+                // LLD only implements C++-like demangling, which doesn't match our own
+                // mangling scheme. Tell LLD to not demangle anything and leave it up to
+                // us to demangle these symbols later. Currently rustc does not perform
+                // further demangling, but tools like twiggy and wasm-bindgen are intended
+                // to do so.
+                concat!($prefix, "--no-demangle"),
+            ]
+        };
+    }
+
+    let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
+    add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
+
+    TargetOptions {
+        is_like_wasm: true,
+        families: cvs!["wasm", "unix"],
+        os: "linux".into(),
+        env: "musl".into(),
+
+        // we allow dynamic linking, but only cdylibs. Basically we allow a
+        // final library artifact that exports some symbols (a wasm module) but
+        // we don't allow intermediate `dylib` crate types
+        dynamic_linking: true,
+        only_cdylib: true,
+
+        // relatively self-explanatory!
+        exe_suffix: ".wasm".into(),
+        dll_prefix: "".into(),
+        dll_suffix: ".wasm".into(),
+        eh_frame_header: false,
+
+        max_atomic_width: Some(64),
+
+        // Unwinding doesn't work right now, so the whole target unconditionally
+        // defaults to panic=abort. Note that this is guaranteed to change in
+        // the future once unwinding is implemented. Don't rely on this as we're
+        // basically guaranteed to change it once WebAssembly supports
+        // exceptions.
+        panic_strategy: PanicStrategy::Abort,
+
+        // Symbol visibility takes care of this for the WebAssembly.
+        // Additionally the only known linker, LLD, doesn't support the script
+        // arguments just yet
+        limit_rdylib_exports: false,
+
+        // we use the LLD shipped with the Rust toolchain by default
+        linker: Some("rust-lld".into()),
+        linker_flavor: LinkerFlavor::WasmLld(Cc::No),
+
+        pre_link_args,
+
+        // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
+        //
+        // rust-lang/rust#104137: cannot blindly remove this without putting in
+        // some other way to compensate for lack of `-nostartfiles` in linker
+        // invocation.
+        link_self_contained: LinkSelfContainedDefault::True,
+        pre_link_objects_self_contained: crt_objects::pre_wasi_self_contained(),
+        post_link_objects_self_contained: crt_objects::post_wasi_self_contained(),
+
+        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
+        // PIC code is implemented this has quite a drastic effect if it stays
+        // at the default, `pic`. In an effort to keep wasm binaries as minimal
+        // as possible we're defaulting to `static` for now, but the hope is
+        // that eventually we can ship a `pic`-compatible standard library which
+        // works with `static` as well (or works with some method of generating
+        // non-relative calls and such later on).
+        relocation_model: RelocModel::Static,
+
+        // When the atomics feature is activated then these two keys matter,
+        // otherwise they're basically ignored by the standard library. In this
+        // mode, however, the `#[thread_local]` attribute works (i.e.
+        // `has_thread_local`) and we need to get it to work by specifying
+        // `local-exec` as that's all that's implemented in LLVM today for wasm.
+        has_thread_local: true,
+        tls_model: TlsModel::LocalExec,
+
+        // Supporting Linux requires multithreading supported by Wasm's thread
+        // proposal
+        singlethread: false,
+
+        // gdb scripts don't work on wasm blobs
+        emit_debug_gdb_scripts: false,
+
+        // There's more discussion of this at
+        // https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is
+        // that this isn't useful for wasm and has tricky issues with
+        // representation, so this is disabled.
+        generate_arange_section: false,
+
+        // Right now this is a bit of a workaround but we're currently saying that
+        // the target by default has a static crt which we're taking as a signal
+        // for "use the bundled crt". If that's turned off then the system's crt
+        // will be used, but this means that default usage of this target doesn't
+        // need an external compiler but it's still interoperable with an external
+        // compiler if configured correctly.
+        crt_static_default: true,
+        crt_static_respected: true,
+
+        // Allow `+crt-static` to create a "cdylib" output which is just a wasm file
+        // without a main function.
+        crt_static_allows_dylibs: true,
+
+        // Wasm start ignores arguments -- relies on API call from interface.
+        main_needs_argc_argv: false,
+
+        // Wasm toolchains mangle the name of "main" to distinguish between different
+        // signatures.
+        entry_name: "__main_void".into(),
+
+        // Wasm Feature flags for supporting Linux
+        features: "+atomics,+bulk-memory,+mutable-globals,+sign-ext".into(),
+
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs
index 6f88be5d37f1..e8fdc8717853 100644
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
@@ -18,6 +18,7 @@ pub(crate) mod linux_gnu;
 pub(crate) mod linux_musl;
 pub(crate) mod linux_ohos;
 pub(crate) mod linux_uclibc;
+pub(crate) mod linux_wasm;
 pub(crate) mod msvc;
 pub(crate) mod netbsd;
 pub(crate) mod nto_qnx;
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index cc8162a2f27e..47044ce9321b 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1925,6 +1925,7 @@ supported_targets! {
     ("wasm32-wasip1", wasm32_wasip1),
     ("wasm32-wasip2", wasm32_wasip2),
     ("wasm32-wasip1-threads", wasm32_wasip1_threads),
+    ("wasm32-wali-linux-musl", wasm32_wali_linux_musl),
     ("wasm64-unknown-unknown", wasm64_unknown_unknown),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
new file mode 100644
index 000000000000..663c17b05e5e
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
@@ -0,0 +1,29 @@
+//! The `wasm32-wali-linux-musl` target is a wasm32 target compliant with the
+//! [WebAssembly Linux Interface](https://github.com/arjunr2/WALI).
+
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
+
+pub(crate) fn target() -> Target {
+    let mut options = base::linux_wasm::opts();
+
+    options
+        .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]);
+    options.add_pre_link_args(
+        LinkerFlavor::WasmLld(Cc::Yes),
+        &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"],
+    );
+
+    Target {
+        llvm_target: "wasm32-wasi".into(),
+        metadata: TargetMetadata {
+            description: Some("WebAssembly Linux Interface with musl-libc".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None,
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        arch: "wasm32".into(),
+        options,
+    }
+}
diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs
index ece3c7538dab..df9a6bb81c8b 100644
--- a/library/core/src/ffi/primitives.rs
+++ b/library/core/src/ffi/primitives.rs
@@ -129,7 +129,10 @@ mod c_char_definition {
 
 mod c_long_definition {
     cfg_if! {
-        if #[cfg(all(target_pointer_width = "64", not(windows)))] {
+        if #[cfg(any(
+            all(target_pointer_width = "64", not(windows)),
+            // wasm32 Linux ABI uses 64-bit long
+            all(target_arch = "wasm32", target_os = "linux")))] {
             pub(super) type c_long = i64;
             pub(super) type c_ulong = u64;
         } else {
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index 1a640bbde71d..7b752af96b08 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -81,6 +81,9 @@ pub const unwinder_private_data_size: usize = 35;
 #[cfg(target_arch = "loongarch64")]
 pub const unwinder_private_data_size: usize = 2;
 
+#[cfg(target_arch = "wasm32")]
+pub const unwinder_private_data_size: usize = 2;
+
 #[repr(C)]
 pub struct _Unwind_Exception {
     pub exception_class: _Unwind_Exception_Class,
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index e3f58d97cbc4..fdf8d1d6d972 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -269,6 +269,11 @@ def v(*args):
     "target.loongarch64-unknown-linux-musl.musl-root",
     "loongarch64-unknown-linux-musl install directory",
 )
+v(
+    "musl-root-wali-wasm32",
+    "target.wasm32-wali-linux-musl.musl-root",
+    "wasm32-wali-linux-musl install directory",
+)
 v(
     "qemu-armhf-rootfs",
     "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 782195007374..5eebba56f878 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -390,24 +390,38 @@ fn copy_self_contained_objects(
         let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
             panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
         });
-        for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
-            copy_and_stamp(
-                builder,
-                &libdir_self_contained,
-                &srcdir,
-                obj,
-                &mut target_deps,
-                DependencyType::TargetSelfContained,
-            );
-        }
-        let crt_path = builder.ensure(llvm::CrtBeginEnd { target });
-        for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
-            let src = crt_path.join(obj);
-            let target = libdir_self_contained.join(obj);
-            builder.copy_link(&src, &target);
-            target_deps.push((target, DependencyType::TargetSelfContained));
+        if !target.starts_with("wasm32") {
+            for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
+                copy_and_stamp(
+                    builder,
+                    &libdir_self_contained,
+                    &srcdir,
+                    obj,
+                    &mut target_deps,
+                    DependencyType::TargetSelfContained,
+                );
+            }
+            let crt_path = builder.ensure(llvm::CrtBeginEnd { target });
+            for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
+                let src = crt_path.join(obj);
+                let target = libdir_self_contained.join(obj);
+                builder.copy_link(&src, &target);
+                target_deps.push((target, DependencyType::TargetSelfContained));
+            }
+        } else {
+            // For wasm32 targets, we need to copy the libc.a and crt1-command.o files from the
+            // musl-libdir, but we don't need the other files.
+            for &obj in &["libc.a", "crt1-command.o"] {
+                copy_and_stamp(
+                    builder,
+                    &libdir_self_contained,
+                    &srcdir,
+                    obj,
+                    &mut target_deps,
+                    DependencyType::TargetSelfContained,
+                );
+            }
         }
-
         if !target.starts_with("s390x") {
             let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
             target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index fdac7f3cb179..583b8e1198ae 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -34,6 +34,7 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
+    "wasm32-wali-linux-musl",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 6c7cdec34802..bc1a12fa7601 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -95,6 +95,7 @@
     - [wasm32-wasip1](platform-support/wasm32-wasip1.md)
     - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md)
     - [wasm32-wasip2](platform-support/wasm32-wasip2.md)
+    - [wasm32-wali-linux-musl](platform-support/wasm32-wali-linux.md)
     - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md)
     - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md)
     - [wasm32v1-none](platform-support/wasm32v1-none.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index c4e5c1aac2f5..c404d116db88 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -405,6 +405,7 @@ target | std | host | notes
 [`thumbv8m.main-nuttx-eabi`](platform-support/nuttx.md) | ✓ |  | ARMv8M Mainline with NuttX
 [`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | ✓ |  | ARMv8M Mainline with NuttX, hardfloat
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
+[`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? |  | WebAssembly with [WALI](https://github.com/arjunr2/WALI)
 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
 [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ? |  | 64-bit x86 Cygwin |
diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md
new file mode 100644
index 000000000000..0c46ea2c01da
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md
@@ -0,0 +1,98 @@
+# `wasm32-wali-linux-*`
+
+**Tier: 3**
+
+WebAssembly targets that use the [WebAssembly Linux Interface (WALI)](https://github.com/arjunr2/WALI) with 32-bit memory. The latest status of the WALI specification and support are documented within the repo.
+
+WALI offers seamless targetability of traditional Linux applications to Wasm by exposing Linux syscalls strategically into the sandbox. Numerous applications and build system work unmodified over WALI, including complex low-level system libraries -- a list of applications are included in the research paper linked in the main repo.
+
+From the wider Wasm ecosystem perspective, implementing WALI within engines allows layering of high-level security policies (e.g. WASI) above it, arming the latter's implementations with sandboxing and portability.
+
+## Target maintainers
+
+- Arjun Ramesh [@arjunr2](https://github.com/arjunr2)
+
+## Requirements
+
+### Compilation
+This target is cross-compiled and requires an installation of the [WALI compiler/sysroot](https://github.com/arjunr2/WALI). This produces standard `wasm32` binaries with the WALI interface methods as module imports that need to be implemented by a supported engine (see the  "Execution" section below).
+
+`wali` targets *minimally require* the following LLVM feature flags:
+
+* [Bulk memory] - `+bulk-memory`
+* Mutable imported globals - `+mutable-globals`
+* [Sign-extending operations] - `+sign-ext`
+* [Threading/Atomics] - `+atomics`
+
+[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md
+[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md
+[Threading/Atomics]: https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md
+
+> **Note**: Users can expect that new enabled-by-default Wasm features for LLVM are transitively incorporatable into this target -- see [wasm32-unknown-unknown](wasm32-unknown-unknown.md) for detailed information on WebAssembly features.
+
+
+> **Note**: The WALI ABI is similar to default Clang wasm32 ABIs but *not identical*. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to mantain minimum source code changes for 64-bit host platforms currently supported. This may change in the future as the spec evolves.
+
+### Execution
+Running generated WALI binaries also requires a supported compliant engine implementation -- a working implementation in the [WebAssembly Micro-Runtime (WAMR)](https://github.com/arjunr2/WALI) is included in the repo.
+
+> **Note**: WALI is still somewhat experimental and bugs may exist in the Rust support, WALI toolchain, or the LLVM compiler. The former can be filed in Rust repos while the latter two in the WALI repo.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`, and pointing to the toolchain artifacts from the previous section ("Requirements->Compilation"). A sample `config.toml` for the `musl` environment will look like this, where `<WALI-root>` is the absolute path to the root directory of the [WALI repo](https://github.com/arjunr2/WALI):
+
+```toml
+[build]
+target = ["wasm32-wali-linux-musl"]
+
+[target.wasm32-wali-linux-musl]
+musl-root = "<WALI>/wali-musl/sysroot"
+llvm-config = "<WALI>/llvm-project/build/bin/llvm-config"
+cc = "<WALI>/llvm-project/build/bin/clang-18"
+cxx = "<WALI>/llvm-project/build/bin/clang-18"
+ar = "<WALI>/llvm-project/build/bin/llvm-ar"
+ranlib = "<WALI>/llvm-project/build/bin/llvm-ranlib"
+llvm-libunwind = "system"
+crt-static = true
+```
+
+> The `llvm-config` settings are only temporary, and the changes will eventually be upstreamed into LLVM
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+Rust program builds can use this target normally. Currently, linking WALI programs may require pointing the `linker` to the llvm build in the [Cargo config](https://doc.rust-lang.org/cargo/reference/config.html) (until LLVM is upstreamed). A `config.toml` for Cargo will look like the following:
+
+```toml
+[target.wasm32-wali-linux-musl]
+linker = "<WALI>/llvm-project/build/bin/lld"
+```
+
+Note that the following `cfg` directives are set for `wasm32-wali-linux-*`:
+
+* `cfg(target_arch = "wasm32")`
+* `cfg(target_family = {"wasm", "unix"})`
+* `cfg(target_r = "wasm")`
+* `cfg(target_os = "linux")`
+* `cfg(target_env = *)`
+
+### Restrictions
+
+Hardware or platform-specific support, besides `syscall` is mostly unsupported in WALI for ISA portability (these tend to be uncommon).
+
+## Testing
+
+Currently testing is not supported for `wali` targets and the Rust project doesn't run any tests for this target.
+
+However, standard ISA-agnostic tests for Linux should be thereotically reusable for WALI targets and minor changes. Testing integration will be continually incorporated as support evolves.
+
+
+## Cross-compilation toolchains and C code
+
+Most fully featured C code is compilable with the WALI toolchain -- examples can be seen in the repo.
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index dc564c60f807..5a72b5719505 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -556,6 +556,9 @@
 //@ revisions: wasm32_wasip1_threads
 //@ [wasm32_wasip1_threads] compile-flags: --target wasm32-wasip1-threads
 //@ [wasm32_wasip1_threads] needs-llvm-components: webassembly
+//@ revisions: wasm32_wali_linux_musl
+//@ [wasm32_wali_linux_musl] compile-flags: --target wasm32-wali-linux-musl
+//@ [wasm32_wali_linux_musl] needs-llvm-components: webassembly
 //@ revisions: wasm32_wasip2
 //@ [wasm32_wasip2] compile-flags: --target wasm32-wasip2
 //@ [wasm32_wasip2] needs-llvm-components: webassembly
diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs
index d203595a4474..017444cfcddc 100644
--- a/tests/run-make/musl-default-linking/rmake.rs
+++ b/tests/run-make/musl-default-linking/rmake.rs
@@ -45,8 +45,21 @@ fn main() {
 
         let target_spec: serde_json::Value =
             serde_json::from_str(&target_spec_json).expect("failed to parse target-spec-json");
-        let default = &target_spec["crt-static-default"];
 
+        let target_families = &target_spec["target-family"];
+        // WebAssembly doesn't support dynamic linking yet; all musl targets
+        // need to be statically linked.
+        if target_families
+            .as_array()
+            .expect("target-family wasn't an array")
+            .iter()
+            .filter_map(|x| x.as_str())
+            .any(|family| family == "wasm")
+        {
+            continue;
+        }
+
+        let default = &target_spec["crt-static-default"];
         // If the value is `null`, then the default to dynamically link from
         // musl_base was not overridden.
         if default.is_null() {

From 4e4bed8684a7144c82ea95aa013e7911dd9fe20d Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu@google.com>
Date: Thu, 6 Mar 2025 16:24:40 -0800
Subject: [PATCH 15/27] setTargetTriple now accepts Triple rather than string

---
 compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index aea2a8dd0978..6d01095cccad 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -153,7 +153,11 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) {
 
 extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M,
                                             const char *Triple) {
+#if LLVM_VERSION_GE(21, 0)
+  unwrap(M)->setTargetTriple(llvm::Triple(Triple::normalize(Triple)));
+#else
   unwrap(M)->setTargetTriple(Triple::normalize(Triple));
+#endif
 }
 
 extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) {

From 69aafd21f5abeb202a377f6b632b3204a2a76b9c Mon Sep 17 00:00:00 2001
From: tcpdumppy <847462026@qq.com>
Date: Fri, 7 Mar 2025 10:50:31 +0800
Subject: [PATCH 16/27] tests: fix some typos in comment

Signed-off-by: tcpdumppy <847462026@qq.com>
---
 tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs | 4 ++--
 tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs | 2 +-
 tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs   | 2 +-
 tests/ui/lint/unused/must-use-ops.rs                          | 2 +-
 tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs        | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
index 20999df9844e..db23dcd5e5eb 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-2.rs
@@ -1,10 +1,10 @@
 //@ check-pass
 
-// this test checks that the `dead_code` lint is *NOT* being emited
+// this test checks that the `dead_code` lint is *NOT* being emitted
 // for `foo` as `foo` is being used by `main`, and so the `#[expect]`
 // is unfulfilled
 //
-// it also checks that the `dead_code` lint is also *NOT* emited
+// it also checks that the `dead_code` lint is also *NOT* emitted
 // for `bar` as it's suppresed by the `#[expect]` on `bar`
 
 #![warn(dead_code)] // to override compiletest
diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
index 08103b233872..c4476e43e1ff 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557-3.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 
 // this test makes sure that the `unfulfilled_lint_expectations` lint
-// is being emited for `foo` as foo is not dead code, it's pub
+// is being emitted for `foo` as foo is not dead code, it's pub
 
 #![warn(dead_code)] // to override compiletest
 
diff --git a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
index f2625f0781f6..ea2e81261d10 100644
--- a/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
+++ b/tests/ui/lint/dead-code/allow-or-expect-dead_code-114557.rs
@@ -2,7 +2,7 @@
 //@ revisions: allow expect
 
 // this test checks that no matter if we put #[allow(dead_code)]
-// or #[expect(dead_code)], no warning is being emited
+// or #[expect(dead_code)], no warning is being emitted
 
 #![warn(dead_code)] // to override compiletest
 
diff --git a/tests/ui/lint/unused/must-use-ops.rs b/tests/ui/lint/unused/must-use-ops.rs
index f61cf0fcfcb4..5085dbb58c19 100644
--- a/tests/ui/lint/unused/must-use-ops.rs
+++ b/tests/ui/lint/unused/must-use-ops.rs
@@ -6,7 +6,7 @@
 #![feature(never_type)]
 
 fn deref_never(x: &!) {
-    // Don't lint for uninhabited typess
+    // Don't lint for uninhabited types
     *x;
 }
 
diff --git a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
index d7ade7f0e96c..009cc66f3f74 100644
--- a/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
+++ b/tests/ui/privacy/pub-priv-dep/priv-dep-issue-122756.rs
@@ -5,7 +5,7 @@
 #![deny(exported_private_dependencies)]
 
 // Ensure the libbar.rlib is loaded first. If the command line parameter `--extern foo` does not
-// exist, previus version would fail to compile
+// exist, previous version would fail to compile
 #![crate_type = "rlib"]
 extern crate bar;
 extern crate foo;

From 8814679a5410b8d9ce8385094ec8ec888395b1a5 Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu@google.com>
Date: Thu, 6 Mar 2025 22:52:20 -0800
Subject: [PATCH 17/27] rename Triple to Target

---
 compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 6d01095cccad..53df59930f4f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -152,11 +152,11 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) {
 }
 
 extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M,
-                                            const char *Triple) {
+                                            const char *Target) {
 #if LLVM_VERSION_GE(21, 0)
-  unwrap(M)->setTargetTriple(llvm::Triple(Triple::normalize(Triple)));
+  unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target)));
 #else
-  unwrap(M)->setTargetTriple(Triple::normalize(Triple));
+  unwrap(M)->setTargetTriple(Triple::normalize(Target));
 #endif
 }
 

From 872ac73f59465ccaf63f74fd12785c583d3aa0a6 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Fri, 7 Mar 2025 17:02:33 +1100
Subject: [PATCH 18/27] Move `visit_id` calls.

In `walk_item`, we call `visit_id` on every item kind. For most of them
we do it directly in `walk_item`. But for `ItemKind::Mod`,
`ItemKind::Enum`, and `ItemKind::Use` we instead do it in the `walk_*`
function called (via the `visit_*` function) from `walk_item`.

I can see no reason for this inconsistency, so this commit makes those
three cases like all the other cases, moving the `visit_id` calls into
`walk_item`. This also avoids the need for a few `HirId` arguments.
---
 compiler/rustc_hir/src/intravisit.rs     | 25 +++++++++---------------
 compiler/rustc_lint/src/late.rs          |  2 +-
 compiler/rustc_middle/src/hir/map.rs     |  2 +-
 compiler/rustc_passes/src/input_stats.rs |  4 ++--
 src/librustdoc/html/render/span_map.rs   |  2 +-
 5 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 41eb5b45bd1e..0aa07d96b3de 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -316,8 +316,8 @@ pub trait Visitor<'v>: Sized {
     fn visit_ident(&mut self, ident: Ident) -> Self::Result {
         walk_ident(self, ident)
     }
-    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> Self::Result {
-        walk_mod(self, m, n)
+    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result {
+        walk_mod(self, m)
     }
     fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
         walk_foreign_item(self, i)
@@ -464,8 +464,8 @@ pub trait Visitor<'v>: Sized {
     fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) -> Self::Result {
-        walk_enum_def(self, enum_definition, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result {
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result {
         walk_variant(self, v)
@@ -539,6 +539,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             visit_opt!(visitor, visit_name, orig_name);
         }
         ItemKind::Use(ref path, _) => {
+            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_use(path, item.hir_id()));
         }
         ItemKind::Static(ref typ, _, body) => {
@@ -566,7 +567,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_id(item.hir_id()));
         }
         ItemKind::Mod(ref module) => {
-            // `visit_mod()` takes care of visiting the `Item`'s `HirId`.
+            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
         }
         ItemKind::ForeignMod { abi: _, items } => {
@@ -587,9 +588,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_generics(generics));
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
+            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
-            // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
+            try_visit!(visitor.visit_enum_def(enum_definition));
         }
         ItemKind::Impl(Impl {
             constness: _,
@@ -638,12 +639,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul
     visitor.visit_name(ident.name)
 }
 
-pub fn walk_mod<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    module: &'v Mod<'v>,
-    mod_hir_id: HirId,
-) -> V::Result {
-    try_visit!(visitor.visit_id(mod_hir_id));
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result {
     walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied());
     V::Result::output()
 }
@@ -1145,7 +1141,6 @@ pub fn walk_use<'v, V: Visitor<'v>>(
     path: &'v UsePath<'v>,
     hir_id: HirId,
 ) -> V::Result {
-    try_visit!(visitor.visit_id(hir_id));
     let UsePath { segments, ref res, span } = *path;
     for &res in res {
         try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id));
@@ -1326,9 +1321,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>(
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     enum_definition: &'v EnumDef<'v>,
-    item_id: HirId,
 ) -> V::Result {
-    try_visit!(visitor.visit_id(item_id));
     walk_list!(visitor, visit_variant, enum_definition.variants);
     V::Result::output()
 }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index d22515d62d60..23d6efa05083 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -74,7 +74,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
 
     fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) {
         lint_callback!(self, check_mod, m, n);
-        hir_visit::walk_mod(self, m, n);
+        hir_visit::walk_mod(self, m);
     }
 }
 
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index fad8c7dcbcbc..c85af81ee25b 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -1356,7 +1356,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
             self.submodules.push(item.owner_id);
             // A module collector does not recurse inside nested modules.
             if self.crate_collector {
-                intravisit::walk_mod(self, module, item.hir_id());
+                intravisit::walk_mod(self, module);
             }
         } else {
             intravisit::walk_item(self, item)
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 92ea49f18e5d..8ff11197e09d 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -255,9 +255,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_body(self, b);
     }
 
-    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) {
+    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) {
         self.record("Mod", None, m);
-        hir_visit::walk_mod(self, m, n)
+        hir_visit::walk_mod(self, m)
     }
 
     fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index ce9c42c01cc7..bd8427261800 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -253,7 +253,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             // If it's a "mod foo {}", we want to look to its documentation page.
             self.extract_info_from_hir_id(id);
         }
-        intravisit::walk_mod(self, m, id);
+        intravisit::walk_mod(self, m);
     }
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {

From 8a981241fe86dfac2e8212638c87bbaf1ae53264 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Fri, 7 Mar 2025 17:37:23 +1100
Subject: [PATCH 19/27] Factor out repeated `visit_id` calls.

Every `ItemKind` now has one.
---
 compiler/rustc_hir/src/intravisit.rs | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 0aa07d96b3de..be9f490edcce 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -532,29 +532,25 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
 }
 
 pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
+    try_visit!(visitor.visit_id(item.hir_id()));
     try_visit!(visitor.visit_ident(item.ident));
     match item.kind {
         ItemKind::ExternCrate(orig_name) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             visit_opt!(visitor, visit_name, orig_name);
         }
         ItemKind::Use(ref path, _) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_use(path, item.hir_id()));
         }
         ItemKind::Static(ref typ, _, body) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Const(ref typ, ref generics, body) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(typ));
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_nested_body(body));
         }
         ItemKind::Fn { sig, generics, body: body_id, .. } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_fn(
                 FnKind::ItemFn(item.ident, generics, sig.header),
                 sig.decl,
@@ -563,19 +559,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
                 item.owner_id.def_id,
             ));
         }
-        ItemKind::Macro(..) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
-        }
+        ItemKind::Macro(..) => {}
         ItemKind::Mod(ref module) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
         }
         ItemKind::ForeignMod { abi: _, items } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             walk_list!(visitor, visit_foreign_item_ref, items);
         }
         ItemKind::GlobalAsm { asm: _, fake_body } => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             // Visit the fake body, which contains the asm statement.
             // Therefore we should not visit the asm statement again
             // outside of the body, or some visitors won't have their
@@ -583,12 +574,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_nested_body(fake_body));
         }
         ItemKind::TyAlias(ref ty, ref generics) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_ty_unambig(ty));
             try_visit!(visitor.visit_generics(generics));
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_enum_def(enum_definition));
         }
@@ -603,7 +592,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             self_ty,
             items,
         }) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             visit_opt!(visitor, visit_trait_ref, of_trait);
             try_visit!(visitor.visit_ty_unambig(self_ty));
@@ -612,17 +600,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_variant_data(struct_definition));
         }
         ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
         ItemKind::TraitAlias(ref generics, bounds) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(visitor.visit_generics(generics));
             walk_list!(visitor, visit_param_bound, bounds);
         }

From bbc80a819b542d751450bd82208438de5754ee47 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 7 Mar 2025 17:09:36 +0000
Subject: [PATCH 20/27] Delay bug for negative auto trait rather than ICEing

---
 .../src/check/always_applicable.rs            |  5 +++-
 tests/ui/auto-traits/ungated-impl.rs          |  7 ++++++
 tests/ui/auto-traits/ungated-impl.stderr      | 23 +++++++++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/auto-traits/ungated-impl.rs
 create mode 100644 tests/ui/auto-traits/ungated-impl.stderr

diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
index ba5b61d3fce0..8a841a115567 100644
--- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs
+++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
@@ -124,7 +124,10 @@ pub(crate) fn check_negative_auto_trait_impl<'tcx>(
                 // be implemented here to handle non-ADT rigid types.
                 Ok(())
             } else {
-                span_bug!(tcx.def_span(impl_def_id), "incoherent impl of negative auto trait");
+                Err(tcx.dcx().span_delayed_bug(
+                    tcx.def_span(impl_def_id),
+                    "incoherent impl of negative auto trait",
+                ))
             }
         }
     }
diff --git a/tests/ui/auto-traits/ungated-impl.rs b/tests/ui/auto-traits/ungated-impl.rs
new file mode 100644
index 000000000000..d46b4b01af9c
--- /dev/null
+++ b/tests/ui/auto-traits/ungated-impl.rs
@@ -0,0 +1,7 @@
+auto trait MyTrait {}
+//~^ ERROR auto traits are experimental and possibly buggy
+
+impl<T> !MyTrait for *mut T {}
+//~^ ERROR negative trait bounds are not fully implemented
+
+fn main() {}
diff --git a/tests/ui/auto-traits/ungated-impl.stderr b/tests/ui/auto-traits/ungated-impl.stderr
new file mode 100644
index 000000000000..9d10d46a9028
--- /dev/null
+++ b/tests/ui/auto-traits/ungated-impl.stderr
@@ -0,0 +1,23 @@
+error[E0658]: auto traits are experimental and possibly buggy
+  --> $DIR/ungated-impl.rs:1:1
+   |
+LL | auto trait MyTrait {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
+   = help: add `#![feature(auto_traits)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: negative trait bounds are not fully implemented; use marker types for now
+  --> $DIR/ungated-impl.rs:4:9
+   |
+LL | impl<T> !MyTrait for *mut T {}
+   |         ^^^^^^^^
+   |
+   = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information
+   = help: add `#![feature(negative_impls)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.

From bae468213296361d5e98b89e3a4f23a69b080f34 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 5 Mar 2025 14:43:36 +0000
Subject: [PATCH 21/27] Rename print_something to should_render

---
 .../rustc_attr_data_structures/src/lib.rs     | 40 +++++++++++--------
 compiler/rustc_macros/src/print_attribute.rs  | 10 ++---
 2 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index e4bb459e6df5..3a7cd6da8e30 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -35,13 +35,17 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStabl
 /// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
 /// representation much.
 pub trait PrintAttribute {
-    fn print_something(&self) -> bool;
+    /// Whether or not this will render as something meaningful, or if it's skipped
+    /// (which will force the containing struct to also skip printing a comma
+    /// and the field name).
+    fn should_render(&self) -> bool;
+
     fn print_attribute(&self, p: &mut Printer);
 }
 
 impl<T: PrintAttribute> PrintAttribute for &T {
-    fn print_something(&self) -> bool {
-        T::print_something(self)
+    fn should_render(&self) -> bool {
+        T::should_render(self)
     }
 
     fn print_attribute(&self, p: &mut Printer) {
@@ -49,9 +53,10 @@ impl<T: PrintAttribute> PrintAttribute for &T {
     }
 }
 impl<T: PrintAttribute> PrintAttribute for Option<T> {
-    fn print_something(&self) -> bool {
-        self.as_ref().is_some_and(|x| x.print_something())
+    fn should_render(&self) -> bool {
+        self.as_ref().is_some_and(|x| x.should_render())
     }
+
     fn print_attribute(&self, p: &mut Printer) {
         if let Some(i) = self {
             T::print_attribute(i, p)
@@ -59,9 +64,10 @@ impl<T: PrintAttribute> PrintAttribute for Option<T> {
     }
 }
 impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
-    fn print_something(&self) -> bool {
-        self.is_empty() || self[0].print_something()
+    fn should_render(&self) -> bool {
+        self.is_empty() || self[0].should_render()
     }
+
     fn print_attribute(&self, p: &mut Printer) {
         let mut last_printed = false;
         p.word("[");
@@ -70,7 +76,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
                 p.word_space(",");
             }
             i.print_attribute(p);
-            last_printed = i.print_something();
+            last_printed = i.should_render();
         }
         p.word("]");
     }
@@ -78,7 +84,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
 macro_rules! print_skip {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { false }
+            fn should_render(&self) -> bool { false }
             fn print_attribute(&self, _: &mut Printer) { }
         })*
     };
@@ -87,7 +93,7 @@ macro_rules! print_skip {
 macro_rules! print_disp {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { true }
+            fn should_render(&self) -> bool { true }
             fn print_attribute(&self, p: &mut Printer) {
                 p.word(format!("{}", self));
             }
@@ -97,7 +103,7 @@ macro_rules! print_disp {
 macro_rules! print_debug {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { true }
+            fn should_render(&self) -> bool { true }
             fn print_attribute(&self, p: &mut Printer) {
                 p.word(format!("{:?}", self));
             }
@@ -106,29 +112,29 @@ macro_rules! print_debug {
 }
 
 macro_rules! print_tup {
-    (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* };
+    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
     () => {};
     ($t: ident $($ts: ident)*) => {
         #[allow(non_snake_case, unused)]
         impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
-            fn print_something(&self) -> bool {
+            fn should_render(&self) -> bool {
                 let ($t, $($ts),*) = self;
-                print_tup!(num_print_something $t $($ts)*) != 0
+                print_tup!(num_should_render $t $($ts)*) != 0
             }
 
             fn print_attribute(&self, p: &mut Printer) {
                 let ($t, $($ts),*) = self;
-                let parens = print_tup!(num_print_something $t $($ts)*) > 1;
+                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
                 if parens {
                     p.word("(");
                 }
 
-                let mut printed_anything = $t.print_something();
+                let mut printed_anything = $t.should_render();
 
                 $t.print_attribute(p);
 
                 $(
-                    if printed_anything && $ts.print_something() {
+                    if $ts.should_render() {
                         p.word_space(",");
                         printed_anything = true;
                     }
diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs
index 3c6e30b851bf..fe78fb15cb95 100644
--- a/compiler/rustc_macros/src/print_attribute.rs
+++ b/compiler/rustc_macros/src/print_attribute.rs
@@ -16,7 +16,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 let name = field.ident.as_ref().unwrap();
                 let string_name = name.to_string();
                 disps.push(quote! {
-                    if __printed_anything && #name.print_something() {
+                    if __printed_anything && #name.should_render() {
                         __p.word_space(",");
                         __printed_anything = true;
                     }
@@ -31,7 +31,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 quote! { {#(#field_names),*} },
                 quote! {
                     __p.word(#string_name);
-                    if true #(&& !#field_names.print_something())* {
+                    if true #(&& !#field_names.should_render())* {
                         return;
                     }
 
@@ -48,7 +48,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
             for idx in 0..fields_unnamed.unnamed.len() {
                 let name = format_ident!("f{idx}");
                 disps.push(quote! {
-                    if __printed_anything && #name.print_something() {
+                    if __printed_anything && #name.should_render() {
                         __p.word_space(",");
                         __printed_anything = true;
                     }
@@ -62,7 +62,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 quote! {
                     __p.word(#string_name);
 
-                    if true #(&& !#field_names.print_something())* {
+                    if true #(&& !#field_names.should_render())* {
                         return;
                     }
 
@@ -138,7 +138,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
     input.gen_impl(quote! {
         #[allow(unused)]
         gen impl PrintAttribute for @Self {
-            fn print_something(&self) -> bool { #printed }
+            fn should_render(&self) -> bool { #printed }
             fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
         }
     })

From 9ae94534c9d8a891213797911443a06ab5923ead Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 5 Mar 2025 15:20:16 +0000
Subject: [PATCH 22/27] Fix pretty printing of parsed attrs in hir_pretty

---
 .../rustc_attr_data_structures/src/lib.rs     | 12 ++++++-----
 compiler/rustc_hir_pretty/src/lib.rs          |  4 ++--
 compiler/rustc_macros/src/print_attribute.rs  | 21 ++++++++++++-------
 tests/ui/unpretty/deprecated-attr.rs          |  2 --
 tests/ui/unpretty/deprecated-attr.stdout      | 21 ++++++++-----------
 5 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index 3a7cd6da8e30..65e5d83cf6fe 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -126,7 +126,7 @@ macro_rules! print_tup {
                 let ($t, $($ts),*) = self;
                 let parens = print_tup!(num_should_render $t $($ts)*) > 1;
                 if parens {
-                    p.word("(");
+                    p.popen();
                 }
 
                 let mut printed_anything = $t.should_render();
@@ -135,14 +135,16 @@ macro_rules! print_tup {
 
                 $(
                     if $ts.should_render() {
-                        p.word_space(",");
+                        if printed_anything {
+                            p.word_space(",");
+                        }
                         printed_anything = true;
                     }
                     $ts.print_attribute(p);
                 )*
 
                 if parens {
-                    p.word(")");
+                    p.pclose();
                 }
             }
         }
@@ -153,5 +155,5 @@ macro_rules! print_tup {
 
 print_tup!(A B C D E F G H);
 print_skip!(Span, ());
-print_disp!(Symbol, u16, bool, NonZero<u32>);
-print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
+print_disp!(u16, bool, NonZero<u32>);
+print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1f6fb3a329a5..63efb364684a 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -118,9 +118,9 @@ impl<'a> State<'a> {
                 self.hardbreak()
             }
             hir::Attribute::Parsed(pa) => {
-                self.word("#[attr=\"");
+                self.word("#[attr = ");
                 pa.print_attribute(self);
-                self.word("\")]");
+                self.word("]");
                 self.hardbreak()
             }
         }
diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs
index fe78fb15cb95..42d94e72ee94 100644
--- a/compiler/rustc_macros/src/print_attribute.rs
+++ b/compiler/rustc_macros/src/print_attribute.rs
@@ -16,12 +16,14 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 let name = field.ident.as_ref().unwrap();
                 let string_name = name.to_string();
                 disps.push(quote! {
-                    if __printed_anything && #name.should_render() {
-                        __p.word_space(",");
+                    if #name.should_render() {
+                        if __printed_anything {
+                            __p.word_space(",");
+                        }
+                        __p.word(#string_name);
+                        __p.word_space(":");
                         __printed_anything = true;
                     }
-                    __p.word(#string_name);
-                    __p.word_space(":");
                     #name.print_attribute(__p);
                 });
                 field_names.push(name);
@@ -35,6 +37,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                         return;
                     }
 
+                    __p.nbsp();
                     __p.word("{");
                     #(#disps)*
                     __p.word("}");
@@ -48,8 +51,10 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
             for idx in 0..fields_unnamed.unnamed.len() {
                 let name = format_ident!("f{idx}");
                 disps.push(quote! {
-                    if __printed_anything && #name.should_render() {
-                        __p.word_space(",");
+                    if #name.should_render() {
+                        if __printed_anything {
+                            __p.word_space(",");
+                        }
                         __printed_anything = true;
                     }
                     #name.print_attribute(__p);
@@ -66,9 +71,9 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                         return;
                     }
 
-                    __p.word("(");
+                    __p.popen();
                     #(#disps)*
-                    __p.word(")");
+                    __p.pclose();
                 },
                 quote! { true },
             )
diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs
index 24a32d8a9acf..dda362a595e2 100644
--- a/tests/ui/unpretty/deprecated-attr.rs
+++ b/tests/ui/unpretty/deprecated-attr.rs
@@ -1,8 +1,6 @@
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
-// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is
-// slightly broken.
 #[deprecated]
 pub struct PlainDeprecated;
 
diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout
index 675351351a0c..42de7b4533e5 100644
--- a/tests/ui/unpretty/deprecated-attr.stdout
+++ b/tests/ui/unpretty/deprecated-attr.stdout
@@ -5,24 +5,21 @@ extern crate std;
 //@ compile-flags: -Zunpretty=hir
 //@ check-pass
 
-// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is
-// slightly broken.
-#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
-suggestion: }span: }")]
+#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
 struct PlainDeprecated;
 
-#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
-here's why this is deprecatedsuggestion: }span: }")]
+#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:
+"here's why this is deprecated"}}]
 struct DirectNote;
 
-#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
-here's why this is deprecatedsuggestion: }span: }")]
+#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:
+"here's why this is deprecated"}}]
 struct ExplicitNote;
 
-#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note:
-here's why this is deprecatedsuggestion: }span: }")]
+#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"),
+note: "here's why this is deprecated"}}]
 struct SinceAndNote;
 
-#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note:
-here's why this is deprecatedsuggestion: }span: }")]
+#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"),
+note: "here's why this is deprecated"}}]
 struct FlippedOrder;

From fb04372dc56129d69e39af80cac6e81694bd285f Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Thu, 6 Feb 2025 11:38:59 +0000
Subject: [PATCH 23/27] Move all alloc integration tests to a new alloctests
 crate

---
 library/Cargo.lock                            |  8 ++++
 library/Cargo.toml                            |  1 +
 library/alloc/Cargo.toml                      | 18 --------
 .../alloc/src/{raw_vec.rs => raw_vec/mod.rs}  |  0
 library/alloc/src/{rc.rs => rc/mod.rs}        |  0
 library/alloctests/Cargo.toml                 | 46 +++++++++++++++++++
 .../benches/binary_heap.rs                    |  0
 .../benches/btree/map.rs                      |  0
 .../benches/btree/mod.rs                      |  0
 .../benches/btree/set.rs                      |  0
 library/{alloc => alloctests}/benches/lib.rs  |  0
 .../benches/linked_list.rs                    |  0
 .../{alloc => alloctests}/benches/slice.rs    |  0
 library/{alloc => alloctests}/benches/str.rs  |  0
 .../{alloc => alloctests}/benches/string.rs   |  0
 library/{alloc => alloctests}/benches/vec.rs  |  0
 .../benches/vec_deque.rs                      |  0
 .../benches/vec_deque_append.rs               |  0
 library/alloctests/lib.rs                     |  1 +
 .../tests/alloc_test.rs}                      |  0
 library/{alloc => alloctests}/tests/arc.rs    |  0
 .../{alloc => alloctests}/tests/autotraits.rs |  0
 library/{alloc => alloctests}/tests/borrow.rs |  0
 library/{alloc => alloctests}/tests/boxed.rs  |  0
 .../tests/btree_set_hash.rs                   |  0
 library/{alloc => alloctests}/tests/c_str.rs  |  0
 library/{alloc => alloctests}/tests/c_str2.rs |  0
 .../tests/collections/binary_heap.rs          |  0
 .../tests/collections/mod.rs                  |  0
 .../{alloc => alloctests}/tests/const_fns.rs  |  0
 .../{alloc => alloctests}/tests/cow_str.rs    |  0
 library/{alloc => alloctests}/tests/fmt.rs    |  0
 library/{alloc => alloctests}/tests/heap.rs   |  0
 library/{alloc => alloctests}/tests/lib.rs    |  3 +-
 .../tests/linked_list.rs                      |  0
 .../{alloc => alloctests}/tests/misc_tests.rs |  0
 library/{alloc => alloctests}/tests/rc.rs     |  0
 library/{alloc => alloctests}/tests/slice.rs  |  0
 .../tests/sort/ffi_types.rs                   |  0
 .../tests/sort/known_good_stable_sort.rs      |  0
 .../{alloc => alloctests}/tests/sort/mod.rs   |  0
 .../tests/sort/patterns.rs                    |  0
 .../{alloc => alloctests}/tests/sort/tests.rs |  0
 .../{alloc => alloctests}/tests/sort/zipf.rs  |  0
 library/{alloc => alloctests}/tests/str.rs    |  0
 library/{alloc => alloctests}/tests/string.rs |  0
 library/{alloc => alloctests}/tests/sync.rs   |  0
 library/{alloc => alloctests}/tests/task.rs   |  0
 .../tests/testing/crash_test.rs               |  0
 .../tests/testing/mod.rs                      |  0
 .../{alloc => alloctests}/tests/thin_box.rs   |  0
 library/{alloc => alloctests}/tests/vec.rs    |  0
 .../{alloc => alloctests}/tests/vec_deque.rs  |  0
 .../tests/vec_deque_alloc_error.rs            |  0
 src/bootstrap/mk/Makefile.in                  |  2 +
 src/bootstrap/src/core/build_steps/check.rs   |  5 +-
 src/bootstrap/src/core/build_steps/test.rs    | 12 +++--
 src/tools/tidy/src/style.rs                   |  2 +-
 58 files changed, 73 insertions(+), 25 deletions(-)
 rename library/alloc/src/{raw_vec.rs => raw_vec/mod.rs} (100%)
 rename library/alloc/src/{rc.rs => rc/mod.rs} (100%)
 create mode 100644 library/alloctests/Cargo.toml
 rename library/{alloc => alloctests}/benches/binary_heap.rs (100%)
 rename library/{alloc => alloctests}/benches/btree/map.rs (100%)
 rename library/{alloc => alloctests}/benches/btree/mod.rs (100%)
 rename library/{alloc => alloctests}/benches/btree/set.rs (100%)
 rename library/{alloc => alloctests}/benches/lib.rs (100%)
 rename library/{alloc => alloctests}/benches/linked_list.rs (100%)
 rename library/{alloc => alloctests}/benches/slice.rs (100%)
 rename library/{alloc => alloctests}/benches/str.rs (100%)
 rename library/{alloc => alloctests}/benches/string.rs (100%)
 rename library/{alloc => alloctests}/benches/vec.rs (100%)
 rename library/{alloc => alloctests}/benches/vec_deque.rs (100%)
 rename library/{alloc => alloctests}/benches/vec_deque_append.rs (100%)
 create mode 100644 library/alloctests/lib.rs
 rename library/{alloc/tests/alloc.rs => alloctests/tests/alloc_test.rs} (100%)
 rename library/{alloc => alloctests}/tests/arc.rs (100%)
 rename library/{alloc => alloctests}/tests/autotraits.rs (100%)
 rename library/{alloc => alloctests}/tests/borrow.rs (100%)
 rename library/{alloc => alloctests}/tests/boxed.rs (100%)
 rename library/{alloc => alloctests}/tests/btree_set_hash.rs (100%)
 rename library/{alloc => alloctests}/tests/c_str.rs (100%)
 rename library/{alloc => alloctests}/tests/c_str2.rs (100%)
 rename library/{alloc => alloctests}/tests/collections/binary_heap.rs (100%)
 rename library/{alloc => alloctests}/tests/collections/mod.rs (100%)
 rename library/{alloc => alloctests}/tests/const_fns.rs (100%)
 rename library/{alloc => alloctests}/tests/cow_str.rs (100%)
 rename library/{alloc => alloctests}/tests/fmt.rs (100%)
 rename library/{alloc => alloctests}/tests/heap.rs (100%)
 rename library/{alloc => alloctests}/tests/lib.rs (98%)
 rename library/{alloc => alloctests}/tests/linked_list.rs (100%)
 rename library/{alloc => alloctests}/tests/misc_tests.rs (100%)
 rename library/{alloc => alloctests}/tests/rc.rs (100%)
 rename library/{alloc => alloctests}/tests/slice.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/ffi_types.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/known_good_stable_sort.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/mod.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/patterns.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/tests.rs (100%)
 rename library/{alloc => alloctests}/tests/sort/zipf.rs (100%)
 rename library/{alloc => alloctests}/tests/str.rs (100%)
 rename library/{alloc => alloctests}/tests/string.rs (100%)
 rename library/{alloc => alloctests}/tests/sync.rs (100%)
 rename library/{alloc => alloctests}/tests/task.rs (100%)
 rename library/{alloc => alloctests}/tests/testing/crash_test.rs (100%)
 rename library/{alloc => alloctests}/tests/testing/mod.rs (100%)
 rename library/{alloc => alloctests}/tests/thin_box.rs (100%)
 rename library/{alloc => alloctests}/tests/vec.rs (100%)
 rename library/{alloc => alloctests}/tests/vec_deque.rs (100%)
 rename library/{alloc => alloctests}/tests/vec_deque_alloc_error.rs (100%)

diff --git a/library/Cargo.lock b/library/Cargo.lock
index 316564141216..bdf50a5b383e 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -40,6 +40,14 @@ version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
+[[package]]
+name = "alloctests"
+version = "0.0.0"
+dependencies = [
+ "rand",
+ "rand_xorshift",
+]
+
 [[package]]
 name = "cc"
 version = "1.2.0"
diff --git a/library/Cargo.toml b/library/Cargo.toml
index 1205f7c9ed6b..4d5955593ffc 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -4,6 +4,7 @@ members = [
   "std",
   "sysroot",
   "coretests",
+  "alloctests",
 ]
 
 exclude = [
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 4cb835012568..d9e1c9b38a8c 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -18,24 +18,6 @@ compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
 rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
 rand_xorshift = "0.4.0"
 
-[[test]]
-name = "alloctests"
-path = "tests/lib.rs"
-
-[[test]]
-name = "vec_deque_alloc_error"
-path = "tests/vec_deque_alloc_error.rs"
-
-[[bench]]
-name = "allocbenches"
-path = "benches/lib.rs"
-test = true
-
-[[bench]]
-name = "vec_deque_append_bench"
-path = "benches/vec_deque_append.rs"
-harness = false
-
 [features]
 compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec/mod.rs
similarity index 100%
rename from library/alloc/src/raw_vec.rs
rename to library/alloc/src/raw_vec/mod.rs
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc/mod.rs
similarity index 100%
rename from library/alloc/src/rc.rs
rename to library/alloc/src/rc/mod.rs
diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml
new file mode 100644
index 000000000000..f1a783b1e224
--- /dev/null
+++ b/library/alloctests/Cargo.toml
@@ -0,0 +1,46 @@
+[package]
+name = "alloctests"
+version = "0.0.0"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-lang/rust.git"
+description = "Tests for the Rust Allocation Library"
+autotests = false
+autobenches = false
+edition = "2021"
+
+[lib]
+path = "lib.rs"
+test = false
+bench = false
+
+[dev-dependencies]
+rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
+rand_xorshift = "0.4.0"
+
+[[test]]
+name = "alloctests"
+path = "tests/lib.rs"
+
+[[test]]
+name = "vec_deque_alloc_error"
+path = "tests/vec_deque_alloc_error.rs"
+
+[[bench]]
+name = "allocbenches"
+path = "benches/lib.rs"
+test = true
+
+[[bench]]
+name = "vec_deque_append_bench"
+path = "benches/vec_deque_append.rs"
+harness = false
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    'cfg(bootstrap)',
+    'cfg(no_global_oom_handling)',
+    'cfg(no_rc)',
+    'cfg(no_sync)',
+    'cfg(randomized_layouts)',
+]
diff --git a/library/alloc/benches/binary_heap.rs b/library/alloctests/benches/binary_heap.rs
similarity index 100%
rename from library/alloc/benches/binary_heap.rs
rename to library/alloctests/benches/binary_heap.rs
diff --git a/library/alloc/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs
similarity index 100%
rename from library/alloc/benches/btree/map.rs
rename to library/alloctests/benches/btree/map.rs
diff --git a/library/alloc/benches/btree/mod.rs b/library/alloctests/benches/btree/mod.rs
similarity index 100%
rename from library/alloc/benches/btree/mod.rs
rename to library/alloctests/benches/btree/mod.rs
diff --git a/library/alloc/benches/btree/set.rs b/library/alloctests/benches/btree/set.rs
similarity index 100%
rename from library/alloc/benches/btree/set.rs
rename to library/alloctests/benches/btree/set.rs
diff --git a/library/alloc/benches/lib.rs b/library/alloctests/benches/lib.rs
similarity index 100%
rename from library/alloc/benches/lib.rs
rename to library/alloctests/benches/lib.rs
diff --git a/library/alloc/benches/linked_list.rs b/library/alloctests/benches/linked_list.rs
similarity index 100%
rename from library/alloc/benches/linked_list.rs
rename to library/alloctests/benches/linked_list.rs
diff --git a/library/alloc/benches/slice.rs b/library/alloctests/benches/slice.rs
similarity index 100%
rename from library/alloc/benches/slice.rs
rename to library/alloctests/benches/slice.rs
diff --git a/library/alloc/benches/str.rs b/library/alloctests/benches/str.rs
similarity index 100%
rename from library/alloc/benches/str.rs
rename to library/alloctests/benches/str.rs
diff --git a/library/alloc/benches/string.rs b/library/alloctests/benches/string.rs
similarity index 100%
rename from library/alloc/benches/string.rs
rename to library/alloctests/benches/string.rs
diff --git a/library/alloc/benches/vec.rs b/library/alloctests/benches/vec.rs
similarity index 100%
rename from library/alloc/benches/vec.rs
rename to library/alloctests/benches/vec.rs
diff --git a/library/alloc/benches/vec_deque.rs b/library/alloctests/benches/vec_deque.rs
similarity index 100%
rename from library/alloc/benches/vec_deque.rs
rename to library/alloctests/benches/vec_deque.rs
diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs
similarity index 100%
rename from library/alloc/benches/vec_deque_append.rs
rename to library/alloctests/benches/vec_deque_append.rs
diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs
new file mode 100644
index 000000000000..b49208cd4eb3
--- /dev/null
+++ b/library/alloctests/lib.rs
@@ -0,0 +1 @@
+// Intentionally left empty.
diff --git a/library/alloc/tests/alloc.rs b/library/alloctests/tests/alloc_test.rs
similarity index 100%
rename from library/alloc/tests/alloc.rs
rename to library/alloctests/tests/alloc_test.rs
diff --git a/library/alloc/tests/arc.rs b/library/alloctests/tests/arc.rs
similarity index 100%
rename from library/alloc/tests/arc.rs
rename to library/alloctests/tests/arc.rs
diff --git a/library/alloc/tests/autotraits.rs b/library/alloctests/tests/autotraits.rs
similarity index 100%
rename from library/alloc/tests/autotraits.rs
rename to library/alloctests/tests/autotraits.rs
diff --git a/library/alloc/tests/borrow.rs b/library/alloctests/tests/borrow.rs
similarity index 100%
rename from library/alloc/tests/borrow.rs
rename to library/alloctests/tests/borrow.rs
diff --git a/library/alloc/tests/boxed.rs b/library/alloctests/tests/boxed.rs
similarity index 100%
rename from library/alloc/tests/boxed.rs
rename to library/alloctests/tests/boxed.rs
diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloctests/tests/btree_set_hash.rs
similarity index 100%
rename from library/alloc/tests/btree_set_hash.rs
rename to library/alloctests/tests/btree_set_hash.rs
diff --git a/library/alloc/tests/c_str.rs b/library/alloctests/tests/c_str.rs
similarity index 100%
rename from library/alloc/tests/c_str.rs
rename to library/alloctests/tests/c_str.rs
diff --git a/library/alloc/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs
similarity index 100%
rename from library/alloc/tests/c_str2.rs
rename to library/alloctests/tests/c_str2.rs
diff --git a/library/alloc/tests/collections/binary_heap.rs b/library/alloctests/tests/collections/binary_heap.rs
similarity index 100%
rename from library/alloc/tests/collections/binary_heap.rs
rename to library/alloctests/tests/collections/binary_heap.rs
diff --git a/library/alloc/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs
similarity index 100%
rename from library/alloc/tests/collections/mod.rs
rename to library/alloctests/tests/collections/mod.rs
diff --git a/library/alloc/tests/const_fns.rs b/library/alloctests/tests/const_fns.rs
similarity index 100%
rename from library/alloc/tests/const_fns.rs
rename to library/alloctests/tests/const_fns.rs
diff --git a/library/alloc/tests/cow_str.rs b/library/alloctests/tests/cow_str.rs
similarity index 100%
rename from library/alloc/tests/cow_str.rs
rename to library/alloctests/tests/cow_str.rs
diff --git a/library/alloc/tests/fmt.rs b/library/alloctests/tests/fmt.rs
similarity index 100%
rename from library/alloc/tests/fmt.rs
rename to library/alloctests/tests/fmt.rs
diff --git a/library/alloc/tests/heap.rs b/library/alloctests/tests/heap.rs
similarity index 100%
rename from library/alloc/tests/heap.rs
rename to library/alloctests/tests/heap.rs
diff --git a/library/alloc/tests/lib.rs b/library/alloctests/tests/lib.rs
similarity index 98%
rename from library/alloc/tests/lib.rs
rename to library/alloctests/tests/lib.rs
index 785070fb2bbc..46c11ea150bf 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -43,11 +43,12 @@
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+extern crate alloc;
 extern crate test;
 
 use std::hash::{DefaultHasher, Hash, Hasher};
 
-mod alloc;
+mod alloc_test;
 mod arc;
 mod autotraits;
 mod borrow;
diff --git a/library/alloc/tests/linked_list.rs b/library/alloctests/tests/linked_list.rs
similarity index 100%
rename from library/alloc/tests/linked_list.rs
rename to library/alloctests/tests/linked_list.rs
diff --git a/library/alloc/tests/misc_tests.rs b/library/alloctests/tests/misc_tests.rs
similarity index 100%
rename from library/alloc/tests/misc_tests.rs
rename to library/alloctests/tests/misc_tests.rs
diff --git a/library/alloc/tests/rc.rs b/library/alloctests/tests/rc.rs
similarity index 100%
rename from library/alloc/tests/rc.rs
rename to library/alloctests/tests/rc.rs
diff --git a/library/alloc/tests/slice.rs b/library/alloctests/tests/slice.rs
similarity index 100%
rename from library/alloc/tests/slice.rs
rename to library/alloctests/tests/slice.rs
diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloctests/tests/sort/ffi_types.rs
similarity index 100%
rename from library/alloc/tests/sort/ffi_types.rs
rename to library/alloctests/tests/sort/ffi_types.rs
diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloctests/tests/sort/known_good_stable_sort.rs
similarity index 100%
rename from library/alloc/tests/sort/known_good_stable_sort.rs
rename to library/alloctests/tests/sort/known_good_stable_sort.rs
diff --git a/library/alloc/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs
similarity index 100%
rename from library/alloc/tests/sort/mod.rs
rename to library/alloctests/tests/sort/mod.rs
diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs
similarity index 100%
rename from library/alloc/tests/sort/patterns.rs
rename to library/alloctests/tests/sort/patterns.rs
diff --git a/library/alloc/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs
similarity index 100%
rename from library/alloc/tests/sort/tests.rs
rename to library/alloctests/tests/sort/tests.rs
diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloctests/tests/sort/zipf.rs
similarity index 100%
rename from library/alloc/tests/sort/zipf.rs
rename to library/alloctests/tests/sort/zipf.rs
diff --git a/library/alloc/tests/str.rs b/library/alloctests/tests/str.rs
similarity index 100%
rename from library/alloc/tests/str.rs
rename to library/alloctests/tests/str.rs
diff --git a/library/alloc/tests/string.rs b/library/alloctests/tests/string.rs
similarity index 100%
rename from library/alloc/tests/string.rs
rename to library/alloctests/tests/string.rs
diff --git a/library/alloc/tests/sync.rs b/library/alloctests/tests/sync.rs
similarity index 100%
rename from library/alloc/tests/sync.rs
rename to library/alloctests/tests/sync.rs
diff --git a/library/alloc/tests/task.rs b/library/alloctests/tests/task.rs
similarity index 100%
rename from library/alloc/tests/task.rs
rename to library/alloctests/tests/task.rs
diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloctests/tests/testing/crash_test.rs
similarity index 100%
rename from library/alloc/tests/testing/crash_test.rs
rename to library/alloctests/tests/testing/crash_test.rs
diff --git a/library/alloc/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs
similarity index 100%
rename from library/alloc/tests/testing/mod.rs
rename to library/alloctests/tests/testing/mod.rs
diff --git a/library/alloc/tests/thin_box.rs b/library/alloctests/tests/thin_box.rs
similarity index 100%
rename from library/alloc/tests/thin_box.rs
rename to library/alloctests/tests/thin_box.rs
diff --git a/library/alloc/tests/vec.rs b/library/alloctests/tests/vec.rs
similarity index 100%
rename from library/alloc/tests/vec.rs
rename to library/alloctests/tests/vec.rs
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs
similarity index 100%
rename from library/alloc/tests/vec_deque.rs
rename to library/alloctests/tests/vec_deque.rs
diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloctests/tests/vec_deque_alloc_error.rs
similarity index 100%
rename from library/alloc/tests/vec_deque_alloc_error.rs
rename to library/alloctests/tests/vec_deque_alloc_error.rs
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 88aa70d4f2f8..6cb0b19d7632 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -56,6 +56,7 @@ check-aux:
 	# Run standard library tests in Miri.
 	$(Q)$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
+		library/alloctests \
 		library/alloc \
 		$(BOOTSTRAP_ARGS) \
 		--no-doc
@@ -63,6 +64,7 @@ check-aux:
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
+		library/alloctests \
 		library/alloc \
 		$(BOOTSTRAP_ARGS) \
 		--doc
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index b8bbe1eb5f8a..18aa3119842c 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -45,7 +45,10 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library")
+        run.crate_or_deps("sysroot")
+            .crate_or_deps("coretests")
+            .crate_or_deps("alloctests")
+            .path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 4b7c8d5770e4..e80f8f9a4b72 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2609,7 +2609,7 @@ impl Step for Crate {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.crate_or_deps("sysroot").crate_or_deps("coretests")
+        run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2724,12 +2724,16 @@ impl Step for Crate {
         };
 
         let mut crates = self.crates.clone();
-        // The core crate can't directly be tested. We could silently
-        // ignore it, but adding it's own test crate is less confusing
-        // for users. We still keep core itself for doctests.
+        // The core and alloc crates can't directly be tested. We
+        // could silently ignore them, but adding their own test
+        // crates is less confusing for users. We still keep core and
+        // alloc themself for doctests
         if crates.iter().any(|crate_| crate_ == "core") {
             crates.push("coretests".to_owned());
         }
+        if crates.iter().any(|crate_| crate_ == "alloc") {
+            crates.push("alloctests".to_owned());
+        }
 
         run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder);
     }
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 205d6720718a..2237eac200d8 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -475,7 +475,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                 && !trimmed.starts_with("//")
                 && !file.ancestors().any(|a| {
                     (a.ends_with("tests") && a.join("COMPILER_TESTS.md").exists())
-                        || a.ends_with("library/alloc/tests")
+                        || a.ends_with("library/alloctests")
                 })
                 && filename != "tests.rs"
             {

From be1e0b786df35a535327ed3b1457622e357bae6d Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Thu, 6 Feb 2025 12:07:24 +0000
Subject: [PATCH 24/27] Move most Rc tests to alloctests

---
 library/alloc/src/rc/tests.rs  | 649 ---------------------------------
 library/alloctests/tests/rc.rs | 649 ++++++++++++++++++++++++++++++++-
 2 files changed, 648 insertions(+), 650 deletions(-)

diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
index 2210a7c24c06..35ff6b7d570d 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloc/src/rc/tests.rs
@@ -1,64 +1,5 @@
-use std::cell::RefCell;
-use std::clone::Clone;
-
 use super::*;
 
-#[test]
-fn test_clone() {
-    let x = Rc::new(RefCell::new(5));
-    let y = x.clone();
-    *x.borrow_mut() = 20;
-    assert_eq!(*y.borrow(), 20);
-}
-
-#[test]
-fn test_simple() {
-    let x = Rc::new(5);
-    assert_eq!(*x, 5);
-}
-
-#[test]
-fn test_simple_clone() {
-    let x = Rc::new(5);
-    let y = x.clone();
-    assert_eq!(*x, 5);
-    assert_eq!(*y, 5);
-}
-
-#[test]
-fn test_destructor() {
-    let x: Rc<Box<_>> = Rc::new(Box::new(5));
-    assert_eq!(**x, 5);
-}
-
-#[test]
-fn test_live() {
-    let x = Rc::new(5);
-    let y = Rc::downgrade(&x);
-    assert!(y.upgrade().is_some());
-}
-
-#[test]
-fn test_dead() {
-    let x = Rc::new(5);
-    let y = Rc::downgrade(&x);
-    drop(x);
-    assert!(y.upgrade().is_none());
-}
-
-#[test]
-fn weak_self_cyclic() {
-    struct Cycle {
-        x: RefCell<Option<Weak<Cycle>>>,
-    }
-
-    let a = Rc::new(Cycle { x: RefCell::new(None) });
-    let b = Rc::downgrade(&a.clone());
-    *a.x.borrow_mut() = Some(b);
-
-    // hopefully we don't double-free (or leak)...
-}
-
 #[test]
 fn is_unique() {
     let x = Rc::new(3);
@@ -72,593 +13,3 @@ fn is_unique() {
     drop(w);
     assert!(Rc::is_unique(&x));
 }
-
-#[test]
-fn test_strong_count() {
-    let a = Rc::new(0);
-    assert!(Rc::strong_count(&a) == 1);
-    let w = Rc::downgrade(&a);
-    assert!(Rc::strong_count(&a) == 1);
-    let b = w.upgrade().expect("upgrade of live rc failed");
-    assert!(Rc::strong_count(&b) == 2);
-    assert!(Rc::strong_count(&a) == 2);
-    drop(w);
-    drop(a);
-    assert!(Rc::strong_count(&b) == 1);
-    let c = b.clone();
-    assert!(Rc::strong_count(&b) == 2);
-    assert!(Rc::strong_count(&c) == 2);
-}
-
-#[test]
-fn test_weak_count() {
-    let a = Rc::new(0);
-    assert!(Rc::strong_count(&a) == 1);
-    assert!(Rc::weak_count(&a) == 0);
-    let w = Rc::downgrade(&a);
-    assert!(Rc::strong_count(&a) == 1);
-    assert!(Rc::weak_count(&a) == 1);
-    drop(w);
-    assert!(Rc::strong_count(&a) == 1);
-    assert!(Rc::weak_count(&a) == 0);
-    let c = a.clone();
-    assert!(Rc::strong_count(&a) == 2);
-    assert!(Rc::weak_count(&a) == 0);
-    drop(c);
-}
-
-#[test]
-fn weak_counts() {
-    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
-    assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
-
-    let a = Rc::new(0);
-    let w = Rc::downgrade(&a);
-    assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), 1);
-    let w2 = w.clone();
-    assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), 2);
-    assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), 2);
-    drop(w);
-    assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), 1);
-    let a2 = a.clone();
-    assert_eq!(Weak::strong_count(&w2), 2);
-    assert_eq!(Weak::weak_count(&w2), 1);
-    drop(a2);
-    drop(a);
-    assert_eq!(Weak::strong_count(&w2), 0);
-    assert_eq!(Weak::weak_count(&w2), 0);
-    drop(w2);
-}
-
-#[test]
-fn try_unwrap() {
-    let x = Rc::new(3);
-    assert_eq!(Rc::try_unwrap(x), Ok(3));
-    let x = Rc::new(4);
-    let _y = x.clone();
-    assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
-    let x = Rc::new(5);
-    let _w = Rc::downgrade(&x);
-    assert_eq!(Rc::try_unwrap(x), Ok(5));
-}
-
-#[test]
-fn into_inner() {
-    let x = Rc::new(3);
-    assert_eq!(Rc::into_inner(x), Some(3));
-
-    let x = Rc::new(4);
-    let y = Rc::clone(&x);
-    assert_eq!(Rc::into_inner(x), None);
-    assert_eq!(Rc::into_inner(y), Some(4));
-
-    let x = Rc::new(5);
-    let _w = Rc::downgrade(&x);
-    assert_eq!(Rc::into_inner(x), Some(5));
-}
-
-#[test]
-fn into_from_raw() {
-    let x = Rc::new(Box::new("hello"));
-    let y = x.clone();
-
-    let x_ptr = Rc::into_raw(x);
-    drop(y);
-    unsafe {
-        assert_eq!(**x_ptr, "hello");
-
-        let x = Rc::from_raw(x_ptr);
-        assert_eq!(**x, "hello");
-
-        assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
-    }
-}
-
-#[test]
-fn test_into_from_raw_unsized() {
-    use std::fmt::Display;
-    use std::string::ToString;
-
-    let rc: Rc<str> = Rc::from("foo");
-
-    let ptr = Rc::into_raw(rc.clone());
-    let rc2 = unsafe { Rc::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }, "foo");
-    assert_eq!(rc, rc2);
-
-    let rc: Rc<dyn Display> = Rc::new(123);
-
-    let ptr = Rc::into_raw(rc.clone());
-    let rc2 = unsafe { Rc::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }.to_string(), "123");
-    assert_eq!(rc2.to_string(), "123");
-}
-
-#[test]
-fn into_from_weak_raw() {
-    let x = Rc::new(Box::new("hello"));
-    let y = Rc::downgrade(&x);
-
-    let y_ptr = Weak::into_raw(y);
-    unsafe {
-        assert_eq!(**y_ptr, "hello");
-
-        let y = Weak::from_raw(y_ptr);
-        let y_up = Weak::upgrade(&y).unwrap();
-        assert_eq!(**y_up, "hello");
-        drop(y_up);
-
-        assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
-    }
-}
-
-#[test]
-fn test_into_from_weak_raw_unsized() {
-    use std::fmt::Display;
-    use std::string::ToString;
-
-    let arc: Rc<str> = Rc::from("foo");
-    let weak: Weak<str> = Rc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }, "foo");
-    assert!(weak.ptr_eq(&weak2));
-
-    let arc: Rc<dyn Display> = Rc::new(123);
-    let weak: Weak<dyn Display> = Rc::downgrade(&arc);
-
-    let ptr = Weak::into_raw(weak.clone());
-    let weak2 = unsafe { Weak::from_raw(ptr) };
-
-    assert_eq!(unsafe { &*ptr }.to_string(), "123");
-    assert!(weak.ptr_eq(&weak2));
-}
-
-#[test]
-fn get_mut() {
-    let mut x = Rc::new(3);
-    *Rc::get_mut(&mut x).unwrap() = 4;
-    assert_eq!(*x, 4);
-    let y = x.clone();
-    assert!(Rc::get_mut(&mut x).is_none());
-    drop(y);
-    assert!(Rc::get_mut(&mut x).is_some());
-    let _w = Rc::downgrade(&x);
-    assert!(Rc::get_mut(&mut x).is_none());
-}
-
-#[test]
-fn test_cowrc_clone_make_unique() {
-    let mut cow0 = Rc::new(75);
-    let mut cow1 = cow0.clone();
-    let mut cow2 = cow1.clone();
-
-    assert!(75 == *Rc::make_mut(&mut cow0));
-    assert!(75 == *Rc::make_mut(&mut cow1));
-    assert!(75 == *Rc::make_mut(&mut cow2));
-
-    *Rc::make_mut(&mut cow0) += 1;
-    *Rc::make_mut(&mut cow1) += 2;
-    *Rc::make_mut(&mut cow2) += 3;
-
-    assert!(76 == *cow0);
-    assert!(77 == *cow1);
-    assert!(78 == *cow2);
-
-    // none should point to the same backing memory
-    assert!(*cow0 != *cow1);
-    assert!(*cow0 != *cow2);
-    assert!(*cow1 != *cow2);
-}
-
-#[test]
-fn test_cowrc_clone_unique2() {
-    let mut cow0 = Rc::new(75);
-    let cow1 = cow0.clone();
-    let cow2 = cow1.clone();
-
-    assert!(75 == *cow0);
-    assert!(75 == *cow1);
-    assert!(75 == *cow2);
-
-    *Rc::make_mut(&mut cow0) += 1;
-
-    assert!(76 == *cow0);
-    assert!(75 == *cow1);
-    assert!(75 == *cow2);
-
-    // cow1 and cow2 should share the same contents
-    // cow0 should have a unique reference
-    assert!(*cow0 != *cow1);
-    assert!(*cow0 != *cow2);
-    assert!(*cow1 == *cow2);
-}
-
-#[test]
-fn test_cowrc_clone_weak() {
-    let mut cow0 = Rc::new(75);
-    let cow1_weak = Rc::downgrade(&cow0);
-
-    assert!(75 == *cow0);
-    assert!(75 == *cow1_weak.upgrade().unwrap());
-
-    *Rc::make_mut(&mut cow0) += 1;
-
-    assert!(76 == *cow0);
-    assert!(cow1_weak.upgrade().is_none());
-}
-
-/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice).
-#[test]
-fn test_cowrc_unsized() {
-    use std::rc::Rc;
-
-    let mut data: Rc<[i32]> = Rc::new([10, 20, 30]);
-
-    Rc::make_mut(&mut data)[0] += 1; // Won't clone anything
-    let mut other_data = Rc::clone(&data); // Won't clone inner data
-    Rc::make_mut(&mut data)[1] += 1; // Clones inner data
-    Rc::make_mut(&mut data)[2] += 1; // Won't clone anything
-    Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything
-
-    // Now `data` and `other_data` point to different allocations.
-    assert_eq!(*data, [11, 21, 31]);
-    assert_eq!(*other_data, [110, 20, 30]);
-}
-
-#[test]
-fn test_show() {
-    let foo = Rc::new(75);
-    assert_eq!(format!("{foo:?}"), "75");
-}
-
-#[test]
-fn test_unsized() {
-    let foo: Rc<[i32]> = Rc::new([1, 2, 3]);
-    assert_eq!(foo, foo.clone());
-}
-
-#[test]
-fn test_maybe_thin_unsized() {
-    // If/when custom thin DSTs exist, this test should be updated to use one
-    use std::ffi::CStr;
-
-    let x: Rc<CStr> = Rc::from(c"swordfish");
-    assert_eq!(format!("{x:?}"), "\"swordfish\"");
-    let y: Weak<CStr> = Rc::downgrade(&x);
-    drop(x);
-
-    // At this point, the weak points to a dropped DST
-    assert!(y.upgrade().is_none());
-    // But we still need to be able to get the alloc layout to drop.
-    // CStr has no drop glue, but custom DSTs might, and need to work.
-    drop(y);
-}
-
-#[test]
-fn test_from_owned() {
-    let foo = 123;
-    let foo_rc = Rc::from(foo);
-    assert!(123 == *foo_rc);
-}
-
-#[test]
-fn test_new_weak() {
-    let foo: Weak<usize> = Weak::new();
-    assert!(foo.upgrade().is_none());
-}
-
-#[test]
-fn test_ptr_eq() {
-    let five = Rc::new(5);
-    let same_five = five.clone();
-    let other_five = Rc::new(5);
-
-    assert!(Rc::ptr_eq(&five, &same_five));
-    assert!(!Rc::ptr_eq(&five, &other_five));
-}
-
-#[test]
-fn test_from_str() {
-    let r: Rc<str> = Rc::from("foo");
-
-    assert_eq!(&r[..], "foo");
-}
-
-#[test]
-fn test_copy_from_slice() {
-    let s: &[u32] = &[1, 2, 3];
-    let r: Rc<[u32]> = Rc::from(s);
-
-    assert_eq!(&r[..], [1, 2, 3]);
-}
-
-#[test]
-fn test_clone_from_slice() {
-    #[derive(Clone, Debug, Eq, PartialEq)]
-    struct X(u32);
-
-    let s: &[X] = &[X(1), X(2), X(3)];
-    let r: Rc<[X]> = Rc::from(s);
-
-    assert_eq!(&r[..], s);
-}
-
-#[test]
-#[should_panic]
-fn test_clone_from_slice_panic() {
-    use std::string::{String, ToString};
-
-    struct Fail(u32, String);
-
-    impl Clone for Fail {
-        fn clone(&self) -> Fail {
-            if self.0 == 2 {
-                panic!();
-            }
-            Fail(self.0, self.1.clone())
-        }
-    }
-
-    let s: &[Fail] =
-        &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())];
-
-    // Should panic, but not cause memory corruption
-    let _r: Rc<[Fail]> = Rc::from(s);
-}
-
-#[test]
-fn test_from_box() {
-    let b: Box<u32> = Box::new(123);
-    let r: Rc<u32> = Rc::from(b);
-
-    assert_eq!(*r, 123);
-}
-
-#[test]
-fn test_from_box_str() {
-    use std::string::String;
-
-    let s = String::from("foo").into_boxed_str();
-    assert_eq!((&&&s).as_str(), "foo");
-
-    let r: Rc<str> = Rc::from(s);
-    assert_eq!((&r).as_str(), "foo");
-    assert_eq!(r.as_str(), "foo");
-
-    assert_eq!(&r[..], "foo");
-}
-
-#[test]
-fn test_from_box_slice() {
-    let s = vec![1, 2, 3].into_boxed_slice();
-    let r: Rc<[u32]> = Rc::from(s);
-
-    assert_eq!(&r[..], [1, 2, 3]);
-}
-
-#[test]
-fn test_from_box_trait() {
-    use std::fmt::Display;
-    use std::string::ToString;
-
-    let b: Box<dyn Display> = Box::new(123);
-    let r: Rc<dyn Display> = Rc::from(b);
-
-    assert_eq!(r.to_string(), "123");
-}
-
-#[test]
-fn test_from_box_trait_zero_sized() {
-    use std::fmt::Debug;
-
-    let b: Box<dyn Debug> = Box::new(());
-    let r: Rc<dyn Debug> = Rc::from(b);
-
-    assert_eq!(format!("{r:?}"), "()");
-}
-
-#[test]
-fn test_from_vec() {
-    let v = vec![1, 2, 3];
-    let r: Rc<[u32]> = Rc::from(v);
-
-    assert_eq!(&r[..], [1, 2, 3]);
-}
-
-#[test]
-fn test_downcast() {
-    use std::any::Any;
-
-    let r1: Rc<dyn Any> = Rc::new(i32::MAX);
-    let r2: Rc<dyn Any> = Rc::new("abc");
-
-    assert!(r1.clone().downcast::<u32>().is_err());
-
-    let r1i32 = r1.downcast::<i32>();
-    assert!(r1i32.is_ok());
-    assert_eq!(r1i32.unwrap(), Rc::new(i32::MAX));
-
-    assert!(r2.clone().downcast::<i32>().is_err());
-
-    let r2str = r2.downcast::<&'static str>();
-    assert!(r2str.is_ok());
-    assert_eq!(r2str.unwrap(), Rc::new("abc"));
-}
-
-#[test]
-fn test_array_from_slice() {
-    let v = vec![1, 2, 3];
-    let r: Rc<[u32]> = Rc::from(v);
-
-    let a: Result<Rc<[u32; 3]>, _> = r.clone().try_into();
-    assert!(a.is_ok());
-
-    let a: Result<Rc<[u32; 2]>, _> = r.clone().try_into();
-    assert!(a.is_err());
-}
-
-#[test]
-fn test_rc_cyclic_with_zero_refs() {
-    struct ZeroRefs {
-        inner: Weak<ZeroRefs>,
-    }
-
-    let zero_refs = Rc::new_cyclic(|inner| {
-        assert_eq!(inner.strong_count(), 0);
-        assert!(inner.upgrade().is_none());
-        ZeroRefs { inner: Weak::new() }
-    });
-
-    assert_eq!(Rc::strong_count(&zero_refs), 1);
-    assert_eq!(Rc::weak_count(&zero_refs), 0);
-    assert_eq!(zero_refs.inner.strong_count(), 0);
-    assert_eq!(zero_refs.inner.weak_count(), 0);
-}
-
-#[test]
-fn test_rc_cyclic_with_one_ref() {
-    struct OneRef {
-        inner: Weak<OneRef>,
-    }
-
-    let one_ref = Rc::new_cyclic(|inner| {
-        assert_eq!(inner.strong_count(), 0);
-        assert!(inner.upgrade().is_none());
-        OneRef { inner: inner.clone() }
-    });
-
-    assert_eq!(Rc::strong_count(&one_ref), 1);
-    assert_eq!(Rc::weak_count(&one_ref), 1);
-
-    let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap();
-    assert!(Rc::ptr_eq(&one_ref, &one_ref2));
-
-    assert_eq!(one_ref.inner.strong_count(), 2);
-    assert_eq!(one_ref.inner.weak_count(), 1);
-}
-
-#[test]
-fn test_rc_cyclic_with_two_ref() {
-    struct TwoRefs {
-        inner: Weak<TwoRefs>,
-        inner1: Weak<TwoRefs>,
-    }
-
-    let two_refs = Rc::new_cyclic(|inner| {
-        assert_eq!(inner.strong_count(), 0);
-        assert!(inner.upgrade().is_none());
-        TwoRefs { inner: inner.clone(), inner1: inner.clone() }
-    });
-
-    assert_eq!(Rc::strong_count(&two_refs), 1);
-    assert_eq!(Rc::weak_count(&two_refs), 2);
-
-    let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap();
-    assert!(Rc::ptr_eq(&two_refs, &two_ref3));
-
-    let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap();
-    assert!(Rc::ptr_eq(&two_refs, &two_ref2));
-
-    assert_eq!(Rc::strong_count(&two_refs), 3);
-    assert_eq!(Rc::weak_count(&two_refs), 2);
-}
-
-#[test]
-fn test_unique_rc_weak() {
-    let rc = UniqueRc::new(42);
-    let weak = UniqueRc::downgrade(&rc);
-    assert!(weak.upgrade().is_none());
-
-    let _rc = UniqueRc::into_rc(rc);
-    assert_eq!(*weak.upgrade().unwrap(), 42);
-}
-
-#[test]
-fn test_unique_rc_drop_weak() {
-    let rc = UniqueRc::new(42);
-    let weak = UniqueRc::downgrade(&rc);
-    mem::drop(weak);
-
-    let rc = UniqueRc::into_rc(rc);
-    assert_eq!(*rc, 42);
-}
-
-#[test]
-fn test_unique_rc_drops_contents() {
-    let mut dropped = false;
-    struct DropMe<'a>(&'a mut bool);
-    impl Drop for DropMe<'_> {
-        fn drop(&mut self) {
-            *self.0 = true;
-        }
-    }
-    {
-        let rc = UniqueRc::new(DropMe(&mut dropped));
-        drop(rc);
-    }
-    assert!(dropped);
-}
-
-/// Exercise the non-default allocator usage.
-#[test]
-fn test_unique_rc_with_alloc_drops_contents() {
-    let mut dropped = false;
-    struct DropMe<'a>(&'a mut bool);
-    impl Drop for DropMe<'_> {
-        fn drop(&mut self) {
-            *self.0 = true;
-        }
-    }
-    {
-        let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System);
-        drop(rc);
-    }
-    assert!(dropped);
-}
-
-#[test]
-fn test_unique_rc_weak_clone_holding_ref() {
-    let mut v = UniqueRc::new(0u8);
-    let w = UniqueRc::downgrade(&v);
-    let r = &mut *v;
-    let _ = w.clone(); // touch weak count
-    *r = 123;
-}
-
-#[test]
-fn test_unique_rc_unsizing_coercion() {
-    let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]);
-    assert_eq!(rc.len(), 3);
-    rc[0] = 123;
-    let rc: Rc<[u8]> = UniqueRc::into_rc(rc);
-    assert_eq!(*rc, [123, 0, 0]);
-}
diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs
index 9d82a7621a21..0628011ba682 100644
--- a/library/alloctests/tests/rc.rs
+++ b/library/alloctests/tests/rc.rs
@@ -1,7 +1,8 @@
 use std::any::Any;
 use std::cell::{Cell, RefCell};
 use std::iter::TrustedLen;
-use std::rc::{Rc, Weak};
+use std::mem;
+use std::rc::{Rc, UniqueRc, Weak};
 
 #[test]
 fn uninhabited() {
@@ -257,3 +258,649 @@ mod pin_coerce_unsized {
         arg
     }
 }
+
+#[test]
+fn test_clone() {
+    let x = Rc::new(RefCell::new(5));
+    let y = x.clone();
+    *x.borrow_mut() = 20;
+    assert_eq!(*y.borrow(), 20);
+}
+
+#[test]
+fn test_simple() {
+    let x = Rc::new(5);
+    assert_eq!(*x, 5);
+}
+
+#[test]
+fn test_simple_clone() {
+    let x = Rc::new(5);
+    let y = x.clone();
+    assert_eq!(*x, 5);
+    assert_eq!(*y, 5);
+}
+
+#[test]
+fn test_destructor() {
+    let x: Rc<Box<_>> = Rc::new(Box::new(5));
+    assert_eq!(**x, 5);
+}
+
+#[test]
+fn test_live() {
+    let x = Rc::new(5);
+    let y = Rc::downgrade(&x);
+    assert!(y.upgrade().is_some());
+}
+
+#[test]
+fn test_dead() {
+    let x = Rc::new(5);
+    let y = Rc::downgrade(&x);
+    drop(x);
+    assert!(y.upgrade().is_none());
+}
+
+#[test]
+fn weak_self_cyclic() {
+    struct Cycle {
+        x: RefCell<Option<Weak<Cycle>>>,
+    }
+
+    let a = Rc::new(Cycle { x: RefCell::new(None) });
+    let b = Rc::downgrade(&a.clone());
+    *a.x.borrow_mut() = Some(b);
+
+    // hopefully we don't double-free (or leak)...
+}
+
+#[test]
+fn test_strong_count() {
+    let a = Rc::new(0);
+    assert!(Rc::strong_count(&a) == 1);
+    let w = Rc::downgrade(&a);
+    assert!(Rc::strong_count(&a) == 1);
+    let b = w.upgrade().expect("upgrade of live rc failed");
+    assert!(Rc::strong_count(&b) == 2);
+    assert!(Rc::strong_count(&a) == 2);
+    drop(w);
+    drop(a);
+    assert!(Rc::strong_count(&b) == 1);
+    let c = b.clone();
+    assert!(Rc::strong_count(&b) == 2);
+    assert!(Rc::strong_count(&c) == 2);
+}
+
+#[test]
+fn test_weak_count() {
+    let a = Rc::new(0);
+    assert!(Rc::strong_count(&a) == 1);
+    assert!(Rc::weak_count(&a) == 0);
+    let w = Rc::downgrade(&a);
+    assert!(Rc::strong_count(&a) == 1);
+    assert!(Rc::weak_count(&a) == 1);
+    drop(w);
+    assert!(Rc::strong_count(&a) == 1);
+    assert!(Rc::weak_count(&a) == 0);
+    let c = a.clone();
+    assert!(Rc::strong_count(&a) == 2);
+    assert!(Rc::weak_count(&a) == 0);
+    drop(c);
+}
+
+#[test]
+fn weak_counts() {
+    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
+    assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
+
+    let a = Rc::new(0);
+    let w = Rc::downgrade(&a);
+    assert_eq!(Weak::strong_count(&w), 1);
+    assert_eq!(Weak::weak_count(&w), 1);
+    let w2 = w.clone();
+    assert_eq!(Weak::strong_count(&w), 1);
+    assert_eq!(Weak::weak_count(&w), 2);
+    assert_eq!(Weak::strong_count(&w2), 1);
+    assert_eq!(Weak::weak_count(&w2), 2);
+    drop(w);
+    assert_eq!(Weak::strong_count(&w2), 1);
+    assert_eq!(Weak::weak_count(&w2), 1);
+    let a2 = a.clone();
+    assert_eq!(Weak::strong_count(&w2), 2);
+    assert_eq!(Weak::weak_count(&w2), 1);
+    drop(a2);
+    drop(a);
+    assert_eq!(Weak::strong_count(&w2), 0);
+    assert_eq!(Weak::weak_count(&w2), 0);
+    drop(w2);
+}
+
+#[test]
+fn try_unwrap() {
+    let x = Rc::new(3);
+    assert_eq!(Rc::try_unwrap(x), Ok(3));
+    let x = Rc::new(4);
+    let _y = x.clone();
+    assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
+    let x = Rc::new(5);
+    let _w = Rc::downgrade(&x);
+    assert_eq!(Rc::try_unwrap(x), Ok(5));
+}
+
+#[test]
+fn into_inner() {
+    let x = Rc::new(3);
+    assert_eq!(Rc::into_inner(x), Some(3));
+
+    let x = Rc::new(4);
+    let y = Rc::clone(&x);
+    assert_eq!(Rc::into_inner(x), None);
+    assert_eq!(Rc::into_inner(y), Some(4));
+
+    let x = Rc::new(5);
+    let _w = Rc::downgrade(&x);
+    assert_eq!(Rc::into_inner(x), Some(5));
+}
+
+#[test]
+fn into_from_raw() {
+    let x = Rc::new(Box::new("hello"));
+    let y = x.clone();
+
+    let x_ptr = Rc::into_raw(x);
+    drop(y);
+    unsafe {
+        assert_eq!(**x_ptr, "hello");
+
+        let x = Rc::from_raw(x_ptr);
+        assert_eq!(**x, "hello");
+
+        assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
+    }
+}
+
+#[test]
+fn test_into_from_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let rc: Rc<str> = Rc::from("foo");
+
+    let ptr = Rc::into_raw(rc.clone());
+    let rc2 = unsafe { Rc::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert_eq!(rc, rc2);
+
+    let rc: Rc<dyn Display> = Rc::new(123);
+
+    let ptr = Rc::into_raw(rc.clone());
+    let rc2 = unsafe { Rc::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert_eq!(rc2.to_string(), "123");
+}
+
+#[test]
+fn into_from_weak_raw() {
+    let x = Rc::new(Box::new("hello"));
+    let y = Rc::downgrade(&x);
+
+    let y_ptr = Weak::into_raw(y);
+    unsafe {
+        assert_eq!(**y_ptr, "hello");
+
+        let y = Weak::from_raw(y_ptr);
+        let y_up = Weak::upgrade(&y).unwrap();
+        assert_eq!(**y_up, "hello");
+        drop(y_up);
+
+        assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
+    }
+}
+
+#[test]
+fn test_into_from_weak_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let arc: Rc<str> = Rc::from("foo");
+    let weak: Weak<str> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert!(weak.ptr_eq(&weak2));
+
+    let arc: Rc<dyn Display> = Rc::new(123);
+    let weak: Weak<dyn Display> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert!(weak.ptr_eq(&weak2));
+}
+
+#[test]
+fn get_mut() {
+    let mut x = Rc::new(3);
+    *Rc::get_mut(&mut x).unwrap() = 4;
+    assert_eq!(*x, 4);
+    let y = x.clone();
+    assert!(Rc::get_mut(&mut x).is_none());
+    drop(y);
+    assert!(Rc::get_mut(&mut x).is_some());
+    let _w = Rc::downgrade(&x);
+    assert!(Rc::get_mut(&mut x).is_none());
+}
+
+#[test]
+fn test_cowrc_clone_make_unique() {
+    let mut cow0 = Rc::new(75);
+    let mut cow1 = cow0.clone();
+    let mut cow2 = cow1.clone();
+
+    assert!(75 == *Rc::make_mut(&mut cow0));
+    assert!(75 == *Rc::make_mut(&mut cow1));
+    assert!(75 == *Rc::make_mut(&mut cow2));
+
+    *Rc::make_mut(&mut cow0) += 1;
+    *Rc::make_mut(&mut cow1) += 2;
+    *Rc::make_mut(&mut cow2) += 3;
+
+    assert!(76 == *cow0);
+    assert!(77 == *cow1);
+    assert!(78 == *cow2);
+
+    // none should point to the same backing memory
+    assert!(*cow0 != *cow1);
+    assert!(*cow0 != *cow2);
+    assert!(*cow1 != *cow2);
+}
+
+#[test]
+fn test_cowrc_clone_unique2() {
+    let mut cow0 = Rc::new(75);
+    let cow1 = cow0.clone();
+    let cow2 = cow1.clone();
+
+    assert!(75 == *cow0);
+    assert!(75 == *cow1);
+    assert!(75 == *cow2);
+
+    *Rc::make_mut(&mut cow0) += 1;
+
+    assert!(76 == *cow0);
+    assert!(75 == *cow1);
+    assert!(75 == *cow2);
+
+    // cow1 and cow2 should share the same contents
+    // cow0 should have a unique reference
+    assert!(*cow0 != *cow1);
+    assert!(*cow0 != *cow2);
+    assert!(*cow1 == *cow2);
+}
+
+#[test]
+fn test_cowrc_clone_weak() {
+    let mut cow0 = Rc::new(75);
+    let cow1_weak = Rc::downgrade(&cow0);
+
+    assert!(75 == *cow0);
+    assert!(75 == *cow1_weak.upgrade().unwrap());
+
+    *Rc::make_mut(&mut cow0) += 1;
+
+    assert!(76 == *cow0);
+    assert!(cow1_weak.upgrade().is_none());
+}
+
+/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice).
+#[test]
+fn test_cowrc_unsized() {
+    use std::rc::Rc;
+
+    let mut data: Rc<[i32]> = Rc::new([10, 20, 30]);
+
+    Rc::make_mut(&mut data)[0] += 1; // Won't clone anything
+    let mut other_data = Rc::clone(&data); // Won't clone inner data
+    Rc::make_mut(&mut data)[1] += 1; // Clones inner data
+    Rc::make_mut(&mut data)[2] += 1; // Won't clone anything
+    Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything
+
+    // Now `data` and `other_data` point to different allocations.
+    assert_eq!(*data, [11, 21, 31]);
+    assert_eq!(*other_data, [110, 20, 30]);
+}
+
+#[test]
+fn test_show() {
+    let foo = Rc::new(75);
+    assert_eq!(format!("{foo:?}"), "75");
+}
+
+#[test]
+fn test_unsized() {
+    let foo: Rc<[i32]> = Rc::new([1, 2, 3]);
+    assert_eq!(foo, foo.clone());
+}
+
+#[test]
+fn test_maybe_thin_unsized() {
+    // If/when custom thin DSTs exist, this test should be updated to use one
+    use std::ffi::CStr;
+
+    let x: Rc<CStr> = Rc::from(c"swordfish");
+    assert_eq!(format!("{x:?}"), "\"swordfish\"");
+    let y: Weak<CStr> = Rc::downgrade(&x);
+    drop(x);
+
+    // At this point, the weak points to a dropped DST
+    assert!(y.upgrade().is_none());
+    // But we still need to be able to get the alloc layout to drop.
+    // CStr has no drop glue, but custom DSTs might, and need to work.
+    drop(y);
+}
+
+#[test]
+fn test_from_owned() {
+    let foo = 123;
+    let foo_rc = Rc::from(foo);
+    assert!(123 == *foo_rc);
+}
+
+#[test]
+fn test_new_weak() {
+    let foo: Weak<usize> = Weak::new();
+    assert!(foo.upgrade().is_none());
+}
+
+#[test]
+fn test_ptr_eq() {
+    let five = Rc::new(5);
+    let same_five = five.clone();
+    let other_five = Rc::new(5);
+
+    assert!(Rc::ptr_eq(&five, &same_five));
+    assert!(!Rc::ptr_eq(&five, &other_five));
+}
+
+#[test]
+fn test_from_str() {
+    let r: Rc<str> = Rc::from("foo");
+
+    assert_eq!(&r[..], "foo");
+}
+
+#[test]
+fn test_copy_from_slice() {
+    let s: &[u32] = &[1, 2, 3];
+    let r: Rc<[u32]> = Rc::from(s);
+
+    assert_eq!(&r[..], [1, 2, 3]);
+}
+
+#[test]
+fn test_clone_from_slice() {
+    #[derive(Clone, Debug, Eq, PartialEq)]
+    struct X(u32);
+
+    let s: &[X] = &[X(1), X(2), X(3)];
+    let r: Rc<[X]> = Rc::from(s);
+
+    assert_eq!(&r[..], s);
+}
+
+#[test]
+#[should_panic]
+fn test_clone_from_slice_panic() {
+    use std::string::{String, ToString};
+
+    struct Fail(u32, String);
+
+    impl Clone for Fail {
+        fn clone(&self) -> Fail {
+            if self.0 == 2 {
+                panic!();
+            }
+            Fail(self.0, self.1.clone())
+        }
+    }
+
+    let s: &[Fail] =
+        &[Fail(0, "foo".to_string()), Fail(1, "bar".to_string()), Fail(2, "baz".to_string())];
+
+    // Should panic, but not cause memory corruption
+    let _r: Rc<[Fail]> = Rc::from(s);
+}
+
+#[test]
+fn test_from_box() {
+    let b: Box<u32> = Box::new(123);
+    let r: Rc<u32> = Rc::from(b);
+
+    assert_eq!(*r, 123);
+}
+
+#[test]
+fn test_from_box_str() {
+    use std::string::String;
+
+    let s = String::from("foo").into_boxed_str();
+    assert_eq!((&&&s).as_str(), "foo");
+
+    let r: Rc<str> = Rc::from(s);
+    assert_eq!((&r).as_str(), "foo");
+    assert_eq!(r.as_str(), "foo");
+
+    assert_eq!(&r[..], "foo");
+}
+
+#[test]
+fn test_from_box_slice() {
+    let s = vec![1, 2, 3].into_boxed_slice();
+    let r: Rc<[u32]> = Rc::from(s);
+
+    assert_eq!(&r[..], [1, 2, 3]);
+}
+
+#[test]
+fn test_from_box_trait() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let b: Box<dyn Display> = Box::new(123);
+    let r: Rc<dyn Display> = Rc::from(b);
+
+    assert_eq!(r.to_string(), "123");
+}
+
+#[test]
+fn test_from_box_trait_zero_sized() {
+    use std::fmt::Debug;
+
+    let b: Box<dyn Debug> = Box::new(());
+    let r: Rc<dyn Debug> = Rc::from(b);
+
+    assert_eq!(format!("{r:?}"), "()");
+}
+
+#[test]
+fn test_from_vec() {
+    let v = vec![1, 2, 3];
+    let r: Rc<[u32]> = Rc::from(v);
+
+    assert_eq!(&r[..], [1, 2, 3]);
+}
+
+#[test]
+fn test_downcast() {
+    use std::any::Any;
+
+    let r1: Rc<dyn Any> = Rc::new(i32::MAX);
+    let r2: Rc<dyn Any> = Rc::new("abc");
+
+    assert!(r1.clone().downcast::<u32>().is_err());
+
+    let r1i32 = r1.downcast::<i32>();
+    assert!(r1i32.is_ok());
+    assert_eq!(r1i32.unwrap(), Rc::new(i32::MAX));
+
+    assert!(r2.clone().downcast::<i32>().is_err());
+
+    let r2str = r2.downcast::<&'static str>();
+    assert!(r2str.is_ok());
+    assert_eq!(r2str.unwrap(), Rc::new("abc"));
+}
+
+#[test]
+fn test_array_from_slice() {
+    let v = vec![1, 2, 3];
+    let r: Rc<[u32]> = Rc::from(v);
+
+    let a: Result<Rc<[u32; 3]>, _> = r.clone().try_into();
+    assert!(a.is_ok());
+
+    let a: Result<Rc<[u32; 2]>, _> = r.clone().try_into();
+    assert!(a.is_err());
+}
+
+#[test]
+fn test_rc_cyclic_with_zero_refs() {
+    struct ZeroRefs {
+        inner: Weak<ZeroRefs>,
+    }
+
+    let zero_refs = Rc::new_cyclic(|inner| {
+        assert_eq!(inner.strong_count(), 0);
+        assert!(inner.upgrade().is_none());
+        ZeroRefs { inner: Weak::new() }
+    });
+
+    assert_eq!(Rc::strong_count(&zero_refs), 1);
+    assert_eq!(Rc::weak_count(&zero_refs), 0);
+    assert_eq!(zero_refs.inner.strong_count(), 0);
+    assert_eq!(zero_refs.inner.weak_count(), 0);
+}
+
+#[test]
+fn test_rc_cyclic_with_one_ref() {
+    struct OneRef {
+        inner: Weak<OneRef>,
+    }
+
+    let one_ref = Rc::new_cyclic(|inner| {
+        assert_eq!(inner.strong_count(), 0);
+        assert!(inner.upgrade().is_none());
+        OneRef { inner: inner.clone() }
+    });
+
+    assert_eq!(Rc::strong_count(&one_ref), 1);
+    assert_eq!(Rc::weak_count(&one_ref), 1);
+
+    let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap();
+    assert!(Rc::ptr_eq(&one_ref, &one_ref2));
+
+    assert_eq!(one_ref.inner.strong_count(), 2);
+    assert_eq!(one_ref.inner.weak_count(), 1);
+}
+
+#[test]
+fn test_rc_cyclic_with_two_ref() {
+    struct TwoRefs {
+        inner: Weak<TwoRefs>,
+        inner1: Weak<TwoRefs>,
+    }
+
+    let two_refs = Rc::new_cyclic(|inner| {
+        assert_eq!(inner.strong_count(), 0);
+        assert!(inner.upgrade().is_none());
+        TwoRefs { inner: inner.clone(), inner1: inner.clone() }
+    });
+
+    assert_eq!(Rc::strong_count(&two_refs), 1);
+    assert_eq!(Rc::weak_count(&two_refs), 2);
+
+    let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap();
+    assert!(Rc::ptr_eq(&two_refs, &two_ref3));
+
+    let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap();
+    assert!(Rc::ptr_eq(&two_refs, &two_ref2));
+
+    assert_eq!(Rc::strong_count(&two_refs), 3);
+    assert_eq!(Rc::weak_count(&two_refs), 2);
+}
+
+#[test]
+fn test_unique_rc_weak() {
+    let rc = UniqueRc::new(42);
+    let weak = UniqueRc::downgrade(&rc);
+    assert!(weak.upgrade().is_none());
+
+    let _rc = UniqueRc::into_rc(rc);
+    assert_eq!(*weak.upgrade().unwrap(), 42);
+}
+
+#[test]
+fn test_unique_rc_drop_weak() {
+    let rc = UniqueRc::new(42);
+    let weak = UniqueRc::downgrade(&rc);
+    mem::drop(weak);
+
+    let rc = UniqueRc::into_rc(rc);
+    assert_eq!(*rc, 42);
+}
+
+#[test]
+fn test_unique_rc_drops_contents() {
+    let mut dropped = false;
+    struct DropMe<'a>(&'a mut bool);
+    impl Drop for DropMe<'_> {
+        fn drop(&mut self) {
+            *self.0 = true;
+        }
+    }
+    {
+        let rc = UniqueRc::new(DropMe(&mut dropped));
+        drop(rc);
+    }
+    assert!(dropped);
+}
+
+/// Exercise the non-default allocator usage.
+#[test]
+fn test_unique_rc_with_alloc_drops_contents() {
+    let mut dropped = false;
+    struct DropMe<'a>(&'a mut bool);
+    impl Drop for DropMe<'_> {
+        fn drop(&mut self) {
+            *self.0 = true;
+        }
+    }
+    {
+        let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System);
+        drop(rc);
+    }
+    assert!(dropped);
+}
+
+#[test]
+fn test_unique_rc_weak_clone_holding_ref() {
+    let mut v = UniqueRc::new(0u8);
+    let w = UniqueRc::downgrade(&v);
+    let r = &mut *v;
+    let _ = w.clone(); // touch weak count
+    *r = 123;
+}
+
+#[test]
+fn test_unique_rc_unsizing_coercion() {
+    let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]);
+    assert_eq!(rc.len(), 3);
+    rc[0] = 123;
+    let rc: Rc<[u8]> = UniqueRc::into_rc(rc);
+    assert_eq!(*rc, [123, 0, 0]);
+}

From 701bedc323b0314ef6f084ba98ed18327faa36bc Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Thu, 6 Feb 2025 12:09:45 +0000
Subject: [PATCH 25/27] Move last remaining Rc test to alloctests

---
 library/alloc/src/{rc/mod.rs => rc.rs} |  3 ---
 library/alloc/src/rc/tests.rs          | 15 ---------------
 library/alloctests/tests/rc.rs         | 18 ++++++++++++++++++
 3 files changed, 18 insertions(+), 18 deletions(-)
 rename library/alloc/src/{rc/mod.rs => rc.rs} (99%)
 delete mode 100644 library/alloc/src/rc/tests.rs

diff --git a/library/alloc/src/rc/mod.rs b/library/alloc/src/rc.rs
similarity index 99%
rename from library/alloc/src/rc/mod.rs
rename to library/alloc/src/rc.rs
index 09206c2f8b29..2a4d4f264444 100644
--- a/library/alloc/src/rc/mod.rs
+++ b/library/alloc/src/rc.rs
@@ -276,9 +276,6 @@ use crate::string::String;
 #[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
-#[cfg(test)]
-mod tests;
-
 // This is repr(C) to future-proof against possible field-reordering, which
 // would interfere with otherwise safe [into|from]_raw() of transmutable
 // inner types.
diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
deleted file mode 100644
index 35ff6b7d570d..000000000000
--- a/library/alloc/src/rc/tests.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use super::*;
-
-#[test]
-fn is_unique() {
-    let x = Rc::new(3);
-    assert!(Rc::is_unique(&x));
-    let y = x.clone();
-    assert!(!Rc::is_unique(&x));
-    drop(y);
-    assert!(Rc::is_unique(&x));
-    let w = Rc::downgrade(&x);
-    assert!(!Rc::is_unique(&x));
-    drop(w);
-    assert!(Rc::is_unique(&x));
-}
diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs
index 0628011ba682..bb68eb4ac9e3 100644
--- a/library/alloctests/tests/rc.rs
+++ b/library/alloctests/tests/rc.rs
@@ -315,6 +315,24 @@ fn weak_self_cyclic() {
     // hopefully we don't double-free (or leak)...
 }
 
+#[test]
+fn is_unique() {
+    fn is_unique<T>(this: &Rc<T>) -> bool {
+        Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
+    }
+
+    let x = Rc::new(3);
+    assert!(is_unique(&x));
+    let y = x.clone();
+    assert!(!is_unique(&x));
+    drop(y);
+    assert!(is_unique(&x));
+    let w = Rc::downgrade(&x);
+    assert!(!is_unique(&x));
+    drop(w);
+    assert!(is_unique(&x));
+}
+
 #[test]
 fn test_strong_count() {
     let a = Rc::new(0);

From ae5687e4b0a375d3307856fb81810f6cc9019be5 Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Thu, 6 Feb 2025 12:46:33 +0000
Subject: [PATCH 26/27] Fully test the alloc crate through alloctests

For the tests that make use of internal implementation details, we
include the module to test using #[path] in alloctests now.
---
 ...le-f16-and-f128-in-compiler-builtins.patch |   6 +-
 library/Cargo.lock                            |   2 -
 library/alloc/Cargo.toml                      |   8 +-
 library/alloc/src/alloc.rs                    |  18 +-
 library/alloc/src/borrow.rs                   |   6 +-
 library/alloc/src/bstr.rs                     |  20 --
 .../alloc/src/collections/binary_heap/mod.rs  |   5 +-
 library/alloc/src/collections/mod.rs          |  21 ++
 .../alloc/src/collections/vec_deque/mod.rs    |   1 +
 .../src/collections/vec_deque/spec_extend.rs  |   2 +
 .../collections/vec_deque/spec_from_iter.rs   |   1 +
 library/alloc/src/ffi/c_str.rs                |  16 +-
 library/alloc/src/lib.rs                      |  39 +---
 library/alloc/src/macros.rs                   |  23 +--
 library/alloc/src/raw_vec/mod.rs              |   1 +
 library/alloc/src/rc.rs                       |   7 +-
 library/alloc/src/slice.rs                    | 182 +++++++-----------
 library/alloc/src/str.rs                      |   3 -
 library/alloc/src/string.rs                   |  30 +--
 library/alloc/src/sync.rs                     |   4 +-
 library/alloc/src/vec/into_iter.rs            |   5 -
 library/alloc/src/vec/mod.rs                  |  47 +----
 library/alloctests/Cargo.toml                 |   5 +-
 library/alloctests/lib.rs                     |  91 ++++++++-
 .../src => alloctests}/testing/crash_test.rs  |   0
 .../{alloc/src => alloctests}/testing/mod.rs  |   0
 .../src => alloctests}/testing/ord_chaos.rs   |   0
 .../{alloc/src => alloctests}/testing/rng.rs  |   0
 28 files changed, 232 insertions(+), 311 deletions(-)
 rename library/{alloc/src => alloctests}/testing/crash_test.rs (100%)
 rename library/{alloc/src => alloctests}/testing/mod.rs (100%)
 rename library/{alloc/src => alloctests}/testing/ord_chaos.rs (100%)
 rename library/{alloc/src => alloctests}/testing/rng.rs (100%)

diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
index c2027863b00b..754025ff49db 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644
 --- a/library/alloc/Cargo.toml
 +++ b/library/alloc/Cargo.toml
 @@ -11,7 +11,7 @@ test = { path = "../test" }
- edition = "2021"
+ bench = false
  
  [dependencies]
  core = { path = "../core", public = true }
 -compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
 +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] }
  
- [dev-dependencies]
- rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+ [features]
+ compiler-builtins-mem = ['compiler_builtins/mem']
 -- 
 2.34.1
 
diff --git a/library/Cargo.lock b/library/Cargo.lock
index bdf50a5b383e..405c69d95686 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -30,8 +30,6 @@ version = "0.0.0"
 dependencies = [
  "compiler_builtins",
  "core",
- "rand",
- "rand_xorshift",
 ]
 
 [[package]]
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index d9e1c9b38a8c..dbdf292433be 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,14 +10,14 @@ autotests = false
 autobenches = false
 edition = "2021"
 
+[lib]
+test = false
+bench = false
+
 [dependencies]
 core = { path = "../core", public = true }
 compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] }
 
-[dev-dependencies]
-rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
-rand_xorshift = "0.4.0"
-
 [features]
 compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 3bfdc68dcdaf..2f752f6eb394 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -5,9 +5,7 @@
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
 pub use core::alloc::*;
-#[cfg(not(test))]
 use core::hint;
-#[cfg(not(test))]
 use core::ptr::{self, NonNull};
 
 unsafe extern "Rust" {
@@ -44,14 +42,10 @@ unsafe extern "Rust" {
 /// accessed through the [free functions in `alloc`](self#functions).
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
-#[cfg(not(test))]
 // the compiler needs to know when a Box uses the global allocator vs a custom one
 #[lang = "global_alloc_ty"]
 pub struct Global;
 
-#[cfg(test)]
-pub use std::alloc::Global;
-
 /// Allocates memory with the global allocator.
 ///
 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
@@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
     }
 }
 
-#[cfg(not(test))]
 impl Global {
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -246,7 +239,6 @@ impl Global {
 }
 
 #[unstable(feature = "allocator_api", issue = "32838")]
-#[cfg(not(test))]
 unsafe impl Allocator for Global {
     #[inline]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -346,7 +338,7 @@ unsafe impl Allocator for Global {
 }
 
 /// The allocator for `Box`.
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[lang = "exchange_malloc"]
 #[inline]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -395,7 +387,7 @@ unsafe extern "Rust" {
 /// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[cold]
 #[optimize(size)]
 pub const fn handle_alloc_error(layout: Layout) -> ! {
@@ -419,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
     ct_error(layout)
 }
 
-// For alloc test `std::alloc::handle_alloc_error` can be used directly.
-#[cfg(all(not(no_global_oom_handling), test))]
-pub use std::alloc::handle_alloc_error;
-
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 17dad3277b95..07f51b7614ff 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -32,7 +32,7 @@ where
 /// implementing the `Clone` trait. But `Clone` works only for going from `&T`
 /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
 /// from any borrow of a given type.
-#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")]
+#[rustc_diagnostic_item = "ToOwned"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ToOwned {
     /// The resulting type after obtaining ownership.
@@ -54,7 +54,7 @@ pub trait ToOwned {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "cloning is often expensive and is not expected to have side effects"]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")]
+    #[rustc_diagnostic_item = "to_owned_method"]
     fn to_owned(&self) -> Self::Owned;
 
     /// Uses borrowed data to replace owned data, usually by cloning.
@@ -175,7 +175,7 @@ where
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")]
+#[rustc_diagnostic_item = "Cow"]
 pub enum Cow<'a, B: ?Sized + 'a>
 where
     B: ToOwned,
diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs
index 61e61019b508..338c7ac7f887 100644
--- a/library/alloc/src/bstr.rs
+++ b/library/alloc/src/bstr.rs
@@ -12,13 +12,10 @@ use core::ops::{
     Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive,
     RangeTo, RangeToInclusive,
 };
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use core::str::FromStr;
 use core::{fmt, hash};
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use crate::borrow::{Cow, ToOwned};
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 use crate::boxed::Box;
 #[cfg(not(no_rc))]
 use crate::rc::Rc;
@@ -181,7 +178,6 @@ impl Default for ByteString {
 
 // Omitted due to inference failures
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a, const N: usize> From<&'a [u8; N]> for ByteString {
 //     #[inline]
@@ -190,7 +186,6 @@ impl Default for ByteString {
 //     }
 // }
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<const N: usize> From<[u8; N]> for ByteString {
 //     #[inline]
@@ -199,7 +194,6 @@ impl Default for ByteString {
 //     }
 // }
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a> From<&'a [u8]> for ByteString {
 //     #[inline]
@@ -226,7 +220,6 @@ impl From<ByteString> for Vec<u8> {
 
 // Omitted due to inference failures
 //
-// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 // #[unstable(feature = "bstr", issue = "134915")]
 // impl<'a> From<&'a str> for ByteString {
 //     #[inline]
@@ -243,7 +236,6 @@ impl From<ByteString> for Vec<u8> {
 //     }
 // }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteStr> for ByteString {
     #[inline]
@@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<ByteString> for Cow<'a, ByteStr> {
     #[inline]
@@ -261,7 +252,6 @@ impl<'a> From<ByteString> for Cow<'a, ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> {
     #[inline]
@@ -330,7 +320,6 @@ impl FromIterator<ByteString> for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl FromStr for ByteString {
     type Err = core::convert::Infallible;
@@ -488,7 +477,6 @@ impl PartialEq for ByteString {
 
 macro_rules! impl_partial_eq_ord_cow {
     ($lhs:ty, $rhs:ty) => {
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialEq<$rhs> for $lhs {
@@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialEq<$lhs> for $rhs {
@@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialOrd<$rhs> for $lhs {
@@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow {
             }
         }
 
-        #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
         #[allow(unused_lifetimes)]
         #[unstable(feature = "bstr", issue = "134915")]
         impl<'a> PartialOrd<$lhs> for $rhs {
@@ -572,7 +557,6 @@ impl PartialOrd for ByteString {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl ToOwned for ByteStr {
     type Owned = ByteString;
@@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str {
 
 // Additional impls for `ByteStr` that require types from `alloc`:
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl Clone for Box<ByteStr> {
     #[inline]
@@ -614,7 +597,6 @@ impl Clone for Box<ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
     #[inline]
@@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl From<Box<[u8]>> for Box<ByteStr> {
     #[inline]
@@ -633,7 +614,6 @@ impl From<Box<[u8]>> for Box<ByteStr> {
     }
 }
 
-#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100
 #[unstable(feature = "bstr", issue = "134915")]
 impl From<Box<ByteStr>> for Box<[u8]> {
     #[inline]
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 965fd63a5298..b764b8fa5d97 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -153,7 +153,9 @@ use core::{fmt, ptr};
 use crate::alloc::Global;
 use crate::collections::TryReserveError;
 use crate::slice;
-use crate::vec::{self, AsVecIntoIter, Vec};
+#[cfg(not(test))]
+use crate::vec::AsVecIntoIter;
+use crate::vec::{self, Vec};
 
 /// A priority queue implemented with a binary heap.
 ///
@@ -1600,6 +1602,7 @@ unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
     const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1);
 }
 
+#[cfg(not(test))]
 unsafe impl<I> AsVecIntoIter for IntoIter<I> {
     type Item = I;
 
diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 020cf4d73651..1414f797e8a4 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -24,41 +24,54 @@ pub mod btree_map {
 pub mod btree_set {
     //! An ordered set based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(not(test))]
     pub use super::btree::set::*;
 }
 
+#[cfg(not(test))]
 use core::fmt::Display;
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use binary_heap::BinaryHeap;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use btree_map::BTreeMap;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use btree_set::BTreeSet;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use linked_list::LinkedList;
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
+#[cfg(not(test))]
 pub use vec_deque::VecDeque;
 
+#[cfg(not(test))]
 use crate::alloc::{Layout, LayoutError};
 
 /// The error type for `try_reserve` methods.
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 pub struct TryReserveError {
     kind: TryReserveErrorKind,
 }
 
+#[cfg(test)]
+pub use realalloc::collections::TryReserveError;
+
+#[cfg(not(test))]
 impl TryReserveError {
     /// Details about the allocation that caused the error
     #[inline]
@@ -80,6 +93,7 @@ impl TryReserveError {
     reason = "Uncertain how much info should be exposed",
     issue = "48043"
 )]
+#[cfg(not(test))]
 pub enum TryReserveErrorKind {
     /// Error due to the computed capacity exceeding the collection's maximum
     /// (usually `isize::MAX` bytes).
@@ -103,11 +117,15 @@ pub enum TryReserveErrorKind {
     },
 }
 
+#[cfg(test)]
+pub use realalloc::collections::TryReserveErrorKind;
+
 #[unstable(
     feature = "try_reserve_kind",
     reason = "Uncertain how much info should be exposed",
     issue = "48043"
 )]
+#[cfg(not(test))]
 impl From<TryReserveErrorKind> for TryReserveError {
     #[inline]
     fn from(kind: TryReserveErrorKind) -> Self {
@@ -116,6 +134,7 @@ impl From<TryReserveErrorKind> for TryReserveError {
 }
 
 #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")]
+#[cfg(not(test))]
 impl From<LayoutError> for TryReserveErrorKind {
     /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
     #[inline]
@@ -125,6 +144,7 @@ impl From<LayoutError> for TryReserveErrorKind {
 }
 
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 impl Display for TryReserveError {
     fn fmt(
         &self,
@@ -152,4 +172,5 @@ trait SpecExtend<I: IntoIterator> {
 }
 
 #[stable(feature = "try_reserve", since = "1.57.0")]
+#[cfg(not(test))]
 impl core::error::Error for TryReserveError {}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 299c8b8679e3..f8844e2d3a5c 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -645,6 +645,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// initialized rather than only supporting `0..len`.  Requires that
     /// `initialized.start` ≤ `initialized.end` ≤ `capacity`.
     #[inline]
+    #[cfg(not(test))]
     pub(crate) unsafe fn from_contiguous_raw_parts_in(
         ptr: *mut T,
         initialized: Range<usize>,
diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs
index d246385ca841..7c7072c4c3a1 100644
--- a/library/alloc/src/collections/vec_deque/spec_extend.rs
+++ b/library/alloc/src/collections/vec_deque/spec_extend.rs
@@ -3,6 +3,7 @@ use core::slice;
 
 use super::VecDeque;
 use crate::alloc::Allocator;
+#[cfg(not(test))]
 use crate::vec;
 
 // Specialization trait used for VecDeque::extend
@@ -78,6 +79,7 @@ where
     }
 }
 
+#[cfg(not(test))]
 impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
     #[track_caller]
     fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {
diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs
index 1efe84d6d7d7..c80a30c2103d 100644
--- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs
+++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs
@@ -19,6 +19,7 @@ where
     }
 }
 
+#[cfg(not(test))]
 impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
     #[inline]
     fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index fd93045a5ac4..f6743c657109 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::Rc;
-use crate::slice::hack::into_vec;
 use crate::string::String;
 #[cfg(target_has_atomic = "ptr")]
 use crate::sync::Arc;
@@ -103,7 +102,7 @@ use crate::vec::Vec;
 /// of `CString` instances can lead to invalid memory accesses, memory leaks,
 /// and other memory errors.
 #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
+#[rustc_diagnostic_item = "cstring_type"]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub struct CString {
     // Invariant 1: the slice ends with a zero byte and has a length of at least one.
@@ -491,7 +490,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes(self) -> Vec<u8> {
-        let mut vec = into_vec(self.into_inner());
+        let mut vec = self.into_inner().into_vec();
         let _nul = vec.pop();
         debug_assert_eq!(_nul, Some(0u8));
         vec
@@ -512,7 +511,7 @@ impl CString {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_bytes_with_nul(self) -> Vec<u8> {
-        into_vec(self.into_inner())
+        self.into_inner().into_vec()
     }
 
     /// Returns the contents of this `CString` as a slice of bytes.
@@ -573,7 +572,7 @@ impl CString {
     #[inline]
     #[must_use]
     #[stable(feature = "as_c_str", since = "1.20.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")]
+    #[rustc_diagnostic_item = "cstring_as_c_str"]
     pub fn as_c_str(&self) -> &CStr {
         &*self
     }
@@ -755,7 +754,6 @@ impl<'a> From<Cow<'a, CStr>> for CString {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "box_from_c_str", since = "1.17.0")]
 impl From<&CStr> for Box<CStr> {
     /// Converts a `&CStr` into a `Box<CStr>`,
@@ -766,7 +764,6 @@ impl From<&CStr> for Box<CStr> {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "box_from_mut_slice", since = "1.84.0")]
 impl From<&mut CStr> for Box<CStr> {
     /// Converts a `&mut CStr` into a `Box<CStr>`,
@@ -845,7 +842,6 @@ impl TryFrom<CString> for String {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "more_box_slice_clone", since = "1.29.0")]
 impl Clone for Box<CStr> {
     #[inline]
@@ -971,7 +967,6 @@ impl Default for Rc<CStr> {
     }
 }
 
-#[cfg(not(test))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
     fn default() -> Box<CStr> {
@@ -1080,7 +1075,7 @@ impl ToOwned for CStr {
     }
 
     fn clone_into(&self, target: &mut CString) {
-        let mut b = into_vec(mem::take(&mut target.inner));
+        let mut b = mem::take(&mut target.inner).into_vec();
         self.to_bytes_with_nul().clone_into(&mut b);
         target.inner = b.into_boxed_slice();
     }
@@ -1113,7 +1108,6 @@ impl AsRef<CStr> for CString {
     }
 }
 
-#[cfg(not(test))]
 impl CStr {
     /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
     ///
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index cb93100f56cf..84bbc5a29739 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -92,7 +92,6 @@
 //
 // Library features:
 // tidy-alphabetical-start
-#![cfg_attr(test, feature(str_as_str))]
 #![feature(alloc_layout_extra)]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
@@ -159,13 +158,11 @@
 //
 // Language features:
 // tidy-alphabetical-start
-#![cfg_attr(not(test), feature(coroutine_trait))]
-#![cfg_attr(test, feature(panic_update_hook))]
-#![cfg_attr(test, feature(test))]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(cfg_sanitize)]
 #![feature(const_precise_live_drops)]
+#![feature(coroutine_trait)]
 #![feature(decl_macro)]
 #![feature(dropck_eyepatch)]
 #![feature(fundamental)]
@@ -198,15 +195,6 @@
 // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
 #![feature(intra_doc_pointers)]
 
-// Allow testing this library
-#[cfg(test)]
-#[macro_use]
-extern crate std;
-#[cfg(test)]
-extern crate test;
-#[cfg(test)]
-mod testing;
-
 // Module with internal macros used by other modules (needs to be included before other modules).
 #[macro_use]
 mod macros;
@@ -214,7 +202,6 @@ mod macros;
 mod raw_vec;
 
 // Heaps provided for low-level allocation strategies
-
 pub mod alloc;
 
 // Primitive types using the heaps above
@@ -222,13 +209,8 @@ pub mod alloc;
 // Need to conditionally define the mod from `boxed.rs` to avoid
 // duplicating the lang-items when building in test cfg; but also need
 // to allow code to have `use boxed::Box;` declarations.
-#[cfg(not(test))]
-pub mod boxed;
-#[cfg(test)]
-mod boxed {
-    pub(crate) use std::boxed::Box;
-}
 pub mod borrow;
+pub mod boxed;
 #[unstable(feature = "bstr", issue = "134915")]
 pub mod bstr;
 pub mod collections;
@@ -252,20 +234,3 @@ pub mod __export {
     pub use core::format_args;
     pub use core::hint::must_use;
 }
-
-#[cfg(test)]
-#[allow(dead_code)] // Not used in all configurations
-pub(crate) mod test_helpers {
-    /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
-    /// seed not being the same for every RNG invocation too.
-    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
-        use std::hash::{BuildHasher, Hash, Hasher};
-        let mut hasher = std::hash::RandomState::new().build_hasher();
-        std::panic::Location::caller().hash(&mut hasher);
-        let hc64 = hasher.finish();
-        let seed_vec =
-            hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
-        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
-        rand::SeedableRng::from_seed(seed)
-    }
-}
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index c000fd6f4efa..214192b8c9a9 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -34,7 +34,7 @@
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(not(no_global_oom_handling))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -55,25 +55,6 @@ macro_rules! vec {
     );
 }
 
-// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
-// required for this macro definition, is not available. Instead use the
-// `slice::into_vec`  function which is only available with cfg(test)
-// NB see the slice::hack module in slice.rs for more information
-#[cfg(all(not(no_global_oom_handling), test))]
-#[allow(unused_macro_rules)]
-macro_rules! vec {
-    () => (
-        $crate::vec::Vec::new()
-    );
-    ($elem:expr; $n:expr) => (
-        $crate::vec::from_elem($elem, $n)
-    );
-    ($($x:expr),*) => (
-        $crate::slice::into_vec($crate::boxed::Box::new([$($x),*]))
-    );
-    ($($x:expr,)*) => (vec![$($x),*])
-}
-
 /// Creates a `String` using interpolation of runtime expressions.
 ///
 /// The first argument `format!` receives is a format string. This must be a string
@@ -120,7 +101,7 @@ macro_rules! vec {
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable(hint_must_use, liballoc_internals)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
+#[rustc_diagnostic_item = "format_macro"]
 macro_rules! format {
     ($($arg:tt)*) => {
         $crate::__export::must_use({
diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs
index 70f32fbaab42..f1f5ffefb9b7 100644
--- a/library/alloc/src/raw_vec/mod.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -1,4 +1,5 @@
 #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
+#![cfg_attr(test, allow(dead_code))]
 
 use core::marker::PhantomData;
 use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 2a4d4f264444..fe0b25f31b92 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -262,14 +262,11 @@ use core::ptr::{self, NonNull, drop_in_place};
 #[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 use core::{borrow, fmt, hint};
-#[cfg(test)]
-use std::boxed::Box;
 
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::handle_alloc_error;
 use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
-#[cfg(not(test))]
 use crate::boxed::Box;
 #[cfg(not(no_global_oom_handling))]
 use crate::string::String;
@@ -306,7 +303,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout {
 ///
 /// [get_mut]: Rc::get_mut
 #[doc(search_unbox)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
+#[rustc_diagnostic_item = "Rc"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_insignificant_dtor]
 pub struct Rc<
@@ -2981,7 +2978,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
 ///
 /// [`upgrade`]: Weak::upgrade
 #[stable(feature = "rc_weak", since = "1.4.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")]
+#[rustc_diagnostic_item = "RcWeak"]
 pub struct Weak<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 8baf96850626..7c5d22e1ee9b 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -8,9 +8,6 @@
 //! A few functions are provided to create a slice from a value reference
 //! or from a raw pointer.
 #![stable(feature = "rust1", since = "1.0.0")]
-// Many of the usings in this module are only used in the test configuration.
-// It's cleaner to just turn off the unused_imports warning than to fix them.
-#![cfg_attr(test, allow(unused_imports, dead_code))]
 
 use core::borrow::{Borrow, BorrowMut};
 #[cfg(not(no_global_oom_handling))]
@@ -63,16 +60,6 @@ pub use core::slice::{range, try_range};
 ////////////////////////////////////////////////////////////////////////////////
 // Basic slice extension methods
 ////////////////////////////////////////////////////////////////////////////////
-
-// HACK(japaric) needed for the implementation of `vec!` macro during testing
-// N.B., see the `hack` module in this file for more details.
-#[cfg(test)]
-pub use hack::into_vec;
-// HACK(japaric) needed for the implementation of `Vec::clone` during testing
-// N.B., see the `hack` module in this file for more details.
-#[cfg(test)]
-pub use hack::to_vec;
-
 use crate::alloc::Allocator;
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::Global;
@@ -81,98 +68,6 @@ use crate::borrow::ToOwned;
 use crate::boxed::Box;
 use crate::vec::Vec;
 
-// HACK(japaric): With cfg(test) `impl [T]` is not available, these three
-// functions are actually methods that are in `impl [T]` but not in
-// `core::slice::SliceExt` - we need to supply these functions for the
-// `test_permutations` test
-#[allow(unreachable_pub)] // cfg(test) pub above
-pub(crate) mod hack {
-    use core::alloc::Allocator;
-
-    use crate::boxed::Box;
-    use crate::vec::Vec;
-
-    // We shouldn't add inline attribute to this since this is used in
-    // `vec!` macro mostly and causes perf regression. See #71204 for
-    // discussion and perf results.
-    #[allow(missing_docs)]
-    pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
-        unsafe {
-            let len = b.len();
-            let (b, alloc) = Box::into_raw_with_allocator(b);
-            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
-        }
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    #[allow(missing_docs)]
-    #[inline]
-    pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> {
-        T::to_vec(s, alloc)
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    pub trait ConvertVec {
-        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
-        where
-            Self: Sized;
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    impl<T: Clone> ConvertVec for T {
-        #[inline]
-        default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
-            struct DropGuard<'a, T, A: Allocator> {
-                vec: &'a mut Vec<T, A>,
-                num_init: usize,
-            }
-            impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
-                #[inline]
-                fn drop(&mut self) {
-                    // SAFETY:
-                    // items were marked initialized in the loop below
-                    unsafe {
-                        self.vec.set_len(self.num_init);
-                    }
-                }
-            }
-            let mut vec = Vec::with_capacity_in(s.len(), alloc);
-            let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
-            let slots = guard.vec.spare_capacity_mut();
-            // .take(slots.len()) is necessary for LLVM to remove bounds checks
-            // and has better codegen than zip.
-            for (i, b) in s.iter().enumerate().take(slots.len()) {
-                guard.num_init = i;
-                slots[i].write(b.clone());
-            }
-            core::mem::forget(guard);
-            // SAFETY:
-            // the vec was allocated and initialized above to at least this length.
-            unsafe {
-                vec.set_len(s.len());
-            }
-            vec
-        }
-    }
-
-    #[cfg(not(no_global_oom_handling))]
-    impl<T: Copy> ConvertVec for T {
-        #[inline]
-        fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
-            let mut v = Vec::with_capacity_in(s.len(), alloc);
-            // SAFETY:
-            // allocated above with the capacity of `s`, and initialize to `s.len()` in
-            // ptr::copy_to_non_overlapping below.
-            unsafe {
-                s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
-                v.set_len(s.len());
-            }
-            v
-        }
-    }
-}
-
-#[cfg(not(test))]
 impl<T> [T] {
     /// Sorts the slice, preserving initial order of equal elements.
     ///
@@ -501,8 +396,64 @@ impl<T> [T] {
     where
         T: Clone,
     {
-        // N.B., see the `hack` module in this file for more details.
-        hack::to_vec(self, alloc)
+        return T::to_vec(self, alloc);
+
+        trait ConvertVec {
+            fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
+            where
+                Self: Sized;
+        }
+
+        impl<T: Clone> ConvertVec for T {
+            #[inline]
+            default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
+                struct DropGuard<'a, T, A: Allocator> {
+                    vec: &'a mut Vec<T, A>,
+                    num_init: usize,
+                }
+                impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
+                    #[inline]
+                    fn drop(&mut self) {
+                        // SAFETY:
+                        // items were marked initialized in the loop below
+                        unsafe {
+                            self.vec.set_len(self.num_init);
+                        }
+                    }
+                }
+                let mut vec = Vec::with_capacity_in(s.len(), alloc);
+                let mut guard = DropGuard { vec: &mut vec, num_init: 0 };
+                let slots = guard.vec.spare_capacity_mut();
+                // .take(slots.len()) is necessary for LLVM to remove bounds checks
+                // and has better codegen than zip.
+                for (i, b) in s.iter().enumerate().take(slots.len()) {
+                    guard.num_init = i;
+                    slots[i].write(b.clone());
+                }
+                core::mem::forget(guard);
+                // SAFETY:
+                // the vec was allocated and initialized above to at least this length.
+                unsafe {
+                    vec.set_len(s.len());
+                }
+                vec
+            }
+        }
+
+        impl<T: Copy> ConvertVec for T {
+            #[inline]
+            fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
+                let mut v = Vec::with_capacity_in(s.len(), alloc);
+                // SAFETY:
+                // allocated above with the capacity of `s`, and initialize to `s.len()` in
+                // ptr::copy_to_non_overlapping below.
+                unsafe {
+                    s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len());
+                    v.set_len(s.len());
+                }
+                v
+            }
+        }
     }
 
     /// Converts `self` into a vector without clones or allocation.
@@ -522,10 +473,13 @@ impl<T> [T] {
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")]
+    #[rustc_diagnostic_item = "slice_into_vec"]
     pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
-        // N.B., see the `hack` module in this file for more details.
-        hack::into_vec(self)
+        unsafe {
+            let len = self.len();
+            let (b, alloc) = Box::into_raw_with_allocator(self);
+            Vec::from_raw_parts_in(b as *mut T, len, len, alloc)
+        }
     }
 
     /// Creates a vector by copying a slice `n` times.
@@ -666,7 +620,6 @@ impl<T> [T] {
     }
 }
 
-#[cfg(not(test))]
 impl [u8] {
     /// Returns a vector containing a copy of this slice where each byte
     /// is mapped to its ASCII upper case equivalent.
@@ -883,14 +836,9 @@ impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> ToOwned for [T] {
     type Owned = Vec<T>;
-    #[cfg(not(test))]
-    fn to_owned(&self) -> Vec<T> {
-        self.to_vec()
-    }
 
-    #[cfg(test)]
     fn to_owned(&self) -> Vec<T> {
-        hack::to_vec(self, Global)
+        self.to_vec()
     }
 
     fn clone_into(&self, target: &mut Vec<T>) {
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 6fee8d3fe334..0664f2c3cf2c 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -219,7 +219,6 @@ impl ToOwned for str {
 }
 
 /// Methods for string slices.
-#[cfg(not(test))]
 impl str {
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
     ///
@@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
 #[unstable(feature = "str_internals", issue = "none")]
 #[doc(hidden)]
 #[inline]
-#[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
 pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
     // Process the input in chunks of 16 bytes to enable auto-vectorization.
@@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
     }
 }
 #[inline]
-#[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
 #[allow(dead_code)]
 /// Faster implementation of string replacement for ASCII to ASCII cases.
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 2c0347865498..2ba797ab2add 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -356,7 +356,7 @@ use crate::vec::{self, Vec};
 /// [`as_str()`]: String::as_str
 #[derive(PartialEq, PartialOrd, Eq, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), lang = "String")]
+#[lang = "String"]
 pub struct String {
     vec: Vec<u8>,
 }
@@ -438,7 +438,7 @@ impl String {
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")]
+    #[rustc_diagnostic_item = "string_new"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub const fn new() -> String {
@@ -501,17 +501,6 @@ impl String {
         Ok(String { vec: Vec::try_with_capacity(capacity)? })
     }
 
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Since we don't
-    // require this method for testing purposes, I'll just stub it
-    // NB see the slice::hack module in slice.rs for more information
-    #[inline]
-    #[cfg(test)]
-    #[allow(missing_docs)]
-    pub fn from_str(_: &str) -> String {
-        panic!("not available with cfg(test)");
-    }
-
     /// Converts a vector of bytes to a `String`.
     ///
     /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
@@ -570,7 +559,7 @@ impl String {
     /// [`into_bytes`]: String::into_bytes
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")]
+    #[rustc_diagnostic_item = "string_from_utf8"]
     pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
         match str::from_utf8(&vec) {
             Ok(..) => Ok(String { vec }),
@@ -1071,7 +1060,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
+    #[rustc_diagnostic_item = "string_as_str"]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     pub const fn as_str(&self) -> &str {
         // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
@@ -1094,7 +1083,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
+    #[rustc_diagnostic_item = "string_as_mut_str"]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     pub const fn as_mut_str(&mut self) -> &mut str {
         // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
@@ -1117,7 +1106,7 @@ impl String {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_confusables("append", "push")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")]
+    #[rustc_diagnostic_item = "string_push_str"]
     pub fn push_str(&mut self, string: &str) {
         self.vec.extend_from_slice(string.as_bytes())
     }
@@ -1755,7 +1744,7 @@ impl String {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "insert_str", since = "1.16.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")]
+    #[rustc_diagnostic_item = "string_insert_str"]
     pub fn insert_str(&mut self, idx: usize, string: &str) {
         assert!(self.is_char_boundary(idx));
 
@@ -2724,7 +2713,7 @@ impl FromStr for String {
 /// implementation for free.
 ///
 /// [`Display`]: fmt::Display
-#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")]
+#[rustc_diagnostic_item = "ToString"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ToString {
     /// Converts the given value to a `String`.
@@ -2739,7 +2728,7 @@ pub trait ToString {
     /// ```
     #[rustc_conversion_suggestion]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")]
+    #[rustc_diagnostic_item = "to_string_method"]
     fn to_string(&self) -> String;
 }
 
@@ -2979,7 +2968,6 @@ impl From<&String> for String {
 }
 
 // note: test pulls in std, which causes errors here
-#[cfg(not(test))]
 #[stable(feature = "string_from_box", since = "1.18.0")]
 impl From<Box<str>> for String {
     /// Converts the given boxed `str` slice to a [`String`].
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 1956dda53881..faee15ab0c66 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -234,7 +234,7 @@ macro_rules! acquire {
 ///
 /// [rc_examples]: crate::rc#examples
 #[doc(search_unbox)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
+#[rustc_diagnostic_item = "Arc"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_insignificant_dtor]
 pub struct Arc<
@@ -311,7 +311,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 ///
 /// [`upgrade`]: Weak::upgrade
 #[stable(feature = "arc_weak", since = "1.4.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")]
+#[rustc_diagnostic_item = "ArcWeak"]
 pub struct Weak<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 52597e41c1cf..3eee988b6c9d 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -472,14 +472,9 @@ where
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
-    #[cfg(not(test))]
     fn clone(&self) -> Self {
         self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter()
     }
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter()
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 49878f2b6fa5..ce6685405981 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -404,7 +404,7 @@ mod spec_extend;
 /// [owned slice]: Box
 /// [`into_boxed_slice`]: Vec::into_boxed_slice
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")]
+#[rustc_diagnostic_item = "Vec"]
 #[rustc_insignificant_dtor]
 pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
     buf: RawVec<T, A>,
@@ -428,7 +428,7 @@ impl<T> Vec<T> {
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")]
+    #[rustc_diagnostic_item = "vec_new"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub const fn new() -> Self {
@@ -489,7 +489,7 @@ impl<T> Vec<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")]
+    #[rustc_diagnostic_item = "vec_with_capacity"]
     #[track_caller]
     pub fn with_capacity(capacity: usize) -> Self {
         Self::with_capacity_in(capacity, Global)
@@ -1279,7 +1279,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[track_caller]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")]
+    #[rustc_diagnostic_item = "vec_reserve"]
     pub fn reserve(&mut self, additional: usize) {
         self.buf.reserve(self.len, additional);
     }
@@ -1568,7 +1568,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
+    #[rustc_diagnostic_item = "vec_as_slice"]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     pub const fn as_slice(&self) -> &[T] {
         // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
@@ -1600,7 +1600,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
+    #[rustc_diagnostic_item = "vec_as_mut_slice"]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     pub const fn as_mut_slice(&mut self) -> &mut [T] {
         // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
@@ -2511,7 +2511,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// Takes *O*(1) time.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")]
+    #[rustc_diagnostic_item = "vec_pop"]
     pub fn pop(&mut self) -> Option<T> {
         if self.len == 0 {
             None
@@ -2712,7 +2712,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// assert!(!v.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
+    #[rustc_diagnostic_item = "vec_is_empty"]
     #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
@@ -3193,7 +3193,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
 #[doc(hidden)]
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")]
+#[rustc_diagnostic_item = "vec_from_elem"]
 #[track_caller]
 pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
     <T as SpecFromElem>::from_elem(elem, n, Global)
@@ -3293,23 +3293,12 @@ unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {}
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
-    #[cfg(not(test))]
     #[track_caller]
     fn clone(&self) -> Self {
         let alloc = self.allocator().clone();
         <[T]>::to_vec_in(&**self, alloc)
     }
 
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec` function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn clone(&self) -> Self {
-        let alloc = self.allocator().clone();
-        crate::slice::to_vec(&**self, alloc)
-    }
-
     /// Overwrites the contents of `self` with a clone of the contents of `source`.
     ///
     /// This method is preferred over simply assigning `source.clone()` to `self`,
@@ -3854,15 +3843,10 @@ impl<T: Clone> From<&[T]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: &[T]) -> Vec<T> {
         s.to_vec()
     }
-    #[cfg(test)]
-    fn from(s: &[T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
 }
 
 #[cfg(not(no_global_oom_handling))]
@@ -3875,15 +3859,10 @@ impl<T: Clone> From<&mut [T]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: &mut [T]) -> Vec<T> {
         s.to_vec()
     }
-    #[cfg(test)]
-    fn from(s: &mut [T]) -> Vec<T> {
-        crate::slice::to_vec(s, Global)
-    }
 }
 
 #[cfg(not(no_global_oom_handling))]
@@ -3928,16 +3907,10 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> {
     /// ```
     /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]);
     /// ```
-    #[cfg(not(test))]
     #[track_caller]
     fn from(s: [T; N]) -> Vec<T> {
         <[T]>::into_vec(Box::new(s))
     }
-
-    #[cfg(test)]
-    fn from(s: [T; N]) -> Vec<T> {
-        crate::slice::into_vec(Box::new(s))
-    }
 }
 
 #[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
@@ -3966,7 +3939,6 @@ where
 }
 
 // note: test pulls in std, which causes errors here
-#[cfg(not(test))]
 #[stable(feature = "vec_from_box", since = "1.18.0")]
 impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
     /// Converts a boxed slice into a vector by transferring ownership of
@@ -3985,7 +3957,6 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
 
 // note: test pulls in std, which causes errors here
 #[cfg(not(no_global_oom_handling))]
-#[cfg(not(test))]
 #[stable(feature = "box_from_vec", since = "1.20.0")]
 impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
     /// Converts a vector into a boxed slice.
diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml
index f1a783b1e224..306375f5f01c 100644
--- a/library/alloctests/Cargo.toml
+++ b/library/alloctests/Cargo.toml
@@ -10,8 +10,9 @@ edition = "2021"
 
 [lib]
 path = "lib.rs"
-test = false
-bench = false
+test = true
+bench = true
+doc = false
 
 [dev-dependencies]
 rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs
index b49208cd4eb3..0b5aa2c575d9 100644
--- a/library/alloctests/lib.rs
+++ b/library/alloctests/lib.rs
@@ -1 +1,90 @@
-// Intentionally left empty.
+#![cfg(test)]
+#![allow(unused_attributes)]
+#![unstable(feature = "alloctests", issue = "none")]
+#![no_std]
+// Lints:
+#![deny(unsafe_op_in_unsafe_fn)]
+#![warn(deprecated_in_future)]
+#![warn(missing_debug_implementations)]
+#![allow(explicit_outlives_requirements)]
+#![allow(internal_features)]
+#![allow(rustdoc::redundant_explicit_links)]
+#![warn(rustdoc::unescaped_backticks)]
+#![deny(ffi_unwind_calls)]
+//
+// Library features:
+// tidy-alphabetical-start
+#![feature(alloc_layout_extra)]
+#![feature(allocator_api)]
+#![feature(array_into_iter_constructors)]
+#![feature(assert_matches)]
+#![feature(core_intrinsics)]
+#![feature(exact_size_is_empty)]
+#![feature(extend_one)]
+#![feature(extend_one_unchecked)]
+#![feature(hasher_prefixfree_extras)]
+#![feature(inplace_iteration)]
+#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
+#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array_transpose)]
+#![feature(ptr_internals)]
+#![feature(sized_type_properties)]
+#![feature(slice_iter_mut_as_mut_slice)]
+#![feature(slice_ptr_get)]
+#![feature(slice_range)]
+#![feature(std_internals)]
+#![feature(temporary_niche_types)]
+#![feature(trusted_fused)]
+#![feature(trusted_len)]
+#![feature(trusted_random_access)]
+#![feature(try_reserve_kind)]
+#![feature(try_trait_v2)]
+// tidy-alphabetical-end
+//
+// Language features:
+// tidy-alphabetical-start
+#![feature(cfg_sanitize)]
+#![feature(dropck_eyepatch)]
+#![feature(lang_items)]
+#![feature(min_specialization)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(optimize_attribute)]
+#![feature(rustc_allow_const_fn_unstable)]
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+#![feature(test)]
+#![rustc_preserve_ub_checks]
+// tidy-alphabetical-end
+
+// Allow testing this library
+extern crate alloc as realalloc;
+#[macro_use]
+extern crate std;
+#[cfg(test)]
+extern crate test;
+mod testing;
+use realalloc::*;
+
+#[path = "../alloc/src/collections/mod.rs"]
+mod collections;
+
+#[path = "../alloc/src/raw_vec/mod.rs"]
+mod raw_vec;
+
+#[allow(dead_code)] // Not used in all configurations
+pub(crate) mod test_helpers {
+    /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+    /// seed not being the same for every RNG invocation too.
+    pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+        use std::hash::{BuildHasher, Hash, Hasher};
+        let mut hasher = std::hash::RandomState::new().build_hasher();
+        std::panic::Location::caller().hash(&mut hasher);
+        let hc64 = hasher.finish();
+        let seed_vec =
+            hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
+        let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+        rand::SeedableRng::from_seed(seed)
+    }
+}
diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloctests/testing/crash_test.rs
similarity index 100%
rename from library/alloc/src/testing/crash_test.rs
rename to library/alloctests/testing/crash_test.rs
diff --git a/library/alloc/src/testing/mod.rs b/library/alloctests/testing/mod.rs
similarity index 100%
rename from library/alloc/src/testing/mod.rs
rename to library/alloctests/testing/mod.rs
diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs
similarity index 100%
rename from library/alloc/src/testing/ord_chaos.rs
rename to library/alloctests/testing/ord_chaos.rs
diff --git a/library/alloc/src/testing/rng.rs b/library/alloctests/testing/rng.rs
similarity index 100%
rename from library/alloc/src/testing/rng.rs
rename to library/alloctests/testing/rng.rs

From 22d0440993d6eab6e9faf35f729e2d52ba6d72a6 Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Thu, 13 Feb 2025 15:38:07 +0000
Subject: [PATCH 27/27] Add comments

---
 library/alloc/src/collections/mod.rs | 3 +++
 library/alloc/src/raw_vec/mod.rs     | 3 +++
 library/alloctests/lib.rs            | 3 +++
 3 files changed, 9 insertions(+)

diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs
index 1414f797e8a4..fac4d1a65abc 100644
--- a/library/alloc/src/collections/mod.rs
+++ b/library/alloc/src/collections/mod.rs
@@ -1,5 +1,8 @@
 //! Collection types.
 
+// Note: This module is also included in the alloctests crate using #[path] to
+// run the tests. See the comment there for an explanation why this is the case.
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[cfg(not(no_global_oom_handling))]
diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs
index f1f5ffefb9b7..99ebc5c4bfca 100644
--- a/library/alloc/src/raw_vec/mod.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -1,6 +1,9 @@
 #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
 #![cfg_attr(test, allow(dead_code))]
 
+// Note: This module is also included in the alloctests crate using #[path] to
+// run the tests. See the comment there for an explanation why this is the case.
+
 use core::marker::PhantomData;
 use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ptr::{self, NonNull, Unique};
diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs
index 0b5aa2c575d9..6ce8a6d9ca17 100644
--- a/library/alloctests/lib.rs
+++ b/library/alloctests/lib.rs
@@ -67,6 +67,9 @@ extern crate test;
 mod testing;
 use realalloc::*;
 
+// We are directly including collections and raw_vec here as both use non-public
+// methods and fields in tests and as such need to have the types to test in the
+// same crate as the tests themself.
 #[path = "../alloc/src/collections/mod.rs"]
 mod collections;