From 4a96800aef385a70d7ee083058413c293c2f34c2 Mon Sep 17 00:00:00 2001
From: marmeladema <xademax@gmail.com>
Date: Thu, 21 May 2020 20:22:47 +0100
Subject: [PATCH] Constify most non-trait `Duration` methods as described in
 #72440

---
 src/libcore/lib.rs                      |  1 +
 src/libcore/time.rs                     | 47 +++++++++++---------
 src/test/ui/consts/duration-consts-2.rs | 57 +++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 19 deletions(-)
 create mode 100644 src/test/ui/consts/duration-consts-2.rs

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index c7496c209bcb0..88991dea7d43e 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -96,6 +96,7 @@
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
+#![feature(duration_consts_2)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intrinsics)]
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index 3b6dafeee2540..acaedbd135e7c 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -130,10 +130,12 @@ impl Duration {
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
-    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
-    pub fn new(secs: u64, nanos: u32) -> Duration {
-        let secs =
-            secs.checked_add((nanos / NANOS_PER_SEC) as u64).expect("overflow in Duration::new");
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn new(secs: u64, nanos: u32) -> Duration {
+        let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
+            Some(secs) => secs,
+            None => panic!("overflow in Duration::new"),
+        };
         let nanos = nanos % NANOS_PER_SEC;
         Duration { secs, nanos }
     }
@@ -433,7 +435,8 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
             let mut nanos = self.nanos + rhs.nanos;
             if nanos >= NANOS_PER_SEC {
@@ -468,7 +471,8 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
             let nanos = if self.nanos >= rhs.nanos {
                 self.nanos - rhs.nanos
@@ -504,19 +508,19 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
         // Multiply nanoseconds as u64, because it cannot overflow that way.
         let total_nanos = self.nanos as u64 * rhs as u64;
         let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
         let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
-        if let Some(secs) =
-            self.secs.checked_mul(rhs as u64).and_then(|s| s.checked_add(extra_secs))
-        {
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs, nanos })
-        } else {
-            None
+        if let Some(s) = self.secs.checked_mul(rhs as u64) {
+            if let Some(secs) = s.checked_add(extra_secs) {
+                debug_assert!(nanos < NANOS_PER_SEC);
+                return Some(Duration { secs, nanos });
+            }
         }
+        None
     }
 
     /// Checked `Duration` division. Computes `self / other`, returning [`None`]
@@ -537,7 +541,8 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_div(self, rhs: u32) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
         if rhs != 0 {
             let secs = self.secs / (rhs as u64);
             let carry = self.secs - secs * (rhs as u64);
@@ -563,7 +568,8 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn as_secs_f64(&self) -> f64 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn as_secs_f64(&self) -> f64 {
         (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
     }
 
@@ -580,7 +586,8 @@ impl Duration {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn as_secs_f32(&self) -> f32 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn as_secs_f32(&self) -> f32 {
         (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
     }
 
@@ -747,7 +754,8 @@ impl Duration {
     /// ```
     #[unstable(feature = "div_duration", issue = "63139")]
     #[inline]
-    pub fn div_duration_f64(self, rhs: Duration) -> f64 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_duration_f64(self, rhs: Duration) -> f64 {
         self.as_secs_f64() / rhs.as_secs_f64()
     }
 
@@ -764,7 +772,8 @@ impl Duration {
     /// ```
     #[unstable(feature = "div_duration", issue = "63139")]
     #[inline]
-    pub fn div_duration_f32(self, rhs: Duration) -> f32 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_duration_f32(self, rhs: Duration) -> f32 {
         self.as_secs_f32() / rhs.as_secs_f32()
     }
 }
diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs
new file mode 100644
index 0000000000000..c8b3939933126
--- /dev/null
+++ b/src/test/ui/consts/duration-consts-2.rs
@@ -0,0 +1,57 @@
+// run-pass
+
+#![feature(const_panic)]
+#![feature(duration_consts_2)]
+#![feature(div_duration)]
+
+use std::time::Duration;
+
+fn duration() {
+    const ZERO : Duration = Duration::new(0, 0);
+    assert_eq!(ZERO, Duration::from_secs(0));
+
+    const ONE : Duration = Duration::new(0, 1);
+    assert_eq!(ONE, Duration::from_nanos(1));
+
+    const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
+
+    const MAX_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
+    assert_eq!(MAX_ADD_ZERO, Some(MAX));
+
+    const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
+    assert_eq!(MAX_ADD_ONE, None);
+
+    const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
+    assert_eq!(ONE_SUB_ONE, Some(ZERO));
+
+    const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
+    assert_eq!(ZERO_SUB_ONE, None);
+
+    const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
+    assert_eq!(ONE_MUL_ONE, Some(ONE));
+
+    const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
+    assert_eq!(MAX_MUL_TWO, None);
+
+    const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1);
+    assert_eq!(ONE_DIV_ONE, Some(ONE));
+
+    const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
+    assert_eq!(ONE_DIV_ZERO, None);
+
+    const MAX_AS_F32 : f32 = MAX.as_secs_f32();
+    assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
+
+    const MAX_AS_F64 : f64 = MAX.as_secs_f64();
+    assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64);
+
+    const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE);
+    assert_eq!(ONE_AS_F32, 1.0_f32);
+
+    const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
+    assert_eq!(ONE_AS_F64, 1.0_f64);
+}
+
+fn main() {
+    duration();
+}