@@ -488,9 +488,19 @@ macro_rules! int_impl {
488488 #[ inline( always) ]
489489 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
490490 pub const unsafe fn unchecked_add( self , rhs: Self ) -> Self {
491- // SAFETY: the caller must uphold the safety contract for
492- // `unchecked_add`.
493- unsafe { intrinsics:: unchecked_add( self , rhs) }
491+ assert_unsafe_precondition!(
492+ check_language_ub,
493+ concat!( stringify!( $SelfT) , "::unchecked_add cannot overflow" ) ,
494+ (
495+ lhs: $SelfT = self ,
496+ rhs: $SelfT = rhs,
497+ ) => !lhs. overflowing_add( rhs) . 1 ,
498+ ) ;
499+
500+ // SAFETY: this is guaranteed to be safe by the caller.
501+ unsafe {
502+ intrinsics:: unchecked_add( self , rhs)
503+ }
494504 }
495505
496506 /// Checked addition with an unsigned integer. Computes `self + rhs`,
@@ -630,9 +640,19 @@ macro_rules! int_impl {
630640 #[ inline( always) ]
631641 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
632642 pub const unsafe fn unchecked_sub( self , rhs: Self ) -> Self {
633- // SAFETY: the caller must uphold the safety contract for
634- // `unchecked_sub`.
635- unsafe { intrinsics:: unchecked_sub( self , rhs) }
643+ assert_unsafe_precondition!(
644+ check_language_ub,
645+ concat!( stringify!( $SelfT) , "::unchecked_sub cannot overflow" ) ,
646+ (
647+ lhs: $SelfT = self ,
648+ rhs: $SelfT = rhs,
649+ ) => !lhs. overflowing_sub( rhs) . 1 ,
650+ ) ;
651+
652+ // SAFETY: this is guaranteed to be safe by the caller.
653+ unsafe {
654+ intrinsics:: unchecked_sub( self , rhs)
655+ }
636656 }
637657
638658 /// Checked subtraction with an unsigned integer. Computes `self - rhs`,
@@ -772,9 +792,19 @@ macro_rules! int_impl {
772792 #[ inline( always) ]
773793 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
774794 pub const unsafe fn unchecked_mul( self , rhs: Self ) -> Self {
775- // SAFETY: the caller must uphold the safety contract for
776- // `unchecked_mul`.
777- unsafe { intrinsics:: unchecked_mul( self , rhs) }
795+ assert_unsafe_precondition!(
796+ check_language_ub,
797+ concat!( stringify!( $SelfT) , "::unchecked_mul cannot overflow" ) ,
798+ (
799+ lhs: $SelfT = self ,
800+ rhs: $SelfT = rhs,
801+ ) => !lhs. overflowing_mul( rhs) . 1 ,
802+ ) ;
803+
804+ // SAFETY: this is guaranteed to be safe by the caller.
805+ unsafe {
806+ intrinsics:: unchecked_mul( self , rhs)
807+ }
778808 }
779809
780810 /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
@@ -1111,9 +1141,18 @@ macro_rules! int_impl {
11111141 #[ inline( always) ]
11121142 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
11131143 pub const unsafe fn unchecked_neg( self ) -> Self {
1114- // SAFETY: the caller must uphold the safety contract for
1115- // `unchecked_neg`.
1116- unsafe { intrinsics:: unchecked_sub( 0 , self ) }
1144+ assert_unsafe_precondition!(
1145+ check_language_ub,
1146+ concat!( stringify!( $SelfT) , "::unchecked_neg cannot overflow" ) ,
1147+ (
1148+ lhs: $SelfT = self ,
1149+ ) => !lhs. overflowing_neg( ) . 1 ,
1150+ ) ;
1151+
1152+ // SAFETY: this is guaranteed to be safe by the caller.
1153+ unsafe {
1154+ intrinsics:: unchecked_sub( 0 , self )
1155+ }
11171156 }
11181157
11191158 /// Strict negation. Computes `-self`, panicking if `self == MIN`.
@@ -1235,9 +1274,19 @@ macro_rules! int_impl {
12351274 }
12361275 #[ cfg( not( bootstrap) ) ]
12371276 {
1238- // SAFETY: the caller must uphold the safety contract for
1239- // `unchecked_shl`.
1240- unsafe { intrinsics:: unchecked_shl( self , rhs) }
1277+ assert_unsafe_precondition!(
1278+ check_language_ub,
1279+ concat!( stringify!( $SelfT) , "::unchecked_shl cannot overflow" ) ,
1280+ (
1281+ rhs: u32 = rhs,
1282+ bits: u32 = Self :: BITS ,
1283+ ) => rhs < bits,
1284+ ) ;
1285+
1286+ // SAFETY: this is guaranteed to be safe by the caller.
1287+ unsafe {
1288+ intrinsics:: unchecked_shl( self , rhs)
1289+ }
12411290 }
12421291 }
12431292
@@ -1326,9 +1375,20 @@ macro_rules! int_impl {
13261375 }
13271376 #[ cfg( not( bootstrap) ) ]
13281377 {
1329- // SAFETY: the caller must uphold the safety contract for
1330- // `unchecked_shr`.
1331- unsafe { intrinsics:: unchecked_shr( self , rhs) }
1378+ assert_unsafe_precondition!(
1379+ check_language_ub,
1380+ concat!( stringify!( $SelfT) , "::unchecked_shr cannot overflow" ) ,
1381+ (
1382+ rhs: u32 = rhs,
1383+ bits: u32 = Self :: BITS ,
1384+ ) => rhs < bits,
1385+ ) ;
1386+
1387+ // SAFETY: this is guaranteed to be safe by the caller.
1388+ // Any legal shift amount is losslessly representable in the self type.
1389+ unsafe {
1390+ intrinsics:: unchecked_shr( self , rhs)
1391+ }
13321392 }
13331393 }
13341394
0 commit comments