about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/alloc/src/rc.rs113
-rw-r--r--library/core/src/array/iter.rs4
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/mem/maybe_uninit.rs49
-rw-r--r--library/core/src/ops/bit.rs134
-rw-r--r--library/core/src/time.rs97
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/time.rs30
-rw-r--r--library/std/src/os/linux/fs.rs2
-rw-r--r--library/std/src/os/linux/mod.rs2
-rw-r--r--library/std/src/os/linux/raw.rs2
-rw-r--r--library/std/src/sys/unix/ext/ffi.rs2
-rw-r--r--library/std/src/sys/unix/ext/io.rs2
-rw-r--r--library/std/src/sys/unix/ext/net.rs4
-rw-r--r--library/std/src/sys/unix/ext/raw.rs2
-rw-r--r--library/std/src/sys/windows/ext/io.rs2
-rw-r--r--library/std/src/sys/windows/ext/raw.rs2
-rw-r--r--src/librustdoc/clean/mod.rs20
-rw-r--r--src/test/rustdoc/const-generics/type-alias.rs6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr (renamed from src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr)2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr10
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs9
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr10
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.rs8
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr (renamed from src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr)2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr10
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs8
-rw-r--r--src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs5
-rw-r--r--src/test/ui/consts/duration-consts-2.rs42
29 files changed, 488 insertions, 94 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index a9b293856e5..f998e49dcfc 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -295,6 +295,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
 
 impl<T: ?Sized> Rc<T> {
+    #[inline(always)]
+    fn inner(&self) -> &RcBox<T> {
+        // This unsafety is ok because while this Rc is alive we're guaranteed
+        // that the inner pointer is valid.
+        unsafe { self.ptr.as_ref() }
+    }
+
     fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
         Self { ptr, phantom: PhantomData }
     }
