diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a9b293856e57b..f998e49dcfcde 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -295,6 +295,13 @@ impl, U: ?Sized> CoerceUnsized> for Rc {} impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + // 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>) -> Self { Self { ptr, phantom: PhantomData } } @@ -469,7 +476,7 @@ impl Rc { // 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 Rc { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { - 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 Rc { #[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 Rc { #[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 Rc { #[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 Rc { 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 { /// ``` 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 Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inc_strong(); + self.inner().inc_strong(); Self::from_inner(self.ptr) } } @@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling(ptr: NonNull) -> 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, + strong: &'a Cell, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. @@ -1910,11 +1926,21 @@ impl Weak { .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> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + 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 Drop for Weak { /// 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 Default for Weak { // clone these much in Rust thanks to ownership and move-semantics. #[doc(hidden)] -trait RcBoxPtr { - fn inner(&self) -> &RcBox; +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; #[inline] fn strong(&self) -> usize { - self.inner().strong.get() + self.strong_ref().get() } #[inline] @@ -2084,17 +2111,17 @@ trait RcBoxPtr { 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 { 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 RcBoxPtr for Rc { +impl RcInnerPtr for RcBox { #[inline(always)] - fn inner(&self) -> &RcBox { - unsafe { self.ptr.as_ref() } + fn weak_ref(&self) -> &Cell { + &self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + &self.strong } } -impl RcBoxPtr for RcBox { +impl<'a> RcInnerPtr for WeakInner<'a> { #[inline(always)] - fn inner(&self) -> &RcBox { - self + fn weak_ref(&self) -> &Cell { + self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + self.strong } } diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 2e8b6419eea1e..cafb002c01a11 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -103,7 +103,7 @@ impl Iterator for IntoIter { // 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 DoubleEndedIterator for IntoIter { // 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 29bbf062f22e4..c3cadcbb01e31 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 3a7489aa27955..b0ebaa6a12b51 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 MaybeUninit { /// *immediate* undefined behavior, but will cause undefined behavior with most /// safe operations (including dropping it). /// + /// [`Vec`]: ../../std/vec/struct.Vec.html + /// /// # Examples /// /// Correct usage of this method: @@ -519,8 +522,8 @@ impl MaybeUninit { /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. 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 MaybeUninit { /// /// let mut x = MaybeUninit::::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::>>::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 MaybeUninit { /// /// let mut x = MaybeUninit::>>::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 MaybeUninit { } } + /// 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` 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`] 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` however will cause undefined behaviour. + /// + /// [`assume_init`]: MaybeUninit::assume_init + /// [`Vec`]: ../../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 bcfff4a223bec..3d71e0b0002c2 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 { 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 { 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 { 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 { 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 { 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 { /// 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 { /// 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 { /// 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 { /// 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 { /// 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 5741f8a53b522..f39781788d7c0 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 4a651e5aa0ee3..a2e294ace1860 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 7a6675dc82fa6..4f90eb63b0472 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -89,6 +89,16 @@ fn checked_add() { assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); } +#[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)); @@ -107,6 +117,17 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } +#[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() { @@ -136,6 +157,15 @@ fn checked_mul() { assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); } +#[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)); diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index 14719a9be5e8a..ff23c3d67e3b4 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 d35307162cc7e..f179a524336fc 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 1950ffcb21b67..a007fd2b6be04 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 76b34a6b5d84a..123f85deaf9e3 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 5077e2e28d18b..ec7a32b675c02 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 3fbd0cb58b120..320378e30ccb1 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 40fa53d484f84..3199a0bff0bcc 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 4573ee589321d..e75f9a4bfd5e3 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 7f2a2877828cf..5014e008eb599 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 1bdbad4675556..9d784d24609dc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1364,16 +1364,16 @@ impl Clean 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 0000000000000..3064d0701e300 --- /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 = [i64; D];' +pub type CellIndex = [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 similarity index 82% rename from src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr index 6e4a22a38b17c..b2816367ea107 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() -> Arr where Arr: 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 0000000000000..269710db164b1 --- /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 = [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 941bd5e9e5d0a..af3090115f24a 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 = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: 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 0000000000000..da8ccdaee4146 --- /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 = [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 a7ead78b97bae..27dc6b103200d 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 = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: 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 similarity index 90% rename from src/test/ui/const-generics/const_evaluatable_checked/simple_fail.stderr rename to src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr index 1ac5e1d95537a..104cab8667c70 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 = [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 0000000000000..042710f13273e --- /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 = [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 1edf1885dd281..b15e0ff183954 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 = [u8; N - 1]; //~ ERROR evaluation of constant +type Arr = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values fn test() -> Arr where Arr: 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 c8db91b62b58c..aa85376bf0d75 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(()); diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs index c8b3939933126..bc0969e4f1fba 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 = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); + const MAX_CHECKED_ADD_ZERO : Option = MAX.checked_add(ZERO); + assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - const MAX_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); + const MAX_CHECKED_ADD_ONE : Option = MAX.checked_add(ONE); + assert_eq!(MAX_CHECKED_ADD_ONE, None); - const ONE_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); + const ONE_CHECKED_SUB_ONE : Option = ONE.checked_sub(ONE); + assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - const ZERO_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); + const ZERO_CHECKED_SUB_ONE : Option = ZERO.checked_sub(ONE); + assert_eq!(ZERO_CHECKED_SUB_ONE, None); - const ONE_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); + const ONE_CHECKED_MUL_ONE : Option = ONE.checked_mul(1); + assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - const MAX_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); + const MAX_CHECKED_MUL_TWO : Option = MAX.checked_mul(2); + assert_eq!(MAX_CHECKED_MUL_TWO, None); - const ONE_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); + const ONE_CHECKED_DIV_ONE : Option = ONE.checked_div(1); + assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - const ONE_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); + const ONE_CHECKED_DIV_ZERO : Option = 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() {