summaryrefslogtreecommitdiffstats
path: root/library/core/tests/ptr.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /library/core/tests/ptr.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/tests/ptr.rs')
-rw-r--r--library/core/tests/ptr.rs291
1 files changed, 291 insertions, 0 deletions
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 97a369810..90bc83510 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -359,6 +359,23 @@ fn align_offset_zst() {
}
#[test]
+#[cfg(not(bootstrap))]
+fn align_offset_zst_const() {
+ const {
+ // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
+ // all, because no amount of elements will align the pointer.
+ let mut p = 1;
+ while p < 1024 {
+ assert!(ptr::invalid::<()>(p).align_offset(p) == 0);
+ if p != 1 {
+ assert!(ptr::invalid::<()>(p + 1).align_offset(p) == !0);
+ }
+ p = (p + 1).next_power_of_two();
+ }
+ }
+}
+
+#[test]
fn align_offset_stride_one() {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
// number of bytes.
@@ -380,6 +397,26 @@ fn align_offset_stride_one() {
}
#[test]
+#[cfg(not(bootstrap))]
+fn align_offset_stride_one_const() {
+ const {
+ // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
+ // number of bytes.
+ let mut align = 1;
+ while align < 1024 {
+ let mut ptr = 1;
+ while ptr < 2 * align {
+ let expected = ptr % align;
+ let offset = if expected == 0 { 0 } else { align - expected };
+ assert!(ptr::invalid::<u8>(ptr).align_offset(align) == offset);
+ ptr += 1;
+ }
+ align = (align + 1).next_power_of_two();
+ }
+ }
+}
+
+#[test]
fn align_offset_various_strides() {
unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
let numptr = ptr as usize;
@@ -456,6 +493,260 @@ fn align_offset_various_strides() {
}
#[test]
+#[cfg(not(bootstrap))]
+fn align_offset_various_strides_const() {
+ const unsafe fn test_stride<T>(ptr: *const T, numptr: usize, align: usize) {
+ let mut expected = usize::MAX;
+ // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
+ let mut el = 0;
+ while el < align {
+ if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
+ expected = el;
+ break;
+ }
+ el += 1;
+ }
+ let got = ptr.align_offset(align);
+ assert!(got == expected);
+ }
+
+ 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();
+ }
+ }
+}
+
+#[test]
+#[cfg(not(bootstrap))]
+fn align_offset_with_provenance_const() {
+ const {
+ // On some platforms (e.g. msp430-none-elf), the alignment of `i32` is less than 4.
+ #[repr(align(4))]
+ struct AlignedI32(i32);
+
+ 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!(ptr.align_offset(8) == usize::MAX);
+ assert!(ptr.wrapping_byte_add(1).align_offset(1) == 0);
+ assert!(ptr.wrapping_byte_add(1).align_offset(2) == usize::MAX);
+ assert!(ptr.wrapping_byte_add(2).align_offset(1) == 0);
+ assert!(ptr.wrapping_byte_add(2).align_offset(2) == 0);
+ assert!(ptr.wrapping_byte_add(2).align_offset(4) == usize::MAX);
+ assert!(ptr.wrapping_byte_add(3).align_offset(1) == 0);
+ assert!(ptr.wrapping_byte_add(3).align_offset(2) == usize::MAX);
+
+ assert!(ptr.wrapping_add(42).align_offset(4) == 0);
+ assert!(ptr.wrapping_add(42).align_offset(8) == usize::MAX);
+
+ let ptr1: *const i8 = ptr.cast();
+ assert!(ptr1.align_offset(1) == 0);
+ assert!(ptr1.align_offset(2) == 0);
+ assert!(ptr1.align_offset(4) == 0);
+ assert!(ptr1.align_offset(8) == usize::MAX);
+ assert!(ptr1.wrapping_byte_add(1).align_offset(1) == 0);
+ assert!(ptr1.wrapping_byte_add(1).align_offset(2) == 1);
+ assert!(ptr1.wrapping_byte_add(1).align_offset(4) == 3);
+ assert!(ptr1.wrapping_byte_add(1).align_offset(8) == usize::MAX);
+ assert!(ptr1.wrapping_byte_add(2).align_offset(1) == 0);
+ assert!(ptr1.wrapping_byte_add(2).align_offset(2) == 0);
+ assert!(ptr1.wrapping_byte_add(2).align_offset(4) == 2);
+ assert!(ptr1.wrapping_byte_add(2).align_offset(8) == usize::MAX);
+ assert!(ptr1.wrapping_byte_add(3).align_offset(1) == 0);
+ assert!(ptr1.wrapping_byte_add(3).align_offset(2) == 1);
+ assert!(ptr1.wrapping_byte_add(3).align_offset(4) == 1);
+ assert!(ptr1.wrapping_byte_add(3).align_offset(8) == usize::MAX);
+
+ let ptr2: *const i16 = ptr.cast();
+ assert!(ptr2.align_offset(1) == 0);
+ assert!(ptr2.align_offset(2) == 0);
+ assert!(ptr2.align_offset(4) == 0);
+ assert!(ptr2.align_offset(8) == usize::MAX);
+ assert!(ptr2.wrapping_byte_add(1).align_offset(1) == 0);
+ assert!(ptr2.wrapping_byte_add(1).align_offset(2) == usize::MAX);
+ assert!(ptr2.wrapping_byte_add(2).align_offset(1) == 0);
+ assert!(ptr2.wrapping_byte_add(2).align_offset(2) == 0);
+ assert!(ptr2.wrapping_byte_add(2).align_offset(4) == 1);
+ assert!(ptr2.wrapping_byte_add(2).align_offset(8) == usize::MAX);
+ assert!(ptr2.wrapping_byte_add(3).align_offset(1) == 0);
+ assert!(ptr2.wrapping_byte_add(3).align_offset(2) == usize::MAX);
+
+ let ptr3: *const i64 = ptr.cast();
+ assert!(ptr3.align_offset(1) == 0);
+ assert!(ptr3.align_offset(2) == 0);
+ assert!(ptr3.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);
+ }
+}
+
+#[test]
+fn align_offset_issue_103361() {
+ #[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]);
+ 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]
fn offset_from() {
let mut a = [0; 5];
let ptr1: *mut i32 = &mut a[1];