Auto merge of #76637 - RalfJung:rollup-eaykf93, r=RalfJung

Rollup of 7 pull requests

Successful merges:

 - #76114 (Add saturating methods for `Duration`)
 - #76297 (rustdoc: fix min_const_generics with ty::Param)
 - #76484 (Add MaybeUninit::assume_init_drop.)
 - #76530 (Eliminate mut reference UB in Drop impl for Rc<T>)
 - #76583 (Update `std::os` module documentation.)
 - #76599 (Finish off revisions for const generics UI tests.)
 - #76615 (Add missing examples on binary core traits)

Failed merges:

r? `@ghost`
This commit is contained in:
bors 2020-09-12 09:34:37 +00:00
commit 2d6cbd21b2
29 changed files with 488 additions and 94 deletions

View File

@ -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
}
}

View File

@ -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() }
})
}
}

View File

@ -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)]

View File

@ -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

View File

@ -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);
}

View File

@ -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`.
///

View File

@ -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)]

View File

@ -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));

View File

@ -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;

View File

@ -1,4 +1,4 @@
//! Linux-specific definitions
//! Linux-specific definitions.
#![stable(feature = "raw_ext", since = "1.1.0")]

View File

@ -1,4 +1,4 @@
//! Linux-specific raw type definitions
//! Linux-specific raw type definitions.
#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(

View File

@ -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
//!

View File

@ -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")]

View File

@ -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;

View File

@ -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(

View File

@ -1,3 +1,5 @@
//! Windows-specific extensions to general I/O primitives.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs;

View File

@ -1,4 +1,4 @@
//! Windows-specific primitives
//! Windows-specific primitives.
#![stable(feature = "raw_ext", since = "1.1.0")]

View File

@ -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)),

View File

@ -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];

View File

@ -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 {
| ^^^^^^

View File

@ -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

View File

@ -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()
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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!()

View File

@ -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>(());

View File

@ -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() {