@@ -469,7 +476,7 @@ impl<T> Rc<T> {
                 // the strong count, and then remove the implicit "strong weak"
                 // pointer while also handling drop logic by just crafting a
                 // fake Weak.
-                this.dec_strong();
+                this.inner().dec_strong();
                 let _weak = Weak { ptr: this.ptr };
                 forget(this);
                 Ok(val)
@@ -735,7 +742,7 @@ impl<T: ?Sized> Rc<T> {
     /// ```
     #[stable(feature = "rc_weak", since = "1.4.0")]
     pub fn downgrade(this: &Self) -> Weak<T> {
-        this.inc_weak();
+        this.inner().inc_weak();
         // Make sure we do not create a dangling Weak
         debug_assert!(!is_dangling(this.ptr));
         Weak { ptr: this.ptr }
@@ -756,7 +763,7 @@ impl<T: ?Sized> Rc<T> {
     #[inline]
     #[stable(feature = "rc_counts", since = "1.15.0")]
     pub fn weak_count(this: &Self) -> usize {
-        this.weak() - 1
+        this.inner().weak() - 1
     }
 
     /// Gets the number of strong (`Rc`) pointers to this allocation.
@@ -774,7 +781,7 @@ impl<T: ?Sized> Rc<T> {
     #[inline]
     #[stable(feature = "rc_counts", since = "1.15.0")]
     pub fn strong_count(this: &Self) -> usize {
-        this.strong()
+        this.inner().strong()
     }
 
     /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to
@@ -844,7 +851,9 @@ impl<T: ?Sized> Rc<T> {
     #[inline]
     #[unstable(feature = "get_mut_unchecked", issue = "63292")]
     pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
-        unsafe { &mut this.ptr.as_mut().value }
+        // We are careful to *not* create a reference covering the "count" fields, as
+        // this would conflict with accesses to the reference counts (e.g. by `Weak`).
+        unsafe { &mut (*this.ptr.as_ptr()).value }
     }
 
     #[inline]
@@ -931,10 +940,10 @@ impl<T: Clone> Rc<T> {
             unsafe {
                 let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value));
                 mem::swap(this, &mut swap);
-                swap.dec_strong();
+                swap.inner().dec_strong();
                 // Remove implicit strong-weak ref (no need to craft a fake
                 // Weak here -- we know other Weaks can clean up for us)
-                swap.dec_weak();
+                swap.inner().dec_weak();
                 forget(swap);
             }
         }
@@ -1192,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
     /// ```
     fn drop(&mut self) {
         unsafe {
-            self.dec_strong();
-            if self.strong() == 0 {
+            self.inner().dec_strong();
+            if self.inner().strong() == 0 {
                 // destroy the contained object
-                ptr::drop_in_place(self.ptr.as_mut());
+                ptr::drop_in_place(Self::get_mut_unchecked(self));
 
                 // remove the implicit "strong weak" pointer now that we've
                 // destroyed the contents.
-                self.dec_weak();
+                self.inner().dec_weak();
 
-                if self.weak() == 0 {
+                if self.inner().weak() == 0 {
                     Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
                 }
             }
@@ -1227,7 +1236,7 @@ impl<T: ?Sized> Clone for Rc<T> {
     /// ```
     #[inline]
     fn clone(&self) -> Rc<T> {
-        self.inc_strong();
+        self.inner().inc_strong();
         Self::from_inner(self.ptr)
     }
 }
@@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
     address == usize::MAX
 }
 
+/// Helper type to allow accessing the reference counts without
+/// making any assertions about the data field.
+struct WeakInner<'a> {
+    weak: &'a Cell<usize>,
+    strong: &'a Cell<usize>,
+}
+
 impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
     /// dropping of the inner value if successful.
@@ -1910,11 +1926,21 @@ impl<T: ?Sized> Weak<T> {
             .unwrap_or(0)
     }
 
-    /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`
+    /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`,
     /// (i.e., when this `Weak` was created by `Weak::new`).
     #[inline]
-    fn inner(&self) -> Option<&RcBox<T>> {
-        if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) }
+    fn inner(&self) -> Option<WeakInner<'_>> {
+        if is_dangling(self.ptr) {
+            None
+        } else {
+            // We are careful to *not* create a reference covering the "data" field, as
+            // the field may be mutated concurrently (for example, if the last `Rc`
+            // is dropped, the data field will be dropped in-place).
+            Some(unsafe {
+                let ptr = self.ptr.as_ptr();
+                WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
+            })
+        }
     }
 
     /// Returns `true` if the two `Weak`s point to the same allocation (similar to
@@ -1992,14 +2018,14 @@ impl<T: ?Sized> Drop for Weak<T> {
     /// assert!(other_weak_foo.upgrade().is_none());
     /// ```
     fn drop(&mut self) {
-        if let Some(inner) = self.inner() {
-            inner.dec_weak();
-            // the weak count starts at 1, and will only go to zero if all
-            // the strong pointers have disappeared.
-            if inner.weak() == 0 {
-                unsafe {
-                    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
-                }
+        let inner = if let Some(inner) = self.inner() { inner } else { return };
+
+        inner.dec_weak();
+        // the weak count starts at 1, and will only go to zero if all
+        // the strong pointers have disappeared.
+        if inner.weak() == 0 {
+            unsafe {
+                Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
             }
         }
     }
@@ -2065,12 +2091,13 @@ impl<T> Default for Weak<T> {
 // clone these much in Rust thanks to ownership and move-semantics.
 
 #[doc(hidden)]
-trait RcBoxPtr<T: ?Sized> {
-    fn inner(&self) -> &RcBox<T>;
+trait RcInnerPtr {
+    fn weak_ref(&self) -> &Cell<usize>;
+    fn strong_ref(&self) -> &Cell<usize>;
 
     #[inline]
     fn strong(&self) -> usize {
-        self.inner().strong.get()
+        self.strong_ref().get()
     }
 
     #[inline]
@@ -2084,17 +2111,17 @@ trait RcBoxPtr<T: ?Sized> {
         if strong == 0 || strong == usize::MAX {
             abort();
         }
-        self.inner().strong.set(strong + 1);
+        self.strong_ref().set(strong + 1);
     }
 
     #[inline]
     fn dec_strong(&self) {
-        self.inner().strong.set(self.strong() - 1);
+        self.strong_ref().set(self.strong() - 1);
     }
 
     #[inline]
     fn weak(&self) -> usize {
-        self.inner().weak.get()
+        self.weak_ref().get()
     }
 
     #[inline]
@@ -2108,26 +2135,36 @@ trait RcBoxPtr<T: ?Sized> {
         if weak == 0 || weak == usize::MAX {
             abort();
         }
-        self.inner().weak.set(weak + 1);
+        self.weak_ref().set(weak + 1);
     }
 
     #[inline]
     fn dec_weak(&self) {
-        self.inner().weak.set(self.weak() - 1);
+        self.weak_ref().set(self.weak() - 1);
     }
 }
 
-impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
+impl<T: ?Sized> RcInnerPtr for RcBox<T> {
     #[inline(always)]
-    fn inner(&self) -> &RcBox<T> {
-        unsafe { self.ptr.as_ref() }
+    fn weak_ref(&self) -> &Cell<usize> {
+        &self.weak
+    }
+
+    #[inline(always)]
+    fn strong_ref(&self) -> &Cell<usize> {
+        &self.strong
     }
 }
 
-impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
+impl<'a> RcInnerPtr for WeakInner<'a> {
     #[inline(always)]
-    fn inner(&self) -> &RcBox<T> {
-        self
+    fn weak_ref(&self) -> &Cell<usize> {
+        self.weak
+    }
+
+    #[inline(always)]
+    fn strong_ref(&self) -> &Cell<usize> {
+        self.strong
     }
 }
 
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 2e8b6419eea..cafb002c01a 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -103,7 +103,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
             // dead now (i.e. do not touch). As `idx` was the start of the
             // alive-zone, the alive zone is now `data[alive]` again, restoring
             // all invariants.
-            unsafe { self.data.get_unchecked(idx).read() }
+            unsafe { self.data.get_unchecked(idx).assume_init_read() }
         })
     }
 
@@ -136,7 +136,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
             // dead now (i.e. do not touch). As `idx` was the end of the
             // alive-zone, the alive zone is now `data[alive]` again, restoring
             // all invariants.
-            unsafe { self.data.get_unchecked(idx).read() }
+            unsafe { self.data.get_unchecked(idx).assume_init_read() }
         })
     }
 }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 29bbf062f22..c3cadcbb01e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -100,6 +100,7 @@
 #![feature(doc_cfg)]
 #![feature(doc_spotlight)]
 #![feature(duration_consts_2)]
+#![feature(duration_saturating_ops)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intrinsics)]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 3a7489aa279..b0ebaa6a12b 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -2,6 +2,7 @@ use crate::any::type_name;
 use crate::fmt;
 use crate::intrinsics;
 use crate::mem::ManuallyDrop;
+use crate::ptr;
 
 /// A wrapper type to construct uninitialized instances of `T`.
 ///
@@ -471,6 +472,8 @@ impl<T> MaybeUninit<T> {
     /// *immediate* undefined behavior, but will cause undefined behavior with most
     /// safe operations (including dropping it).
     ///
+    /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
+    ///
     /// # Examples
     ///
     /// Correct usage of this method:
@@ -519,8 +522,8 @@ impl<T> MaybeUninit<T> {
     /// this initialization invariant.
     ///
     /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
-    /// multiple copies of the data (by calling `read` multiple times, or first
-    /// calling `read` and then [`assume_init`]), it is your responsibility
+    /// multiple copies of the data (by calling `assume_init_read` multiple times, or first
+    /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
     /// [inv]: #initialization-invariant
@@ -536,16 +539,16 @@ impl<T> MaybeUninit<T> {
     ///
     /// let mut x = MaybeUninit::<u32>::uninit();
     /// x.write(13);
-    /// let x1 = unsafe { x.read() };
+    /// let x1 = unsafe { x.assume_init_read() };
     /// // `u32` is `Copy`, so we may read multiple times.
-    /// let x2 = unsafe { x.read() };
+    /// let x2 = unsafe { x.assume_init_read() };
     /// assert_eq!(x1, x2);
     ///
     /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
     /// x.write(None);
-    /// let x1 = unsafe { x.read() };
+    /// let x1 = unsafe { x.assume_init_read() };
     /// // Duplicating a `None` value is okay, so we may read multiple times.
-    /// let x2 = unsafe { x.read() };
+    /// let x2 = unsafe { x.assume_init_read() };
     /// assert_eq!(x1, x2);
     /// ```
     ///
@@ -557,14 +560,14 @@ impl<T> MaybeUninit<T> {
     ///
     /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
     /// x.write(Some(vec![0,1,2]));
-    /// let x1 = unsafe { x.read() };
-    /// let x2 = unsafe { x.read() };
+    /// let x1 = unsafe { x.assume_init_read() };
+    /// let x2 = unsafe { x.assume_init_read() };
     /// // We now created two copies of the same vector, leading to a double-free ⚠️ when
     /// // they both get dropped!
     /// ```
     #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[inline(always)]
-    pub unsafe fn read(&self) -> T {
+    pub unsafe fn assume_init_read(&self) -> T {
         // SAFETY: the caller must guarantee that `self` is initialized.
         // Reading from `self.as_ptr()` is safe since `self` should be initialized.
         unsafe {
@@ -573,6 +576,34 @@ impl<T> MaybeUninit<T> {
         }
     }
 
+    /// Drops the contained value in place.
+    ///
+    /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
+    ///
+    /// # Safety
+    ///
+    /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is
+    /// in an initialized state. Calling this when the content is not yet fully
+    /// initialized causes undefined behavior.
+    ///
+    /// On top of that, all additional invariants of the type `T` must be
+    /// satisfied, as the `Drop` implementation of `T` (or its members) may
+    /// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
+    /// initialized (under the current implementation; this does not constitute
+    /// a stable guarantee) because the only requirement the compiler knows
+    /// about it is that the data pointer must be non-null. Dropping such a
+    /// `Vec<T>` however will cause undefined behaviour.
+    ///
+    /// [`assume_init`]: MaybeUninit::assume_init
+    /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
+    #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
+    pub unsafe fn assume_init_drop(&mut self) {
+        // SAFETY: the caller must guarantee that `self` is initialized and
+        // satisfies all invariants of `T`.
+        // Dropping the value in place is safe if that is the case.
+        unsafe { ptr::drop_in_place(self.as_mut_ptr()) }
+    }
+
     /// Gets a shared reference to the contained value.
     ///
     /// This can be useful when we want to access a `MaybeUninit` that has been
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index bcfff4a223b..3d71e0b0002 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -36,6 +36,15 @@ pub trait Not {
     type Output;
 
     /// Performs the unary `!` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(!true, false);
+    /// assert_eq!(!false, true);
+    /// assert_eq!(!1u8, 254);
+    /// assert_eq!(!0u8, 255);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn not(self) -> Self::Output;
@@ -122,6 +131,15 @@ pub trait BitAnd<Rhs = Self> {
     type Output;
 
     /// Performs the `&` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(true & false, false);
+    /// assert_eq!(true & true, true);
+    /// assert_eq!(5u8 & 1u8, 1);
+    /// assert_eq!(5u8 & 2u8, 0);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn bitand(self, rhs: Rhs) -> Self::Output;
@@ -208,6 +226,15 @@ pub trait BitOr<Rhs = Self> {
     type Output;
 
     /// Performs the `|` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(true | false, true);
+    /// assert_eq!(false | false, false);
+    /// assert_eq!(5u8 | 1u8, 5);
+    /// assert_eq!(5u8 | 2u8, 7);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn bitor(self, rhs: Rhs) -> Self::Output;
@@ -297,6 +324,15 @@ pub trait BitXor<Rhs = Self> {
     type Output;
 
     /// Performs the `^` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(true ^ false, true);
+    /// assert_eq!(true ^ true, false);
+    /// assert_eq!(5u8 ^ 1u8, 4);
+    /// assert_eq!(5u8 ^ 2u8, 7);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn bitxor(self, rhs: Rhs) -> Self::Output;
@@ -387,6 +423,13 @@ pub trait Shl<Rhs = Self> {
     type Output;
 
     /// Performs the `<<` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(5u8 << 1, 10);
+    /// assert_eq!(1u8 << 1, 2);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn shl(self, rhs: Rhs) -> Self::Output;
@@ -498,6 +541,13 @@ pub trait Shr<Rhs = Self> {
     type Output;
 
     /// Performs the `>>` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert_eq!(5u8 >> 1, 2);
+    /// assert_eq!(2u8 >> 1, 1);
+    /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn shr(self, rhs: Rhs) -> Self::Output;
@@ -612,6 +662,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 )]
 pub trait BitAndAssign<Rhs = Self> {
     /// Performs the `&=` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x = true;
+    /// x &= false;
+    /// assert_eq!(x, false);
+    ///
+    /// let mut x = true;
+    /// x &= true;
+    /// assert_eq!(x, true);
+    ///
+    /// let mut x: u8 = 5;
+    /// x &= 1;
+    /// assert_eq!(x, 1);
+    ///
+    /// let mut x: u8 = 5;
+    /// x &= 2;
+    /// assert_eq!(x, 0);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn bitand_assign(&mut self, rhs: Rhs);
 }
@@ -663,6 +733,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 )]
 pub trait BitOrAssign<Rhs = Self> {
     /// Performs the `|=` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x = true;
+    /// x |= false;
+    /// assert_eq!(x, true);
+    ///
+    /// let mut x = false;
+    /// x |= false;
+    /// assert_eq!(x, false);
+    ///
+    /// let mut x: u8 = 5;
+    /// x |= 1;
+    /// assert_eq!(x, 5);
+    ///
+    /// let mut x: u8 = 5;
+    /// x |= 2;
+    /// assert_eq!(x, 7);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn bitor_assign(&mut self, rhs: Rhs);
 }
@@ -714,6 +804,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 )]
 pub trait BitXorAssign<Rhs = Self> {
     /// Performs the `^=` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x = true;
+    /// x ^= false;
+    /// assert_eq!(x, true);
+    ///
+    /// let mut x = true;
+    /// x ^= true;
+    /// assert_eq!(x, false);
+    ///
+    /// let mut x: u8 = 5;
+    /// x ^= 1;
+    /// assert_eq!(x, 4);
+    ///
+    /// let mut x: u8 = 5;
+    /// x ^= 2;
+    /// assert_eq!(x, 7);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn bitxor_assign(&mut self, rhs: Rhs);
 }
@@ -763,6 +873,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 )]
 pub trait ShlAssign<Rhs = Self> {
     /// Performs the `<<=` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x: u8 = 5;
+    /// x <<= 1;
+    /// assert_eq!(x, 10);
+    ///
+    /// let mut x: u8 = 1;
+    /// x <<= 1;
+    /// assert_eq!(x, 2);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn shl_assign(&mut self, rhs: Rhs);
 }
@@ -833,6 +955,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 )]
 pub trait ShrAssign<Rhs = Self> {
     /// Performs the `>>=` operation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x: u8 = 5;
+    /// x >>= 1;
+    /// assert_eq!(x, 2);
+    ///
+    /// let mut x: u8 = 2;
+    /// x >>= 1;
+    /// assert_eq!(x, 1);
+    /// ```
     #[stable(feature = "op_assign_traits", since = "1.8.0")]
     fn shr_assign(&mut self, rhs: Rhs);
 }
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 5741f8a53b5..f39781788d7 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -108,6 +108,34 @@ impl Duration {
     #[unstable(feature = "duration_constants", issue = "57391")]
     pub const NANOSECOND: Duration = Duration::from_nanos(1);
 
+    /// The minimum duration.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constants)]
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::MIN, Duration::new(0, 0));
+    /// ```
+    #[unstable(feature = "duration_constants", issue = "57391")]
+    pub const MIN: Duration = Duration::from_nanos(0);
+
+    /// The maximum duration.
+    ///
+    /// It is roughly equal to a duration of 584,942,417,355 years.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constants)]
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1));
+    /// ```
+    #[unstable(feature = "duration_constants", issue = "57391")]
+    pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1);
+
     /// Creates a new `Duration` from the specified number of whole seconds and
     /// additional nanoseconds.
     ///
@@ -450,6 +478,29 @@ impl Duration {
         }
     }
 
+    /// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`]
+    /// if overflow occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_saturating_ops)]
+    /// #![feature(duration_constants)]
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
+    /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
+    /// ```
+    #[unstable(feature = "duration_saturating_ops", issue = "76416")]
+    #[inline]
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn saturating_add(self, rhs: Duration) -> Duration {
+        match self.checked_add(rhs) {
+            Some(res) => res,
+            None => Duration::MAX,
+        }
+    }
+
     /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
     /// if the result would be negative or if overflow occurred.
     ///
@@ -485,6 +536,29 @@ impl Duration {
         }
     }
 
