@@ -358,6 +358,22 @@ fn align_offset_zst() {
358358 }
359359}
360360
361+ #[ test]
362+ fn align_offset_zst_const ( ) {
363+ const {
364+ // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
365+ // all, because no amount of elements will align the pointer.
366+ let mut p = 1 ;
367+ while p < 1024 {
368+ assert ! ( ptr:: invalid:: <( ) >( p) . align_offset( p) == 0 ) ;
369+ if p != 1 {
370+ assert ! ( ptr:: invalid:: <( ) >( p + 1 ) . align_offset( p) == !0 ) ;
371+ }
372+ p = ( p + 1 ) . next_power_of_two ( ) ;
373+ }
374+ }
375+ }
376+
361377#[ test]
362378fn align_offset_stride_one ( ) {
363379 // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
@@ -379,6 +395,25 @@ fn align_offset_stride_one() {
379395 }
380396}
381397
398+ #[ test]
399+ fn align_offset_stride_one_const ( ) {
400+ const {
401+ // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
402+ // number of bytes.
403+ let mut align = 1 ;
404+ while align < 1024 {
405+ let mut ptr = 1 ;
406+ while ptr < 2 * align {
407+ let expected = ptr % align;
408+ let offset = if expected == 0 { 0 } else { align - expected } ;
409+ assert ! ( ptr:: invalid:: <u8 >( ptr) . align_offset( align) == offset) ;
410+ ptr += 1 ;
411+ }
412+ align = ( align + 1 ) . next_power_of_two ( ) ;
413+ }
414+ }
415+ }
416+
382417#[ test]
383418fn align_offset_various_strides ( ) {
384419 unsafe fn test_stride < T > ( ptr : * const T , align : usize ) -> bool {
@@ -455,6 +490,132 @@ fn align_offset_various_strides() {
455490 assert ! ( !x) ;
456491}
457492
493+ #[ test]
494+ fn align_offset_various_strides_const ( ) {
495+ const unsafe fn test_stride < T > ( ptr : * const T , numptr : usize , align : usize ) {
496+ let mut expected = usize:: MAX ;
497+ // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
498+ let mut el = 0 ;
499+ while el < align {
500+ if ( numptr + el * :: std:: mem:: size_of :: < T > ( ) ) % align == 0 {
501+ expected = el;
502+ break ;
503+ }
504+ el += 1 ;
505+ }
506+ let got = ptr. align_offset ( align) ;
507+ assert ! ( got == expected) ;
508+ }
509+
510+ // For pointers of stride != 1, we verify the algorithm against the naivest possible
511+ // implementation
512+ let mut align = 1 ;
513+ let limit = 1024 ;
514+ while align < limit {
515+ for ptr in 1usize ..4 * align {
516+ unsafe {
517+ #[ repr( packed) ]
518+ struct A3 ( u16 , u8 ) ;
519+ test_stride :: < A3 > ( ptr:: invalid :: < A3 > ( ptr) , ptr, align) ;
520+
521+ struct A4 ( u32 ) ;
522+ test_stride :: < A4 > ( ptr:: invalid :: < A4 > ( ptr) , ptr, align) ;
523+
524+ #[ repr( packed) ]
525+ struct A5 ( u32 , u8 ) ;
526+ test_stride :: < A5 > ( ptr:: invalid :: < A5 > ( ptr) , ptr, align) ;
527+
528+ #[ repr( packed) ]
529+ struct A6 ( u32 , u16 ) ;
530+ test_stride :: < A6 > ( ptr:: invalid :: < A6 > ( ptr) , ptr, align) ;
531+
532+ #[ repr( packed) ]
533+ struct A7 ( u32 , u16 , u8 ) ;
534+ test_stride :: < A7 > ( ptr:: invalid :: < A7 > ( ptr) , ptr, align) ;
535+
536+ #[ repr( packed) ]
537+ struct A8 ( u32 , u32 ) ;
538+ test_stride :: < A8 > ( ptr:: invalid :: < A8 > ( ptr) , ptr, align) ;
539+
540+ #[ repr( packed) ]
541+ struct A9 ( u32 , u32 , u8 ) ;
542+ test_stride :: < A9 > ( ptr:: invalid :: < A9 > ( ptr) , ptr, align) ;
543+
544+ #[ repr( packed) ]
545+ struct A10 ( u32 , u32 , u16 ) ;
546+ test_stride :: < A10 > ( ptr:: invalid :: < A10 > ( ptr) , ptr, align) ;
547+
548+ test_stride :: < u32 > ( ptr:: invalid :: < u32 > ( ptr) , ptr, align) ;
549+ test_stride :: < u128 > ( ptr:: invalid :: < u128 > ( ptr) , ptr, align) ;
550+ }
551+ }
552+ align = ( align + 1 ) . next_power_of_two ( ) ;
553+ }
554+ }
555+
556+ #[ test]
557+ fn align_offset_with_provenance_const ( ) {
558+ const {
559+ let data = 42 ;
560+
561+ let ptr: * const i32 = & data;
562+ assert ! ( ptr. align_offset( 1 ) == 0 ) ;
563+ assert ! ( ptr. align_offset( 2 ) == 0 ) ;
564+ assert ! ( ptr. align_offset( 4 ) == 0 ) ;
565+ assert ! ( ptr. align_offset( 8 ) == usize :: MAX ) ;
566+ assert ! ( ptr. wrapping_byte_add( 1 ) . align_offset( 1 ) == 0 ) ;
567+ assert ! ( ptr. wrapping_byte_add( 1 ) . align_offset( 2 ) == usize :: MAX ) ;
568+ assert ! ( ptr. wrapping_byte_add( 2 ) . align_offset( 1 ) == 0 ) ;
569+ assert ! ( ptr. wrapping_byte_add( 2 ) . align_offset( 2 ) == 0 ) ;
570+ assert ! ( ptr. wrapping_byte_add( 2 ) . align_offset( 4 ) == usize :: MAX ) ;
571+ assert ! ( ptr. wrapping_byte_add( 3 ) . align_offset( 1 ) == 0 ) ;
572+ assert ! ( ptr. wrapping_byte_add( 3 ) . align_offset( 2 ) == usize :: MAX ) ;
573+
574+ assert ! ( ptr. wrapping_add( 42 ) . align_offset( 4 ) == 0 ) ;
575+ assert ! ( ptr. wrapping_add( 42 ) . align_offset( 8 ) == usize :: MAX ) ;
576+
577+ let ptr1: * const i8 = ptr. cast ( ) ;
578+ assert ! ( ptr1. align_offset( 1 ) == 0 ) ;
579+ assert ! ( ptr1. align_offset( 2 ) == 0 ) ;
580+ assert ! ( ptr1. align_offset( 4 ) == 0 ) ;
581+ assert ! ( ptr1. align_offset( 8 ) == usize :: MAX ) ;
582+ assert ! ( ptr1. wrapping_byte_add( 1 ) . align_offset( 1 ) == 0 ) ;
583+ assert ! ( ptr1. wrapping_byte_add( 1 ) . align_offset( 2 ) == 1 ) ;
584+ assert ! ( ptr1. wrapping_byte_add( 1 ) . align_offset( 4 ) == 3 ) ;
585+ assert ! ( ptr1. wrapping_byte_add( 1 ) . align_offset( 8 ) == usize :: MAX ) ;
586+ assert ! ( ptr1. wrapping_byte_add( 2 ) . align_offset( 1 ) == 0 ) ;
587+ assert ! ( ptr1. wrapping_byte_add( 2 ) . align_offset( 2 ) == 0 ) ;
588+ assert ! ( ptr1. wrapping_byte_add( 2 ) . align_offset( 4 ) == 2 ) ;
589+ assert ! ( ptr1. wrapping_byte_add( 2 ) . align_offset( 8 ) == usize :: MAX ) ;
590+ assert ! ( ptr1. wrapping_byte_add( 3 ) . align_offset( 1 ) == 0 ) ;
591+ assert ! ( ptr1. wrapping_byte_add( 3 ) . align_offset( 2 ) == 1 ) ;
592+ assert ! ( ptr1. wrapping_byte_add( 3 ) . align_offset( 4 ) == 1 ) ;
593+ assert ! ( ptr1. wrapping_byte_add( 3 ) . align_offset( 8 ) == usize :: MAX ) ;
594+
595+ let ptr2: * const i16 = ptr. cast ( ) ;
596+ assert ! ( ptr2. align_offset( 1 ) == 0 ) ;
597+ assert ! ( ptr2. align_offset( 2 ) == 0 ) ;
598+ assert ! ( ptr2. align_offset( 4 ) == 0 ) ;
599+ assert ! ( ptr2. align_offset( 8 ) == usize :: MAX ) ;
600+ assert ! ( ptr2. wrapping_byte_add( 1 ) . align_offset( 1 ) == 0 ) ;
601+ assert ! ( ptr2. wrapping_byte_add( 1 ) . align_offset( 2 ) == usize :: MAX ) ;
602+ assert ! ( ptr2. wrapping_byte_add( 2 ) . align_offset( 1 ) == 0 ) ;
603+ assert ! ( ptr2. wrapping_byte_add( 2 ) . align_offset( 2 ) == 0 ) ;
604+ assert ! ( ptr2. wrapping_byte_add( 2 ) . align_offset( 4 ) == 1 ) ;
605+ assert ! ( ptr2. wrapping_byte_add( 2 ) . align_offset( 8 ) == usize :: MAX ) ;
606+ assert ! ( ptr2. wrapping_byte_add( 3 ) . align_offset( 1 ) == 0 ) ;
607+ assert ! ( ptr2. wrapping_byte_add( 3 ) . align_offset( 2 ) == usize :: MAX ) ;
608+
609+ let ptr3: * const i64 = ptr. cast ( ) ;
610+ assert ! ( ptr3. align_offset( 1 ) == 0 ) ;
611+ assert ! ( ptr3. align_offset( 2 ) == 0 ) ;
612+ assert ! ( ptr3. align_offset( 4 ) == 0 ) ;
613+ assert ! ( ptr3. align_offset( 8 ) == usize :: MAX ) ;
614+ assert ! ( ptr3. wrapping_byte_add( 1 ) . align_offset( 1 ) == 0 ) ;
615+ assert ! ( ptr3. wrapping_byte_add( 1 ) . align_offset( 2 ) == usize :: MAX ) ;
616+ }
617+ }
618+
458619#[ test]
459620fn offset_from ( ) {
460621 let mut a = [ 0 ; 5 ] ;
0 commit comments