Skip to content

Commit 73e6c9e

Browse files
committed
Auto merge of #147784 - nxsaken:div_exact_return_option, r=dtolnay
Return `Option` from `exact_div` and inherit overflow checks According to #139911 (comment), `exact_div` should return `Option::None` if `self % rhs != 0`, panic if `rhs == 0`, and handle overflow conditionally (panic in debug, wrap in release). #147771 should rename `exact_div` to `div_exact`.
2 parents bd3ac03 + e834a2e commit 73e6c9e

File tree

4 files changed

+37
-31
lines changed

4 files changed

+37
-31
lines changed

library/core/src/num/int_macros.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,25 +1019,29 @@ macro_rules! int_impl {
10191019
}
10201020
}
10211021

1022-
/// Checked integer division without remainder. Computes `self / rhs`.
1022+
/// Integer division without remainder. Computes `self / rhs`, returning `None` if `self % rhs != 0`.
10231023
///
10241024
/// # Panics
10251025
///
1026-
/// This function will panic if `rhs == 0`, the division results in overflow,
1027-
/// or `self % rhs != 0`.
1026+
/// This function will panic if `rhs == 0`.
1027+
///
1028+
/// ## Overflow behavior
1029+
///
1030+
/// On overflow, this function will panic if overflow checks are enabled (default in debug
1031+
/// mode) and wrap if overflow checks are disabled (default in release mode).
10281032
///
10291033
/// # Examples
10301034
///
10311035
/// ```
10321036
/// #![feature(exact_div)]
1033-
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")]
1034-
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")]
1035-
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).exact_div(-1), ", stringify!($Max), ");")]
1037+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), Some(32));")]
1038+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), Some(2));")]
1039+
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).exact_div(-1), Some(", stringify!($Max), "));")]
1040+
#[doc = concat!("assert_eq!(65", stringify!($SelfT), ".exact_div(2), None);")]
10361041
/// ```
1037-
///
10381042
/// ```should_panic
10391043
/// #![feature(exact_div)]
1040-
#[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")]
1044+
#[doc = concat!("let _ = 64", stringify!($SelfT),".exact_div(0);")]
10411045
/// ```
10421046
/// ```should_panic
10431047
/// #![feature(exact_div)]
@@ -1050,10 +1054,12 @@ macro_rules! int_impl {
10501054
#[must_use = "this returns the result of the operation, \
10511055
without modifying the original"]
10521056
#[inline]
1053-
pub const fn exact_div(self, rhs: Self) -> Self {
1054-
match self.checked_exact_div(rhs) {
1055-
Some(x) => x,
1056-
None => panic!("Failed to divide without remainder"),
1057+
#[rustc_inherit_overflow_checks]
1058+
pub const fn exact_div(self, rhs: Self) -> Option<Self> {
1059+
if self % rhs != 0 {
1060+
None
1061+
} else {
1062+
Some(self / rhs)
10571063
}
10581064
}
10591065

library/core/src/num/uint_macros.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,23 +1249,19 @@ macro_rules! uint_impl {
12491249
}
12501250
}
12511251

1252-
/// Checked integer division without remainder. Computes `self / rhs`.
1252+
/// Integer division without remainder. Computes `self / rhs`, returning `None` if `self % rhs != 0`.
12531253
///
12541254
/// # Panics
12551255
///
1256-
/// This function will panic if `rhs == 0` or `self % rhs != 0`.
1256+
/// This function will panic if `rhs == 0`.
12571257
///
12581258
/// # Examples
12591259
///
12601260
/// ```
12611261
/// #![feature(exact_div)]
1262-
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")]
1263-
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")]
1264-
/// ```
1265-
///
1266-
/// ```should_panic
1267-
/// #![feature(exact_div)]
1268-
#[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")]
1262+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), Some(32));")]
1263+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), Some(2));")]
1264+
#[doc = concat!("assert_eq!(65", stringify!($SelfT), ".exact_div(2), None);")]
12691265
/// ```
12701266
#[unstable(
12711267
feature = "exact_div",
@@ -1274,10 +1270,12 @@ macro_rules! uint_impl {
12741270
#[must_use = "this returns the result of the operation, \
12751271
without modifying the original"]
12761272
#[inline]
1277-
pub const fn exact_div(self, rhs: Self) -> Self {
1278-
match self.checked_exact_div(rhs) {
1279-
Some(x) => x,
1280-
None => panic!("Failed to divide without remainder"),
1273+
#[rustc_inherit_overflow_checks]
1274+
pub const fn exact_div(self, rhs: Self) -> Option<Self> {
1275+
if self % rhs != 0 {
1276+
None
1277+
} else {
1278+
Some(self / rhs)
12811279
}
12821280
}
12831281

library/coretests/tests/num/int_macros.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -741,22 +741,23 @@ macro_rules! int_module {
741741
fn test_exact_div() {
742742
// 42 / 6
743743
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1));
744-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1);
744+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1));
745745

746746
// 18 / 3
747747
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2));
748-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2);
748+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2));
749749

750750
// -91 / 13
751751
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3));
752-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), EXACT_DIV_SUCCESS_QUOTIENT3);
752+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3));
753753

754754
// -57 / -3
755755
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4));
756-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), EXACT_DIV_SUCCESS_QUOTIENT4);
756+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4));
757757

758758
// failures
759759
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None);
760+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(1, 2), None);
760761
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None);
761762
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None);
762763
}

library/coretests/tests/num/uint_macros.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,14 +606,15 @@ macro_rules! uint_module {
606606
fn test_exact_div() {
607607
// 42 / 6
608608
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1));
609-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1);
609+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1));
610610

611611
// 18 / 3
612612
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2));
613-
assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2);
613+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2));
614614

615615
// failures
616616
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None);
617+
assert_eq_const_safe!(Option<$T>: <$T>::exact_div(1, 2), None);
617618
assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None);
618619
}
619620
}

0 commit comments

Comments
 (0)