+    /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`]
+    /// if the result would be negative or if overflow occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_saturating_ops)]
+    /// #![feature(duration_constants)]
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1));
+    /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN);
+    /// ```
+    #[unstable(feature = "duration_saturating_ops", issue = "76416")]
+    #[inline]
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn saturating_sub(self, rhs: Duration) -> Duration {
+        match self.checked_sub(rhs) {
+            Some(res) => res,
+            None => Duration::MIN,
+        }
+    }
+
     /// Checked `Duration` multiplication. Computes `self * other`, returning
     /// [`None`] if overflow occurred.
     ///
@@ -515,6 +589,29 @@ impl Duration {
         None
     }
 
+    /// Saturating `Duration` multiplication. Computes `self * other`, returning
+    /// [`Duration::MAX`] if overflow occurred.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_saturating_ops)]
+    /// #![feature(duration_constants)]
+    /// use std::time::Duration;
+    ///
+    /// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2));
+    /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
+    /// ```
+    #[unstable(feature = "duration_saturating_ops", issue = "76416")]
+    #[inline]
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn saturating_mul(self, rhs: u32) -> Duration {
+        match self.checked_mul(rhs) {
+            Some(res) => res,
+            None => Duration::MAX,
+        }
+    }
+
     /// Checked `Duration` division. Computes `self / other`, returning [`None`]
     /// if `other == 0`.
     ///
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 4a651e5aa0e..a2e294ace18 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -10,6 +10,8 @@
 #![feature(core_private_diy_float)]
 #![feature(debug_non_exhaustive)]
 #![feature(dec2flt)]
