@@ -395,6 +395,36 @@ impl<T: ?Sized> *const T {
395
395
where
396
396
T : Sized ,
397
397
{
398
+ #[ inline]
399
+ const fn runtime_offset_nowrap ( this : * const ( ) , count : isize , size : usize ) -> bool {
400
+ #[ inline]
401
+ fn runtime ( this : * const ( ) , count : isize , size : usize ) -> bool {
402
+ // We know `size <= isize::MAX` so the `as` cast here is not lossy.
403
+ let Some ( byte_offset) = count. checked_mul ( size as isize ) else {
404
+ return false ;
405
+ } ;
406
+ let ( _, overflow) = this. addr ( ) . overflowing_add_signed ( byte_offset) ;
407
+ !overflow
408
+ }
409
+
410
+ const fn comptime ( _: * const ( ) , _: isize , _: usize ) -> bool {
411
+ true
412
+ }
413
+
414
+ // We can use const_eval_select here because this is only for UB checks.
415
+ intrinsics:: const_eval_select ( ( this, count, size) , comptime, runtime)
416
+ }
417
+
418
+ ub_checks:: assert_unsafe_precondition!(
419
+ check_language_ub,
420
+ "ptr::offset requires the address calculation to not overflow" ,
421
+ (
422
+ this: * const ( ) = self as * const ( ) ,
423
+ count: isize = count,
424
+ size: usize = size_of:: <T >( ) ,
425
+ ) => runtime_offset_nowrap( this, count, size)
426
+ ) ;
427
+
398
428
// SAFETY: the caller must uphold the safety contract for `offset`.
399
429
unsafe { intrinsics:: offset ( self , count) }
400
430
}
@@ -726,7 +756,6 @@ impl<T: ?Sized> *const T {
726
756
true
727
757
}
728
758
729
- #[ allow( unused_unsafe) ]
730
759
intrinsics:: const_eval_select ( ( this, origin) , comptime, runtime)
731
760
}
732
761
@@ -858,6 +887,34 @@ impl<T: ?Sized> *const T {
858
887
where
859
888
T : Sized ,
860
889
{
890
+ #[ inline]
891
+ const fn runtime_add_nowrap ( this : * const ( ) , count : usize , size : usize ) -> bool {
892
+ #[ inline]
893
+ fn runtime ( this : * const ( ) , count : usize , size : usize ) -> bool {
894
+ let Some ( byte_offset) = count. checked_mul ( size) else {
895
+ return false ;
896
+ } ;
897
+ let ( _, overflow) = this. addr ( ) . overflowing_add ( byte_offset) ;
898
+ byte_offset <= ( isize:: MAX as usize ) && !overflow
899
+ }
900
+
901
+ const fn comptime ( _: * const ( ) , _: usize , _: usize ) -> bool {
902
+ true
903
+ }
904
+
905
+ intrinsics:: const_eval_select ( ( this, count, size) , comptime, runtime)
906
+ }
907
+
908
+ ub_checks:: assert_unsafe_precondition!(
909
+ check_language_ub,
910
+ "ptr::add requires that the address calculation does not overflow" ,
911
+ (
912
+ this: * const ( ) = self as * const ( ) ,
913
+ count: usize = count,
914
+ size: usize = size_of:: <T >( ) ,
915
+ ) => runtime_add_nowrap( this, count, size)
916
+ ) ;
917
+
861
918
// SAFETY: the caller must uphold the safety contract for `offset`.
862
919
unsafe { intrinsics:: offset ( self , count) }
863
920
}
@@ -936,14 +993,41 @@ impl<T: ?Sized> *const T {
936
993
where
937
994
T : Sized ,
938
995
{
996
+ #[ inline]
997
+ const fn runtime_sub_nowrap ( this : * const ( ) , count : usize , size : usize ) -> bool {
998
+ #[ inline]
999
+ fn runtime ( this : * const ( ) , count : usize , size : usize ) -> bool {
1000
+ let Some ( byte_offset) = count. checked_mul ( size) else {
1001
+ return false ;
1002
+ } ;
1003
+ byte_offset <= ( isize:: MAX as usize ) && this. addr ( ) >= byte_offset
1004
+ }
1005
+
1006
+ const fn comptime ( _: * const ( ) , _: usize , _: usize ) -> bool {
1007
+ true
1008
+ }
1009
+
1010
+ intrinsics:: const_eval_select ( ( this, count, size) , comptime, runtime)
1011
+ }
1012
+
1013
+ ub_checks:: assert_unsafe_precondition!(
1014
+ check_language_ub,
1015
+ "ptr::sub requires that the address calculation does not overflow" ,
1016
+ (
1017
+ this: * const ( ) = self as * const ( ) ,
1018
+ count: usize = count,
1019
+ size: usize = size_of:: <T >( ) ,
1020
+ ) => runtime_sub_nowrap( this, count, size)
1021
+ ) ;
1022
+
939
1023
if T :: IS_ZST {
940
1024
// Pointer arithmetic does nothing when the pointee is a ZST.
941
1025
self
942
1026
} else {
943
1027
// SAFETY: the caller must uphold the safety contract for `offset`.
944
1028
// Because the pointee is *not* a ZST, that means that `count` is
945
1029
// at most `isize::MAX`, and thus the negation cannot overflow.
946
- unsafe { self . offset ( ( count as isize ) . unchecked_neg ( ) ) }
1030
+ unsafe { intrinsics :: offset ( self , intrinsics :: unchecked_sub ( 0 , count as isize ) ) }
947
1031
}
948
1032
}
949
1033
0 commit comments