diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 85a56d37ab75c..f76bc781b4d30 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1501,116 +1501,25 @@ impl *const T { /// For non-`Sized` pointees this operation considers only the data pointer, /// ignoring the metadata. /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two (this includes 0). - /// - /// # Examples - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - /// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - /// - /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); - /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] + /// This is an internal implementation detail of the stdlib, for implementing + /// low-level things like assert_unsafe_precondition. /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` + /// # Safety /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 + /// The return value is unspecified if `align` isn't a power of two. #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { - if !align.is_power_of_two() { - panic!("is_aligned_to: align is not a power-of-two"); - } - + pub(crate) const fn is_aligned_to(self, align: usize) -> bool { #[inline] fn runtime_impl(ptr: *const (), align: usize) -> bool { + // classic bitmath magic trick: + // + // * a power of two is a single bit set like 00001000 + // * multiples of that must have all those low 0's also clear + // * subtracting one from the power gets you 00000111 + // * so if we AND that with a multiple, we should get 0 + // + // Note we get to assume align is a power of two ptr.addr() & (align - 1) == 0 } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 28ba26f5c16c4..2c220ed0553ec 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1764,140 +1764,7 @@ impl *mut T { where T: Sized, { - self.is_aligned_to(mem::align_of::()) - } - - /// Returns whether the pointer is aligned to `align`. - /// - /// For non-`Sized` pointees this operation considers only the data pointer, - /// ignoring the metadata. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two (this includes 0). - /// - /// # Examples - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - /// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - /// - /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); - /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// #![feature(const_mut_refs)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let mut data = AlignedI32(42); - /// let ptr = &mut data as *mut AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// // Also, note that mutable references are not allowed in the final value of constants. - /// const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut(); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *mut u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 - #[must_use] - #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - pub const fn is_aligned_to(self, align: usize) -> bool { - if !align.is_power_of_two() { - panic!("is_aligned_to: align is not a power-of-two"); - } - - #[inline] - fn runtime_impl(ptr: *mut (), align: usize) -> bool { - ptr.addr() & (align - 1) == 0 - } - - #[inline] - const fn const_impl(ptr: *mut (), align: usize) -> bool { - // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead. - // The cast to `()` is used to - // 1. deal with fat pointers; and - // 2. ensure that `align_offset` doesn't actually try to compute an offset. - ptr.align_offset(align) == 0 - } - - // SAFETY: The two versions are equivalent at runtime. - unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) } + (self as *const T).is_aligned() } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index acb8c552a6338..bff0c16bbb4d9 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1405,118 +1405,6 @@ impl NonNull { { self.pointer.is_aligned() } - - /// Returns whether the pointer is aligned to `align`. - /// - /// For non-`Sized` pointees this operation considers only the data pointer, - /// ignoring the metadata. - /// - /// # Panics - /// - /// The function panics if `align` is not a power-of-two (this includes 0). - /// - /// # Examples - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - /// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - /// - /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); - /// ``` - /// - /// # At compiletime - /// **Note: Alignment at compiletime is experimental and subject to change. See the - /// [tracking issue] for details.** - /// - /// At compiletime, the compiler may not know where a value will end up in memory. - /// Calling this function on a pointer created from a reference at compiletime will only - /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer - /// cannot be stricter aligned than the reference's underlying allocation. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// const _: () = { - /// let data = AlignedI32(42); - /// let ptr = &data as *const AlignedI32; - /// - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// - /// // At compiletime, we know for sure that the pointer isn't aligned to 8. - /// assert!(!ptr.is_aligned_to(8)); - /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); - /// }; - /// ``` - /// - /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime - /// pointer is aligned, even if the compiletime pointer wasn't aligned. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// // On some platforms, the alignment of i32 is less than 4. - /// #[repr(align(4))] - /// struct AlignedI32(i32); - /// - /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. - /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); - /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); - /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); - /// - /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. - /// let runtime_ptr = COMPTIME_PTR; - /// assert_ne!( - /// runtime_ptr.is_aligned_to(8), - /// runtime_ptr.wrapping_add(1).is_aligned_to(8), - /// ); - /// ``` - /// - /// If a pointer is created from a fixed address, this function behaves the same during - /// runtime and compiletime. - /// - /// ``` - /// #![feature(pointer_is_aligned)] - /// #![feature(const_pointer_is_aligned)] - /// - /// const _: () = { - /// let ptr = 40 as *const u8; - /// assert!(ptr.is_aligned_to(1)); - /// assert!(ptr.is_aligned_to(2)); - /// assert!(ptr.is_aligned_to(4)); - /// assert!(ptr.is_aligned_to(8)); - /// assert!(!ptr.is_aligned_to(16)); - /// }; - /// ``` - /// - /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 - #[unstable(feature = "pointer_is_aligned", issue = "96284")] - #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] - #[must_use] - #[inline] - pub const fn is_aligned_to(self, align: usize) -> bool { - self.pointer.is_aligned_to(align) - } } impl NonNull<[T]> { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 5c4f0bf9b2b49..f971bf5106c21 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -386,7 +386,7 @@ const fn is_ascii(s: &[u8]) -> bool { // have alignment information it should have given a `usize::MAX` for // `align_offset` earlier, sending things through the scalar path instead of // this one, so this check should pass if it's reachable. - debug_assert!(word_ptr.is_aligned_to(mem::align_of::())); + debug_assert!(word_ptr.is_aligned()); // Read subsequent words until the last aligned word, excluding the last // aligned word by itself to be done in tail check later, to ensure that diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 45193c11e1d6b..b14c512c6be0c 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -420,12 +420,11 @@ impl AtomicBool { /// ``` /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicBool}; - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value /// let ptr: *mut bool = Box::into_raw(Box::new(false)); /// - /// assert!(ptr.is_aligned_to(align_of::())); + /// assert!(ptr.cast::().is_aligned()); /// /// { /// // Create an atomic view of the allocated value @@ -1218,12 +1217,11 @@ impl AtomicPtr { /// ``` /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicPtr}; - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value /// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut())); /// - /// assert!(ptr.is_aligned_to(align_of::>())); + /// assert!(ptr.cast::>().is_aligned()); /// /// { /// // Create an atomic view of the allocated value @@ -2201,12 +2199,11 @@ macro_rules! atomic_int { /// ``` /// #![feature(pointer_is_aligned)] #[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")] - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value #[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")] /// - #[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")] + #[doc = concat!("assert!(ptr.cast::<", stringify!($atomic_type), ">().is_aligned());")] /// /// { /// // Create an atomic view of the allocated value diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 659fbd255c168..77a14eb9f3fed 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -714,15 +714,15 @@ fn is_aligned() { let data = 42; let ptr: *const i32 = &data; assert!(ptr.is_aligned()); - assert!(ptr.is_aligned_to(1)); - assert!(ptr.is_aligned_to(2)); - assert!(ptr.is_aligned_to(4)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); + assert!(ptr.wrapping_add(1).is_aligned()); + assert!(ptr.wrapping_byte_add(4).is_aligned()); + + assert!(!ptr.wrapping_byte_add(1).is_aligned()); + assert!(!ptr.wrapping_byte_add(2).is_aligned()); + assert!(!ptr.wrapping_byte_add(3).is_aligned()); // At runtime either `ptr` or `ptr+1` is aligned to 8. - assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); + assert_ne!(ptr.cast::().is_aligned(), ptr.wrapping_add(1).cast::().is_aligned()); } #[test] @@ -731,16 +731,16 @@ fn is_aligned_const() { let data = 42; let ptr: *const i32 = &data; assert!(ptr.is_aligned()); - assert!(ptr.is_aligned_to(1)); - assert!(ptr.is_aligned_to(2)); - assert!(ptr.is_aligned_to(4)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); + assert!(ptr.wrapping_add(1).is_aligned()); + assert!(ptr.wrapping_byte_add(4).is_aligned()); + + assert!(!ptr.wrapping_byte_add(1).is_aligned()); + assert!(!ptr.wrapping_byte_add(2).is_aligned()); + assert!(!ptr.wrapping_byte_add(3).is_aligned()); // At comptime neither `ptr` nor `ptr+1` is aligned to 8. - assert!(!ptr.is_aligned_to(8)); - assert!(!ptr.wrapping_add(1).is_aligned_to(8)); + assert!(!ptr.cast::().is_aligned()); + assert!(!ptr.wrapping_add(1).cast::().is_aligned()); } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index f99cea360f1f4..93258b33f7998 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -118,7 +118,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) }; + let is_aligned = |p: *const u8| -> bool { p.addr() % Self::align_of() == 0 }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); diff --git a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs index 5cf62995fbee2..a33c880a19a7d 100644 --- a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs +++ b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs @@ -13,7 +13,7 @@ fn main() { let size = 64; assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); assert!(!ptr.is_null()); - assert!(ptr.is_aligned_to(align)); + assert!(ptr.addr() % align == 0); ptr.cast::().write_bytes(1, size); libc::free(ptr); } @@ -25,7 +25,7 @@ fn main() { let size = 8; assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); assert!(!ptr.is_null()); - assert!(ptr.is_aligned_to(align)); + assert!(ptr.addr() % align == 0); ptr.cast::().write_bytes(1, size); libc::free(ptr); } @@ -37,7 +37,7 @@ fn main() { let size = 31; assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); assert!(!ptr.is_null()); - assert!(ptr.is_aligned_to(align)); + assert!(ptr.addr() % align == 0); ptr.cast::().write_bytes(1, size); libc::free(ptr); } @@ -51,7 +51,7 @@ fn main() { // We are not required to return null if size == 0, but we currently do. // It's fine to remove this assert if we start returning non-null pointers. assert!(ptr.is_null()); - assert!(ptr.is_aligned_to(align)); + assert!(ptr.addr() % align == 0); // Regardless of what we return, it must be `free`able. libc::free(ptr); } diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 66f663ce0776c..dff9e2ba566de 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -306,10 +306,10 @@ pub fn main() { let v = Reorder4 {a: 0, b: 0, ary: [0; 4]}; assert_eq!(size_of::(), 12); - assert!((&v.ary).as_ptr().is_aligned_to(4), "[u8; 4] should group with align-4 fields"); + assert_eq!((&v.ary).as_ptr().addr() % 4, 0, "[u8; 4] should group with align-4 fields"); let v = Reorder2 {a: 0, b: 0, ary: [0; 6]}; assert_eq!(size_of::(), 10); - assert!((&v.ary).as_ptr().is_aligned_to(2), "[u8; 6] should group with align-2 fields"); + assert_eq!((&v.ary).as_ptr().addr() % 2, 0, "[u8; 6] should group with align-2 fields"); let v = VecDummy { r: RawVecDummy { ptr: NonNull::dangling(), cap: 0 }, len: 1 }; assert_eq!(ptr::from_ref(&v), ptr::from_ref(&v.r.ptr).cast(), @@ -324,7 +324,7 @@ pub fn main() { assert_eq!(size_of::>(), size_of::()); let v = ReorderWithNiche {a: 0, b: ' ', c: 0, ary: [0; 8]}; - assert!((&v.ary).as_ptr().is_aligned_to(4), + assert_eq!((&v.ary).as_ptr().addr() % 4, 0, "here [u8; 8] should group with _at least_ align-4 fields"); assert_eq!(ptr::from_ref(&v), ptr::from_ref(&v.b).cast(), "sort niches to the front where possible");