+#![feature(duration_constants)]
+#![feature(duration_saturating_ops)]
 #![feature(exact_size_is_empty)]
 #![feature(fixed_size_array)]
 #![feature(flt2dec)]
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index 7a6675dc82f..4f90eb63b04 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -90,6 +90,16 @@ fn checked_add() {
 }
 
 #[test]
+fn saturating_add() {
+    assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
+    assert_eq!(
+        Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)),
+        Duration::new(1, 1)
+    );
+    assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
+}
+
+#[test]
 fn sub() {
     assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
     assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), Duration::new(0, 1));
@@ -108,6 +118,17 @@ fn checked_sub() {
 }
 
 #[test]
+fn saturating_sub() {
+    let zero = Duration::new(0, 0);
+    let one_nano = Duration::new(0, 1);
+    let one_sec = Duration::new(1, 0);
+    assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1));
+    assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999));
+    assert_eq!(zero.saturating_sub(one_nano), Duration::MIN);
+    assert_eq!(zero.saturating_sub(one_sec), Duration::MIN);
+}
+
+#[test]
 #[should_panic]
 fn sub_bad1() {
     let _ = Duration::new(0, 0) - Duration::new(0, 1);
@@ -137,6 +158,15 @@ fn checked_mul() {
 }
 
 #[test]
+fn saturating_mul() {
+    assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2));
+    assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3));
+    assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4));
+    assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000));
+    assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
+}
+
+#[test]
 fn div() {
     assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
     assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index 14719a9be5e..ff23c3d67e3 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -1,3 +1,5 @@
+//! Linux-specific extensions to primitives in the `std::fs` module.
+
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
 use crate::fs::Metadata;
diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs
index d35307162cc..f179a524336 100644
--- a/library/std/src/os/linux/mod.rs
+++ b/library/std/src/os/linux/mod.rs
@@ -1,4 +1,4 @@
-//! Linux-specific definitions
+//! Linux-specific definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index 1950ffcb21b..a007fd2b6be 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -1,4 +1,4 @@
-//! Linux-specific raw type definitions
+//! Linux-specific raw type definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 #![rustc_deprecated(
diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs
index 76b34a6b5d8..123f85deaf9 100644
--- a/library/std/src/sys/unix/ext/ffi.rs
+++ b/library/std/src/sys/unix/ext/ffi.rs
@@ -1,4 +1,4 @@
-//! Unix-specific extension to the primitives in the `std::ffi` module
+//! Unix-specific extension to the primitives in the `std::ffi` module.
 //!
 //! # Examples
 //!
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs
index 5077e2e28d1..ec7a32b675c 100644
--- a/library/std/src/sys/unix/ext/io.rs
+++ b/library/std/src/sys/unix/ext/io.rs
@@ -1,4 +1,4 @@
-//! Unix-specific extensions to general I/O primitives
+//! Unix-specific extensions to general I/O primitives.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs
index 3fbd0cb58b1..320378e30cc 100644
--- a/library/std/src/sys/unix/ext/net.rs
+++ b/library/std/src/sys/unix/ext/net.rs
@@ -1,6 +1,6 @@
-#![stable(feature = "unix_socket", since = "1.10.0")]
+//! Unix-specific networking functionality.
 
-//! Unix-specific networking functionality
+#![stable(feature = "unix_socket", since = "1.10.0")]
 
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs
index 40fa53d484f..3199a0bff0b 100644
--- a/library/std/src/sys/unix/ext/raw.rs
+++ b/library/std/src/sys/unix/ext/raw.rs
@@ -1,4 +1,4 @@
-//! Unix-specific primitives available on all unix platforms
+//! Unix-specific primitives available on all unix platforms.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 #![rustc_deprecated(
diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs
index 4573ee58932..e75f9a4bfd5 100644
--- a/library/std/src/sys/windows/ext/io.rs
+++ b/library/std/src/sys/windows/ext/io.rs
@@ -1,3 +1,5 @@
+//! Windows-specific extensions to general I/O primitives.
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fs;
diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs
index 7f2a2877828..5014e008eb5 100644
--- a/library/std/src/sys/windows/ext/raw.rs
+++ b/library/std/src/sys/windows/ext/raw.rs
@@ -1,4 +1,4 @@
-//! Windows-specific primitives
+//! Windows-specific primitives.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1bdbad46755..9d784d24609 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1364,16 +1364,16 @@ impl Clean<Type> for hir::Ty<'_> {
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
             TyKind::Array(ref ty, ref length) => {
                 let def_id = cx.tcx.hir().local_def_id(length.hir_id);
-                let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) {
-                    Ok(length) => {
-                        print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize))
-                    }
-                    Err(_) => cx
-                        .sess()
-                        .source_map()
-                        .span_to_snippet(cx.tcx.def_span(def_id))
-                        .unwrap_or_else(|_| "_".to_string()),
-                };
+                // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+                // as we currently do not supply the parent generics to anonymous constants
+                // but do allow `ConstKind::Param`.
+                //
+                // `const_eval_poly` tries to to first substitute generic parameters which
+                // results in an ICE while manually constructing the constant and using `eval`
+                // does nothing for `ConstKind::Param`.
+                let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+                let param_env = cx.tcx.param_env(def_id);
+                let length = print_const(cx, ct.eval(cx.tcx, param_env));
                 Array(box ty.clean(cx), length)
             }
             TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs
