about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-30 23:46:42 +0000
committerbors <bors@rust-lang.org>2024-12-30 23:46:42 +0000
commit4e5fec2f1ea4b1cfecaa14304c9f56de59b344cb (patch)
tree1e4e8feb7ca476d0960112846baf5a49c8028b2a
parent7f75bfa1ad4e9a9d33a179a90603001515e91991 (diff)
parent3c0c1386878812780349be38080470c0b4fcdda2 (diff)
downloadrust-4e5fec2f1ea4b1cfecaa14304c9f56de59b344cb.tar.gz
rust-4e5fec2f1ea4b1cfecaa14304c9f56de59b344cb.zip
Auto merge of #134757 - RalfJung:const_swap, r=scottmcm
stabilize const_swap

libs-api FCP passed in https://github.com/rust-lang/rust/issues/83163.

However, I only just realized that this actually involves an intrinsic. The intrinsic could be implemented entirely with existing stable const functionality, but we choose to make it a primitive to be able to detect more UB. So nominating for `@rust-lang/lang`  to make sure they are aware; I leave it up to them whether they want to FCP this.

While at it I also renamed the intrinsic to make the "nonoverlapping" constraint more clear.

Fixes #83163
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs30
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--library/core/src/intrinsics/mod.rs22
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/mem/mod.rs4
-rw-r--r--library/core/src/ptr/mod.rs3
-rw-r--r--library/core/src/ptr/mut_ptr.rs2
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr (renamed from src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr)4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs13
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr15
-rw-r--r--tests/codegen/intrinsics/typed_swap.rs12
-rw-r--r--tests/ui/consts/issue-94371.rs2
-rw-r--r--tests/ui/consts/qualif-indirect-mutation-fail.rs1
-rw-r--r--tests/ui/consts/qualif-indirect-mutation-fail.stderr22
-rw-r--r--tests/ui/thread-local/thread-local-static.rs1
-rw-r--r--tests/ui/thread-local/thread-local-static.stderr4
28 files changed, 139 insertions, 95 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 299b98c0a4f..304ac4544ee 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // If we're swapping something that's *not* an `OperandValue::Ref`,
         // then we can do it directly and avoid the alloca.
         // Otherwise, we'll let the fallback MIR body take care of it.
