Auto merge of #137412 - scottmcm:redo-swap, r=cuviper

Ensure `swap_nonoverlapping` is really always untyped

This replaces #134954, which was arguably overcomplicated.

## Fixes #134713

Actually using the type passed to `ptr::swap_nonoverlapping` for anything other than its size + align turns out to not work, so this goes back to always erasing the types down to just bytes.

(Except in `const`, which keeps doing the same thing as before to preserve `@RalfJung's` fix from #134689)

## Fixes #134946

I'd previously moved the swapping to use auto-vectorization *on bytes*, but someone pointed out on Discord that the tail loop handling from that left a whole bunch of byte-by-byte swapping around.  This goes back to manual tail handling to avoid that, then still triggers auto-vectorization on pointer-width values.  (So you'll see `<4 x i64>` on `x86-64-v3` for example.)
This commit is contained in:
bors 2025-04-10 20:19:11 +00:00
commit 0fe8f3454d
8 changed files with 302 additions and 95 deletions

View file

@ -0,0 +1,30 @@
use std::mem::{size_of, align_of};
// See <https://github.com/rust-lang/rust/issues/134713>
#[repr(C)]
struct Foo(usize, u8);
fn main() {
let buf1: [usize; 2] = [1000, 2000];
let buf2: [usize; 2] = [3000, 4000];
// Foo and [usize; 2] have the same size and alignment,
// so swap_nonoverlapping should treat them the same
assert_eq!(size_of::<Foo>(), size_of::<[usize; 2]>());
assert_eq!(align_of::<Foo>(), align_of::<[usize; 2]>());
let mut b1 = buf1;
let mut b2 = buf2;
// Safety: b1 and b2 are distinct local variables,
// with the same size and alignment as Foo.
unsafe {
std::ptr::swap_nonoverlapping(
b1.as_mut_ptr().cast::<Foo>(),
b2.as_mut_ptr().cast::<Foo>(),
1,
);
}
assert_eq!(b1, buf2);
assert_eq!(b2, buf1);
}