new file mode 100644
index 00000000000..3064d0701e3
--- /dev/null
+++ b/src/test/rustdoc/const-generics/type-alias.rs
@@ -0,0 +1,6 @@
+// ignore-tidy-linelength
+#![feature(min_const_generics)]
+#![crate_name = "foo"]
+
+// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];'
+pub type CellIndex<const D: usize> = [i64; D];
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr
index 6e4a22a38b1..b2816367ea1 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr
@@ -1,5 +1,5 @@
 error: constant expression depends on a generic parameter
-  --> $DIR/feature-gate-const_evaluatable_checked.rs:6:30
+  --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30
    |
 LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
    |                              ^^^^^^
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
new file mode 100644
index 00000000000..269710db164
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
+   |
+LL | type Arr<const N: usize> = [u8; N - 1];
+   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
index 941bd5e9e5d..af3090115f2 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
@@ -1,10 +1,13 @@
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 type Arr<const N: usize> = [u8; N - 1];
+//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
-    //~^ ERROR constant expression depends
+    //[full]~^ ERROR constant expression depends
     Default::default()
 }
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
new file mode 100644
index 00000000000..da8ccdaee41
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/simple.rs:8:33
+   |
+LL | type Arr<const N: usize> = [u8; N - 1];
+   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs
index a7ead78b97b..27dc6b10320 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs
@@ -1,8 +1,12 @@
-// run-pass
-#![feature(const_generics, const_evaluatable_checked)]
+// [full] run-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+#![feature(const_evaluatable_checked)]
 #![allow(incomplete_features)]
 
 type Arr<const N: usize> = [u8; N - 1];
