assert!(got == expected);
}
- // For pointers of stride != 1, we verify the algorithm against the naivest possible
- // implementation
- let mut align = 1;
- let limit = 1024;
- while align < limit {
- for ptr in 1usize..4 * align {
- unsafe {
- #[repr(packed)]
- struct A3(u16, u8);
- test_stride::<A3>(ptr::invalid::<A3>(ptr), ptr, align);
-
- struct A4(u32);
- test_stride::<A4>(ptr::invalid::<A4>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A5(u32, u8);
- test_stride::<A5>(ptr::invalid::<A5>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A6(u32, u16);
- test_stride::<A6>(ptr::invalid::<A6>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A7(u32, u16, u8);
- test_stride::<A7>(ptr::invalid::<A7>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A8(u32, u32);
- test_stride::<A8>(ptr::invalid::<A8>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A9(u32, u32, u8);
- test_stride::<A9>(ptr::invalid::<A9>(ptr), ptr, align);
-
- #[repr(packed)]
- struct A10(u32, u32, u16);
- test_stride::<A10>(ptr::invalid::<A10>(ptr), ptr, align);
-
- test_stride::<u32>(ptr::invalid::<u32>(ptr), ptr, align);
- test_stride::<u128>(ptr::invalid::<u128>(ptr), ptr, align);
+ const {
+ // For pointers of stride != 1, we verify the algorithm against the naivest possible
+ // implementation
+ let mut align = 1;
+ let limit = 32;
+ while align < limit {
+ let mut ptr = 1;
+ while ptr < 4 * align {
+ unsafe {
+ #[repr(packed)]
+ struct A3(u16, u8);
+ test_stride::<A3>(ptr::invalid::<A3>(ptr), ptr, align);
+
+ struct A4(u32);
+ test_stride::<A4>(ptr::invalid::<A4>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A5(u32, u8);
+ test_stride::<A5>(ptr::invalid::<A5>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A6(u32, u16);
+ test_stride::<A6>(ptr::invalid::<A6>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A7(u32, u16, u8);
+ test_stride::<A7>(ptr::invalid::<A7>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A8(u32, u32);
+ test_stride::<A8>(ptr::invalid::<A8>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A9(u32, u32, u8);
+ test_stride::<A9>(ptr::invalid::<A9>(ptr), ptr, align);
+
+ #[repr(packed)]
+ struct A10(u32, u32, u16);
+ test_stride::<A10>(ptr::invalid::<A10>(ptr), ptr, align);
+
+ test_stride::<u32>(ptr::invalid::<u32>(ptr), ptr, align);
+ test_stride::<u128>(ptr::invalid::<u128>(ptr), ptr, align);
+ }
+ ptr += 1;
}
+ align = (align + 1).next_power_of_two();
}
- align = (align + 1).next_power_of_two();
}
}
#[cfg(not(bootstrap))]
fn align_offset_with_provenance_const() {
const {
- let data = 42;
+ // On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4.
+ #[repr(align(4))]
+ struct AlignedI32(i32);
- let ptr: *const i32 = &data;
+ let data = AlignedI32(42);
+
+ // `stride % align == 0` (usual case)
+
+ let ptr: *const i32 = &data.0;
assert!(ptr.align_offset(1) == 0);
assert!(ptr.align_offset(2) == 0);
assert!(ptr.align_offset(4) == 0);
assert!(ptr3.align_offset(8) == usize::MAX);
assert!(ptr3.wrapping_byte_add(1).align_offset(1) == 0);
assert!(ptr3.wrapping_byte_add(1).align_offset(2) == usize::MAX);
+
+ // `stride % align != 0` (edge case)
+
+ let ptr4: *const [u8; 3] = ptr.cast();
+ assert!(ptr4.align_offset(1) == 0);
+ assert!(ptr4.align_offset(2) == 0);
+ assert!(ptr4.align_offset(4) == 0);
+ assert!(ptr4.align_offset(8) == usize::MAX);
+ assert!(ptr4.wrapping_byte_add(1).align_offset(1) == 0);
+ assert!(ptr4.wrapping_byte_add(1).align_offset(2) == 1);
+ assert!(ptr4.wrapping_byte_add(1).align_offset(4) == 1);
+ assert!(ptr4.wrapping_byte_add(1).align_offset(8) == usize::MAX);
+ assert!(ptr4.wrapping_byte_add(2).align_offset(1) == 0);
+ assert!(ptr4.wrapping_byte_add(2).align_offset(2) == 0);
+ assert!(ptr4.wrapping_byte_add(2).align_offset(4) == 2);
+ assert!(ptr4.wrapping_byte_add(2).align_offset(8) == usize::MAX);
+ assert!(ptr4.wrapping_byte_add(3).align_offset(1) == 0);
+ assert!(ptr4.wrapping_byte_add(3).align_offset(2) == 1);
+ assert!(ptr4.wrapping_byte_add(3).align_offset(4) == 3);
+ assert!(ptr4.wrapping_byte_add(3).align_offset(8) == usize::MAX);
+
+ let ptr5: *const [u8; 5] = ptr.cast();
+ assert!(ptr5.align_offset(1) == 0);
+ assert!(ptr5.align_offset(2) == 0);
+ assert!(ptr5.align_offset(4) == 0);
+ assert!(ptr5.align_offset(8) == usize::MAX);
+ assert!(ptr5.wrapping_byte_add(1).align_offset(1) == 0);
+ assert!(ptr5.wrapping_byte_add(1).align_offset(2) == 1);
+ assert!(ptr5.wrapping_byte_add(1).align_offset(4) == 3);
+ assert!(ptr5.wrapping_byte_add(1).align_offset(8) == usize::MAX);
+ assert!(ptr5.wrapping_byte_add(2).align_offset(1) == 0);
+ assert!(ptr5.wrapping_byte_add(2).align_offset(2) == 0);
+ assert!(ptr5.wrapping_byte_add(2).align_offset(4) == 2);
+ assert!(ptr5.wrapping_byte_add(2).align_offset(8) == usize::MAX);
+ assert!(ptr5.wrapping_byte_add(3).align_offset(1) == 0);
+ assert!(ptr5.wrapping_byte_add(3).align_offset(2) == 1);
+ assert!(ptr5.wrapping_byte_add(3).align_offset(4) == 1);
+ assert!(ptr5.wrapping_byte_add(3).align_offset(8) == usize::MAX);
}
}
#[cfg(target_pointer_width = "16")]
const SIZE: usize = 1 << 13;
struct HugeSize([u8; SIZE - 1]);
- let _ = (SIZE as *const HugeSize).align_offset(SIZE);
+ let _ = ptr::invalid::<HugeSize>(SIZE).align_offset(SIZE);
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn align_offset_issue_103361_const() {
+ #[cfg(target_pointer_width = "64")]
+ const SIZE: usize = 1 << 47;
+ #[cfg(target_pointer_width = "32")]
+ const SIZE: usize = 1 << 30;
+ #[cfg(target_pointer_width = "16")]
+ const SIZE: usize = 1 << 13;
+ struct HugeSize([u8; SIZE - 1]);
+
+ const {
+ assert!(ptr::invalid::<HugeSize>(SIZE - 1).align_offset(SIZE) == SIZE - 1);
+ assert!(ptr::invalid::<HugeSize>(SIZE).align_offset(SIZE) == 0);
+ assert!(ptr::invalid::<HugeSize>(SIZE + 1).align_offset(SIZE) == 1);
+ }
+}
+
+#[test]
+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));
+
+ // 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));
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn is_aligned_const() {
+ 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));
+
+ // 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));
+ }
+}
+
+#[test]
+#[cfg(bootstrap)]
+fn is_aligned_const() {
+ const {
+ let data = 42;
+ let ptr: *const i32 = &data;
+ // The bootstrap compiler always returns false for is_aligned.
+ assert!(!ptr.is_aligned());
+ assert!(!ptr.is_aligned_to(1));
+ }
}
#[test]