-        if let sym::typed_swap = name {
+        if let sym::typed_swap_nonoverlapping = name {
             let pointee_ty = fn_args.type_at(0);
             let pointee_layout = bx.layout_of(pointee_ty);
             if !bx.is_backend_ref(pointee_layout)
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index b0138ac8bfe..3ee13b19f66 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -382,7 +382,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     /// Avoids `alloca`s for Immediates and ScalarPairs.
     ///
     /// FIXME: Maybe do something smarter for Ref types too?
-    /// For now, the `typed_swap` intrinsic just doesn't call this for those
+    /// For now, the `typed_swap_nonoverlapping` intrinsic just doesn't call this for those
     /// cases (in non-debug), preferring the fallback body instead.
     fn typed_place_swap(
         &mut self,
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 46720328ea4..99f0ac702c5 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -883,19 +883,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 .local_to_op(mir::RETURN_PLACE, None)
                 .expect("return place should always be live");
             let dest = self.frame().return_place.clone();
-            let res = if self.stack().len() == 1 {
-                // The initializer of constants and statics will get validated separately
-                // after the constant has been fully evaluated. While we could fall back to the default
-                // code path, that will cause -Zenforce-validity to cycle on static initializers.
-                // Reading from a static's memory is not allowed during its evaluation, and will always
-                // trigger a cycle error. Validation must read from the memory of the current item.
-                // For Miri this means we do not validate the root frame return value,
-                // but Miri anyway calls `read_target_isize` on that so separate validation
-                // is not needed.
-                self.copy_op_no_dest_validation(&op, &dest)
-            } else {
-                self.copy_op_allow_transmute(&op, &dest)
-            };
+            let res = self.copy_op_allow_transmute(&op, &dest);
             trace!("return value: {:?}", self.dump_place(&dest.into()));
             // We delay actually short-circuiting on this error until *after* the stack frame is
             // popped, since we want this error to be attributed to the caller, whose type defines
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index e9eca8814c3..0664a882c1d 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -424,8 +424,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
             }
-            sym::typed_swap => {
-                self.typed_swap_intrinsic(&args[0], &args[1])?;
+            sym::typed_swap_nonoverlapping => {
+                self.typed_swap_nonoverlapping_intrinsic(&args[0], &args[1])?;
             }
 
             sym::vtable_size => {
@@ -638,19 +638,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     }
 
     /// Does a *typed* swap of `*left` and `*right`.
-    fn typed_swap_intrinsic(
+    fn typed_swap_nonoverlapping_intrinsic(
         &mut self,
         left: &OpTy<'tcx, <M as Machine<'tcx>>::Provenance>,
         right: &OpTy<'tcx, <M as Machine<'tcx>>::Provenance>,
     ) -> InterpResult<'tcx> {
         let left = self.deref_pointer(left)?;
         let right = self.deref_pointer(right)?;
-        debug_assert_eq!(left.layout, right.layout);
+        assert_eq!(left.layout, right.layout);
+        assert!(left.layout.is_sized());
         let kind = MemoryKind::Stack;
         let temp = self.allocate(left.layout, kind)?;
-        self.copy_op(&left, &temp)?;
-        self.copy_op(&right, &left)?;
-        self.copy_op(&temp, &right)?;
+        self.copy_op(&left, &temp)?; // checks alignment of `left`
+
+        // We want to always enforce non-overlapping, even if this is a scalar type.
+        // Therefore we directly use the underlying `mem_copy` here.
+        self.mem_copy(right.ptr(), left.ptr(), left.layout.size, /*nonoverlapping*/ true)?;
+        // This means we also need to do the validation of the value that used to be in `right`
+        // ourselves. This value is now in `left.` The one that started out in `left` already got
+        // validated by the copy above.
+        if M::enforce_validity(self, left.layout) {
+            self.validate_operand(
+                &left.clone().into(),
+                M::enforce_validity_recursively(self, left.layout),
+                /*reset_provenance_and_padding*/ true,
+            )?;
+        }
+
+        self.copy_op(&temp, &right)?; // checks alignment of `right`
+
         self.deallocate_ptr(temp.ptr(), None, kind)?;
         interp_ok(())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 810e9356b26..0d974071619 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -775,31 +775,13 @@ where
 
     /// Copies the data from an operand to a place.
     /// The layouts of the `src` and `dest` may disagree.
-    /// Does not perform validation of the destination.
-    /// The only known use case for this function is checking the return
-    /// value of a static during stack frame popping.
-    #[inline(always)]
-    pub(super) fn copy_op_no_dest_validation(
-        &mut self,
-        src: &impl Projectable<'tcx, M::Provenance>,
-        dest: &impl Writeable<'tcx, M::Provenance>,
-    ) -> InterpResult<'tcx> {
-        self.copy_op_inner(
-            src, dest, /* allow_transmute */ true, /* validate_dest */ false,
-        )
-    }
-
-    /// Copies the data from an operand to a place.
-    /// The layouts of the `src` and `dest` may disagree.
     #[inline(always)]
     pub fn copy_op_allow_transmute(
         &mut self,
         src: &impl Projectable<'tcx, M::Provenance>,
         dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        self.copy_op_inner(
-            src, dest, /* allow_transmute */ true, /* validate_dest */ true,
-        )
+        self.copy_op_inner(src, dest, /* allow_transmute */ true)
     }
 
     /// Copies the data from an operand to a place.
@@ -810,9 +792,7 @@ where
         src: &impl Projectable<'tcx, M::Provenance>,
         dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
-        self.copy_op_inner(
-            src, dest, /* allow_transmute */ false, /* validate_dest */ true,
-        )
+        self.copy_op_inner(src, dest, /* allow_transmute */ false)
     }
 
     /// Copies the data from an operand to a place.
@@ -824,22 +804,21 @@ where
         src: &impl Projectable<'tcx, M::Provenance>,
         dest: &impl Writeable<'tcx, M::Provenance>,
         allow_transmute: bool,
-        validate_dest: bool,
     ) -> InterpResult<'tcx> {
         // These are technically *two* typed copies: `src` is a not-yet-loaded value,
-        // so we're going a typed copy at `src` type from there to some intermediate storage.
+        // so we're doing a typed copy at `src` type from there to some intermediate storage.
         // And then we're doing a second typed copy from that intermediate storage to `dest`.
         // But as an optimization, we only make a single direct copy here.
 
         // Do the actual copy.
         self.copy_op_no_validate(src, dest, allow_transmute)?;
 
-        if validate_dest && M::enforce_validity(self, dest.layout()) {
+        if M::enforce_validity(self, dest.layout()) {
             let dest = dest.to_place();
             // Given that there were two typed copies, we have to ensure this is valid at both types,
             // and we have to ensure this loses provenance and padding according to both types.
             // But if the types are identical, we only do one pass.
-            if allow_transmute && src.layout().ty != dest.layout().ty {
+            if src.layout().ty != dest.layout().ty {
                 self.validate_operand(
                     &dest.transmute(src.layout(), self)?,
                     M::enforce_validity_recursively(self, src.layout()),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 427ef141c72..fd78bf3e8fc 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -501,7 +501,9 @@ pub fn check_intrinsic_type(
                 (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)
             }
 
-            sym::typed_swap => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit),
+            sym::typed_swap_nonoverlapping => {
+                (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit)
+            }
 
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1b017a07d60..4ecc4201f89 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2059,7 +2059,7 @@ symbols! {
         type_macros,
         type_name,
         type_privacy_lints,
-        typed_swap,
+        typed_swap_nonoverlapping,
         u128,
         u128_legacy_const_max,
         u128_legacy_const_min,
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 65e2dcbc7cc..b5c31d82467 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -3969,6 +3969,21 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
     false
 }
 
+#[rustc_nounwind]
+#[inline]
+#[rustc_intrinsic]
+#[rustc_intrinsic_const_stable_indirect]
+#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic
+#[cfg(bootstrap)]
+pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
+    // SAFETY: The caller provided single non-overlapping items behind
+    // pointers, so swapping them with `count: 1` is fine.
+    unsafe { ptr::swap_nonoverlapping(x, y, 1) };
+}
+
+#[cfg(bootstrap)]
+pub use typed_swap as typed_swap_nonoverlapping;
+
 /// Non-overlapping *typed* swap of a single value.
 ///
 /// The codegen backends will replace this with a better implementation when
@@ -3982,9 +3997,10 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
 #[rustc_nounwind]
 #[inline]
 #[rustc_intrinsic]
-// Const-unstable because `swap_nonoverlapping` is const-unstable.
-#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")]
-pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
+#[rustc_intrinsic_const_stable_indirect]
+#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic
+#[cfg(not(bootstrap))]
+pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
     // SAFETY: The caller provided single non-overlapping items behind
     // pointers, so swapping them with `count: 1` is fine.
     unsafe { ptr::swap_nonoverlapping(x, y, 1) };
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 82d7d045bf5..0d8a3811ede 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -112,7 +112,6 @@
 #![feature(asm_experimental_arch)]
 #![feature(const_carrying_mul_add)]
 #![feature(const_eval_select)]
-#![feature(const_typed_swap)]
 #![feature(core_intrinsics)]
 #![feature(coverage_attribute)]
 #![feature(internal_impls_macro)]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 57acc9dcd6e..2d66e5c2f2a 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -725,12 +725,12 @@ pub unsafe fn uninitialized<T>() -> T {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_diagnostic_item = "mem_swap"]
 pub const fn swap<T>(x: &mut T, y: &mut T) {
     // SAFETY: `&mut` guarantees these are typed readable and writable
     // as well as non-overlapping.
-    unsafe { intrinsics::typed_swap(x, y) }
+    unsafe { intrinsics::typed_swap_nonoverlapping(x, y) }
 }
 
 /// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index e6e13eaff7b..ac074c097d9 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1009,9 +1009,8 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+#[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_diagnostic_item = "ptr_swap"]
-#[rustc_const_stable_indirect]
 pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
     // Give ourselves some scratch space to work with.
     // We do not have to worry about drops: `MaybeUninit` does nothing when dropped.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 34567917b52..d75d570a969 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1594,7 +1594,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// [`ptr::swap`]: crate::ptr::swap()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
-    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+    #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")]
     #[inline(always)]
     pub const unsafe fn swap(self, with: *mut T)
     where
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e0ba469272e..1058fa42cc1 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1146,7 +1146,7 @@ impl<T: ?Sized> NonNull<T> {
     /// [`ptr::swap`]: crate::ptr::swap()
     #[inline(always)]
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+    #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")]
     pub const unsafe fn swap(self, with: NonNull<T>)
     where
         T: Sized,
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index ab65f9d6d2f..3e8c698a7ab 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -913,7 +913,7 @@ impl<T> [T] {
     /// assert!(v == ["a", "b", "e", "d", "c"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+    #[rustc_const_stable(feature = "const_swap", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[track_caller]
     pub const fn swap(&mut self, a: usize, b: usize) {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 8716c094928..f18a3f72df3 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -15,7 +15,6 @@
 #![feature(clone_to_uninit)]
 #![feature(const_black_box)]
 #![feature(const_eval_select)]
-#![feature(const_swap)]
 #![feature(const_swap_nonoverlapping)]
 #![feature(const_trait_impl)]
 #![feature(core_intrinsics)]
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
index 89fdd2a01eb..de154d771a0 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
@@ -1,7 +1,7 @@
 #![feature(core_intrinsics)]
 #![feature(rustc_attrs)]
 
-use std::intrinsics::typed_swap;
+use std::intrinsics::typed_swap_nonoverlapping;
 use std::ptr::addr_of_mut;
 
 fn invalid_array() {
@@ -10,7 +10,7 @@ fn invalid_array() {
     unsafe {
         let a = addr_of_mut!(a).cast::<[bool; 100]>();
         let b = addr_of_mut!(b).cast::<[bool; 100]>();
-        typed_swap(a, b); //~ERROR: constructing invalid value
+        typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
     }
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
index 20b20412e75..5884d13a2ad 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
   --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC
    |
-LL |         typed_swap(a, b);
-   |         ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr
index 6062465f36a..9804233c7fa 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
   --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
    |
-LL |         typed_swap(a, b);
-   |         ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr
new file mode 100644
index 00000000000..54b21f155ca
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean
+  --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+note: inside `main`
+  --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |     invalid_scalar();
+   |     ^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
index 9d014a523f8..f5f9c7efbe4 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
@@ -1,16 +1,18 @@
+//@revisions: left right
 #![feature(core_intrinsics)]
 #![feature(rustc_attrs)]
 
-use std::intrinsics::typed_swap;
+use std::intrinsics::typed_swap_nonoverlapping;
 use std::ptr::addr_of_mut;
 
 fn invalid_scalar() {
-    let mut a = 1_u8;
-    let mut b = 2_u8;
+    // We run the test twice, with either the left or the right side being invalid.
+    let mut a = if cfg!(left) { 2_u8 } else { 1_u8 };
+    let mut b = if cfg!(right) { 3_u8 } else { 1_u8 };
     unsafe {
         let a = addr_of_mut!(a).cast::<bool>();
         let b = addr_of_mut!(b).cast::<bool>();
-        typed_swap(a, b); //~ERROR: constructing invalid value
+        typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
     }
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
new file mode 100644
index 00000000000..e643091a02a
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
@@ -0,0 +1,13 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap_nonoverlapping;
+use std::ptr::addr_of_mut;
+
+fn main() {
+    let mut a = 0_u8;
+    unsafe {
+        let a = addr_of_mut!(a);
+        typed_swap_nonoverlapping(a, a); //~ERROR: called on overlapping ranges
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr
new file mode 100644
index 00000000000..6d578841fe5
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
+  --> tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
+   |
+LL |         typed_swap_nonoverlapping(a, a);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/tests/codegen/intrinsics/typed_swap.rs b/tests/codegen/intrinsics/typed_swap.rs
index e73931d1d54..6b55078407a 100644
--- a/tests/codegen/intrinsics/typed_swap.rs
+++ b/tests/codegen/intrinsics/typed_swap.rs
@@ -8,14 +8,14 @@
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
 
-use std::intrinsics::typed_swap;
+use std::intrinsics::typed_swap_nonoverlapping;
 
 // CHECK-LABEL: @swap_unit(
 #[no_mangle]
 pub unsafe fn swap_unit(x: &mut (), y: &mut ()) {
     // CHECK: start
     // CHECK-NEXT: ret void
-    typed_swap(x, y)
+    typed_swap_nonoverlapping(x, y)
 }
 
 // CHECK-LABEL: @swap_i32(
@@ -32,7 +32,7 @@ pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) {
     // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false)
     // CHECK: store i32 %[[TEMP]], ptr %y, align 4
     // CHECK: ret void
-    typed_swap(x, y)
+    typed_swap_nonoverlapping(x, y)
 }
 
 // CHECK-LABEL: @swap_pair(
@@ -47,7 +47,7 @@ pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
     // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false)
     // CHECK: store i32
     // CHECK: store i32
-    typed_swap(x, y)
+    typed_swap_nonoverlapping(x, y)
 }
 
 // CHECK-LABEL: @swap_str(
@@ -63,7 +63,7 @@ pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
     // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false)
     // CHECK: store ptr
     // CHECK: store i64
-    typed_swap(x, y)
+    typed_swap_nonoverlapping(x, y)
 }
 
 // OPT0-LABEL: @swap_string(
@@ -73,5 +73,5 @@ pub unsafe fn swap_string(x: &mut String, y: &mut String) {
     // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false)
     // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false)
     // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false)
-    typed_swap(x, y)
+    typed_swap_nonoverlapping(x, y)
 }
diff --git a/tests/ui/consts/issue-94371.rs b/tests/ui/consts/issue-94371.rs
index ad9ee9a5a3e..b2dd7053c1f 100644
--- a/tests/ui/consts/issue-94371.rs
+++ b/tests/ui/consts/issue-94371.rs
@@ -1,7 +1,5 @@
 //@ check-pass
 
-#![feature(const_swap)]
-
 #[repr(C)]
 struct Demo(u64, bool, u64, u32, u64, u64, u64);
 
diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.rs b/tests/ui/consts/qualif-indirect-mutation-fail.rs
index c6e08a557c8..0f59a86b7cc 100644
--- a/tests/ui/consts/qualif-indirect-mutation-fail.rs
+++ b/tests/ui/consts/qualif-indirect-mutation-fail.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: --crate-type=lib
 #![feature(const_precise_live_drops)]
-#![feature(const_swap)]
 
 // Mutable borrow of a field with drop impl.
 pub const fn f() {
diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr
index f706b7cf699..e76d7d3b670 100644
--- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr
+++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr
@@ -1,5 +1,5 @@
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:13:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:12:9
    |
 LL |     let mut x = None;
    |         ^^^^^ the destructor for this type cannot be evaluated in constants
@@ -19,13 +19,13 @@ note: inside `std::ptr::drop_in_place::<String> - shim(Some(String))`
 note: inside `std::ptr::drop_in_place::<Option<String>> - shim(Some(Option<String>))`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `A1`
-  --> $DIR/qualif-indirect-mutation-fail.rs:19:1
+  --> $DIR/qualif-indirect-mutation-fail.rs:18:1
    |
 LL | };
    | ^
 
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:29:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:28:9
    |
 LL |     let _z = x;
    |         ^^ the destructor for this type cannot be evaluated in constants
@@ -44,13 +44,13 @@ note: inside `std::ptr::drop_in_place::<String> - shim(Some(String))`
 note: inside `std::ptr::drop_in_place::<Option<String>> - shim(Some(Option<String>))`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `A2`
-  --> $DIR/qualif-indirect-mutation-fail.rs:30:1
+  --> $DIR/qualif-indirect-mutation-fail.rs:29:1
    |
 LL | };
    | ^
 
 error[E0493]: destructor of `(u32, Option<String>)` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:7:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:6:9
    |
 LL |     let mut a: (u32, Option<String>) = (0, None);
    |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
@@ -59,7 +59,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:34:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:33:9
    |
 LL |     let x: Option<T> = None;
    |         ^ the destructor for this type cannot be evaluated in constant functions
@@ -68,7 +68,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:42:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:41:9
    |
 LL |     let _y = x;
    |         ^^ the destructor for this type cannot be evaluated in constant functions
@@ -76,7 +76,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:50:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:49:9
    |
 LL |     let mut y: Option<String> = None;
    |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
@@ -85,7 +85,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:47:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:46:9
    |
 LL |     let mut x: Option<String> = None;
    |         ^^^^^ the destructor for this type cannot be evaluated in constant functions
@@ -94,7 +94,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:60:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:59:9
    |
 LL |     let y: Option<String> = None;
    |         ^ the destructor for this type cannot be evaluated in constant functions
@@ -103,7 +103,7 @@ LL | }
    | - value is dropped here
 
 error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
-  --> $DIR/qualif-indirect-mutation-fail.rs:57:9
+  --> $DIR/qualif-indirect-mutation-fail.rs:56:9
    |
 LL |     let x: Option<String> = None;
    |         ^ the destructor for this type cannot be evaluated in constant functions
diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs
index af30f538366..422dac41002 100644
--- a/tests/ui/thread-local/thread-local-static.rs
+++ b/tests/ui/thread-local/thread-local-static.rs
@@ -1,7 +1,6 @@
 //@ edition:2018
 
 #![feature(thread_local)]
-#![feature(const_swap)]
 #![allow(static_mut_refs)]
 
 #[thread_local]
diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr
index 3bc1aec00c1..bb078b79748 100644
--- a/tests/ui/thread-local/thread-local-static.stderr
+++ b/tests/ui/thread-local/thread-local-static.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/thread-local-static.rs:10:28
+  --> $DIR/thread-local-static.rs:9:28
    |
 LL |     std::mem::swap(x, &mut STATIC_VAR_2)
    |                            ^^^^^^^^^^^^ use of mutable static
@@ -7,7 +7,7 @@ LL |     std::mem::swap(x, &mut STATIC_VAR_2)
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0625]: thread-local statics cannot be accessed at compile-time
-  --> $DIR/thread-local-static.rs:10:28
+  --> $DIR/thread-local-static.rs:9:28
    |
 LL |     std::mem::swap(x, &mut STATIC_VAR_2)
    |                            ^^^^^^^^^^^^