+//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
     Default::default()
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
index 1ac5e1d9553..104cab8667c 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/simple_fail.rs:4:33
+  --> $DIR/simple_fail.rs:7:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
new file mode 100644
index 00000000000..042710f1327
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/simple_fail.rs:7:33
+   |
+LL | type Arr<const N: usize> = [u8; N - 1];
+   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
index 1edf1885dd2..b15e0ff1839 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -1,7 +1,11 @@
-#![feature(const_generics, const_evaluatable_checked)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+#![feature(const_evaluatable_checked)]
 #![allow(incomplete_features)]
 
-type Arr<const N: usize> = [u8; N - 1]; //~ ERROR evaluation of constant
+type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
+//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
     todo!()
diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
index c8db91b62b5..aa85376bf0d 100644
--- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
+++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
@@ -1,5 +1,6 @@
-#![feature(const_generics)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
 
 pub struct Struct<const N: usize>(());
 
diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs
index c8b39399331..bc0969e4f1f 100644
--- a/src/test/ui/consts/duration-consts-2.rs
+++ b/src/test/ui/consts/duration-consts-2.rs
@@ -3,6 +3,7 @@
 #![feature(const_panic)]
 #![feature(duration_consts_2)]
 #![feature(div_duration)]
+#![feature(duration_saturating_ops)]
 
 use std::time::Duration;
 
