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