@@ -15,29 +16,29 @@ fn duration() {
 
     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_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
+    assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));
 
-    const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
-    assert_eq!(MAX_ADD_ONE, None);
+    const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
+    assert_eq!(MAX_CHECKED_ADD_ONE, None);
 
-    const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
-    assert_eq!(ONE_SUB_ONE, Some(ZERO));
+    const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
+    assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));
 
-    const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
-    assert_eq!(ZERO_SUB_ONE, None);
+    const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
+    assert_eq!(ZERO_CHECKED_SUB_ONE, None);
 
-    const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
-    assert_eq!(ONE_MUL_ONE, Some(ONE));
+    const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
+    assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));
 
-    const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
-    assert_eq!(MAX_MUL_TWO, None);
+    const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
+    assert_eq!(MAX_CHECKED_MUL_TWO, None);
 
-    const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1);
-    assert_eq!(ONE_DIV_ONE, Some(ONE));
+    const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
+    assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));
 
-    const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
-    assert_eq!(ONE_DIV_ZERO, None);
+    const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
+    assert_eq!(ONE_CHECKED_DIV_ZERO, None);
 
     const MAX_AS_F32 : f32 = MAX.as_secs_f32();
     assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
@@ -50,6 +51,15 @@ fn duration() {
 
     const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
     assert_eq!(ONE_AS_F64, 1.0_f64);
+
+    const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
+    assert_eq!(MAX_SATURATING_ADD_ONE, MAX);
+
+    const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
+    assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);
+
+    const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
+    assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
 }
 
 fn main() {