Importing rustc-1.53.0 Bug: 194400612 Change-Id: Id2f38eeabc8325fff960e46b89b1cc7216f5227c
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index c159601..b6aaf07 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml
@@ -2,6 +2,9 @@ authors = ["The Rust Project Developers"] name = "core" version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "The Rust Core Library" autotests = false autobenches = false edition = "2018" @@ -25,3 +28,6 @@ [features] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = [] +# Make `RefCell` store additional debugging information, which is printed out when +# a borrow error occurs +debug_refcell = []
diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs index 2792181..9df6626 100644 --- a/library/core/benches/fmt.rs +++ b/library/core/benches/fmt.rs
@@ -112,7 +112,7 @@ #[bench] fn write_u128_max(bh: &mut Bencher) { bh.iter(|| { - std::hint::black_box(format!("{}", u128::MAX)); + test::black_box(format!("{}", u128::MAX)); }); } @@ -120,20 +120,20 @@ fn write_u128_min(bh: &mut Bencher) { bh.iter(|| { let s = format!("{}", 0u128); - std::hint::black_box(s); + test::black_box(s); }); } #[bench] fn write_u64_max(bh: &mut Bencher) { bh.iter(|| { - std::hint::black_box(format!("{}", u64::MAX)); + test::black_box(format!("{}", u64::MAX)); }); } #[bench] fn write_u64_min(bh: &mut Bencher) { bh.iter(|| { - std::hint::black_box(format!("{}", 0u64)); + test::black_box(format!("{}", 0u64)); }); }
diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs index dbab008..04efa52 100644 --- a/library/core/benches/slice.rs +++ b/library/core/benches/slice.rs
@@ -114,3 +114,16 @@ rotate!(rotate_16_usize_5, 16, |i| [i; 5]); rotate!(rotate_64_usize_4, 64, |i| [i; 4]); rotate!(rotate_64_usize_5, 64, |i| [i; 5]); + +#[bench] +fn fill_byte_sized(b: &mut Bencher) { + #[derive(Copy, Clone)] + struct NewType(u8); + + let mut ary = [NewType(0); 1024]; + + b.iter(|| { + let slice = &mut ary[..]; + black_box(slice.fill(black_box(NewType(42)))); + }); +}
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 8b95b70..0e7667d 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs
@@ -93,7 +93,7 @@ /// This function is unsafe as it does not verify the preconditions from /// [`Layout::from_size_align`]. #[stable(feature = "alloc_layout", since = "1.28.0")] - #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")] + #[rustc_const_stable(feature = "alloc_layout", since = "1.36.0")] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { // SAFETY: the caller must ensure that `align` is greater than zero.
diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 98c34f3..5e1725c 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs
@@ -141,7 +141,7 @@ #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for dyn Any { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Any") + f.debug_struct("Any").finish_non_exhaustive() } } @@ -151,14 +151,14 @@ #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for dyn Any + Send { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Any") + f.debug_struct("Any").finish_non_exhaustive() } } #[stable(feature = "any_send_sync_methods", since = "1.28.0")] impl fmt::Debug for dyn Any + Send + Sync { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Any") + f.debug_struct("Any").finish_non_exhaustive() } }
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 4472fba..61ab1b1 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs
@@ -2,7 +2,7 @@ use crate::{ fmt, - iter::{ExactSizeIterator, FusedIterator, TrustedLen}, + iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, mem::{self, MaybeUninit}, ops::Range, ptr, @@ -192,7 +192,7 @@ let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 }; // Clone all alive elements. - for (src, dst) in self.as_slice().iter().zip(&mut new.data) { + for (src, dst) in iter::zip(self.as_slice(), &mut new.data) { // Write a clone into the new array, then update its alive range. // If cloning panics, we'll correctly drop the previous items. dst.write(src.clone());
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 8f52985..8b56c95 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs
@@ -12,7 +12,6 @@ use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; -use crate::marker::Unsize; use crate::mem::{self, MaybeUninit}; use crate::ops::{Index, IndexMut}; use crate::slice::{Iter, IterMut}; @@ -23,54 +22,19 @@ pub use iter::IntoIter; /// Converts a reference to `T` into a reference to an array of length 1 (without copying). -#[unstable(feature = "array_from_ref", issue = "77101")] +#[stable(feature = "array_from_ref", since = "1.53.0")] pub fn from_ref<T>(s: &T) -> &[T; 1] { // SAFETY: Converting `&T` to `&[T; 1]` is sound. unsafe { &*(s as *const T).cast::<[T; 1]>() } } /// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). -#[unstable(feature = "array_from_ref", issue = "77101")] +#[stable(feature = "array_from_ref", since = "1.53.0")] pub fn from_mut<T>(s: &mut T) -> &mut [T; 1] { // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } } -/// Utility trait implemented only on arrays of fixed size -/// -/// This trait can be used to implement other traits on fixed-size arrays -/// without causing much metadata bloat. -/// -/// The trait is marked unsafe in order to restrict implementors to fixed-size -/// arrays. A user of this trait can assume that implementors have the exact -/// layout in memory of a fixed size array (for example, for unsafe -/// initialization). -/// -/// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that -/// may not be fixed-size arrays. Implementors should prefer those traits -/// instead. -#[unstable(feature = "fixed_size_array", issue = "27778")] -pub unsafe trait FixedSizeArray<T> { - /// Converts the array to immutable slice - #[unstable(feature = "fixed_size_array", issue = "27778")] - fn as_slice(&self) -> &[T]; - /// Converts the array to mutable slice - #[unstable(feature = "fixed_size_array", issue = "27778")] - fn as_mut_slice(&mut self) -> &mut [T]; -} - -#[unstable(feature = "fixed_size_array", issue = "27778")] -unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A { - #[inline] - fn as_slice(&self) -> &[T] { - self - } - #[inline] - fn as_mut_slice(&mut self) -> &mut [T] { - self - } -} - /// The error type returned when a conversion from a slice to an array fails. #[stable(feature = "try_from", since = "1.34.0")] #[derive(Debug, Copy, Clone)] @@ -191,6 +155,28 @@ } } +// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator` +// hides this implementation from explicit `.into_iter()` calls on editions < 2021, +// so those calls will still resolve to the slice implementation, by reference. +#[cfg(not(bootstrap))] +#[stable(feature = "array_into_iter_impl", since = "1.53.0")] +impl<T, const N: usize> IntoIterator for [T; N] { + type Item = T; + type IntoIter = IntoIter<T, N>; + + /// Creates a consuming iterator, that is, one that moves each value out of + /// the array (from start to end). The array cannot be used after calling + /// this unless `T` implements `Copy`, so the whole array is copied. + /// + /// Arrays have special behavior when calling `.into_iter()` prior to the + /// 2021 edition -- see the [array] Editions section for more information. + /// + /// [array]: prim@array + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, const N: usize> IntoIterator for &'a [T; N] { type Item = &'a T;
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index a8a25f9..4780d8d 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs
@@ -145,6 +145,6 @@ #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EscapeDefault { .. }") + f.debug_struct("EscapeDefault").finish_non_exhaustive() } }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 2fbbeb3..4820588 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs
@@ -188,7 +188,7 @@ //! [`Rc<T>`]: ../../std/rc/struct.Rc.html //! [`RwLock<T>`]: ../../std/sync/struct.RwLock.html //! [`Mutex<T>`]: ../../std/sync/struct.Mutex.html -//! [`atomic`]: ../../core/sync/atomic/index.html +//! [`atomic`]: crate::sync::atomic #![stable(feature = "rust1", since = "1.0.0")] @@ -325,7 +325,7 @@ /// let c = Cell::new(5); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_cell_new", since = "1.32.0")] + #[rustc_const_stable(feature = "const_cell_new", since = "1.24.0")] #[inline] pub const fn new(value: T) -> Cell<T> { Cell { value: UnsafeCell::new(value) } @@ -575,6 +575,12 @@ #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell<T: ?Sized> { borrow: Cell<BorrowFlag>, + // Stores the location of the earliest currently active borrow. + // This gets updated whenver we go from having zero borrows + // to having a single borrow. When a borrow occurs, this gets included + // in the generated `BorroeError/`BorrowMutError` + #[cfg(feature = "debug_refcell")] + borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>, value: UnsafeCell<T>, } @@ -582,12 +588,19 @@ #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowError { _private: (), + #[cfg(feature = "debug_refcell")] + location: &'static crate::panic::Location<'static>, } #[stable(feature = "try_borrow", since = "1.13.0")] impl Debug for BorrowError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowError").finish() + let mut builder = f.debug_struct("BorrowError"); + + #[cfg(feature = "debug_refcell")] + builder.field("location", self.location); + + builder.finish() } } @@ -602,12 +615,19 @@ #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowMutError { _private: (), + #[cfg(feature = "debug_refcell")] + location: &'static crate::panic::Location<'static>, } #[stable(feature = "try_borrow", since = "1.13.0")] impl Debug for BorrowMutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowMutError").finish() + let mut builder = f.debug_struct("BorrowMutError"); + + #[cfg(feature = "debug_refcell")] + builder.field("location", self.location); + + builder.finish() } } @@ -655,10 +675,15 @@ /// let c = RefCell::new(5); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_refcell_new", since = "1.32.0")] + #[rustc_const_stable(feature = "const_refcell_new", since = "1.24.0")] #[inline] pub const fn new(value: T) -> RefCell<T> { - RefCell { value: UnsafeCell::new(value), borrow: Cell::new(UNUSED) } + RefCell { + value: UnsafeCell::new(value), + borrow: Cell::new(UNUSED), + #[cfg(feature = "debug_refcell")] + borrowed_at: Cell::new(None), + } } /// Consumes the `RefCell`, returning the wrapped value. @@ -823,12 +848,29 @@ /// ``` #[stable(feature = "try_borrow", since = "1.13.0")] #[inline] + #[cfg_attr(feature = "debug_refcell", track_caller)] pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> { match BorrowRef::new(&self.borrow) { - // SAFETY: `BorrowRef` ensures that there is only immutable access - // to the value while borrowed. - Some(b) => Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b }), - None => Err(BorrowError { _private: () }), + Some(b) => { + #[cfg(feature = "debug_refcell")] + { + // `borrowed_at` is always the *first* active borrow + if b.borrow.get() == 1 { + self.borrowed_at.set(Some(crate::panic::Location::caller())); + } + } + + // SAFETY: `BorrowRef` ensures that there is only immutable access + // to the value while borrowed. + Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b }) + } + None => Err(BorrowError { + _private: (), + // If a borrow occured, then we must already have an outstanding borrow, + // so `borrowed_at` will be `Some` + #[cfg(feature = "debug_refcell")] + location: self.borrowed_at.get().unwrap(), + }), } } @@ -896,11 +938,25 @@ /// ``` #[stable(feature = "try_borrow", since = "1.13.0")] #[inline] + #[cfg_attr(feature = "debug_refcell", track_caller)] pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> { match BorrowRefMut::new(&self.borrow) { - // SAFETY: `BorrowRef` guarantees unique access. - Some(b) => Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b }), - None => Err(BorrowMutError { _private: () }), + Some(b) => { + #[cfg(feature = "debug_refcell")] + { + self.borrowed_at.set(Some(crate::panic::Location::caller())); + } + + // SAFETY: `BorrowRef` guarantees unique access. + Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b }) + } + None => Err(BorrowMutError { + _private: (), + // If a borrow occured, then we must already have an outstanding borrow, + // so `borrowed_at` will be `Some` + #[cfg(feature = "debug_refcell")] + location: self.borrowed_at.get().unwrap(), + }), } } @@ -1016,7 +1072,13 @@ // and is thus guaranteed to be valid for the lifetime of `self`. Ok(unsafe { &*self.value.get() }) } else { - Err(BorrowError { _private: () }) + Err(BorrowError { + _private: (), + // If a borrow occured, then we must already have an outstanding borrow, + // so `borrowed_at` will be `Some` + #[cfg(feature = "debug_refcell")] + location: self.borrowed_at.get().unwrap(), + }) } } } @@ -1753,7 +1815,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafe_cell_new", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn new(value: T) -> UnsafeCell<T> { UnsafeCell { value } } @@ -1769,7 +1831,7 @@ /// /// let five = uc.into_inner(); /// ``` - #[inline] + #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] pub const fn into_inner(self) -> T { @@ -1794,7 +1856,7 @@ /// /// let five = uc.get(); /// ``` - #[inline] + #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] pub const fn get(&self) -> *mut T { @@ -1819,7 +1881,7 @@ /// /// assert_eq!(*c.get_mut(), 6); /// ``` - #[inline] + #[inline(always)] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] pub fn get_mut(&mut self) -> &mut T { &mut self.value @@ -1852,7 +1914,7 @@ /// /// assert_eq!(uc.into_inner(), 5); /// ``` - #[inline] + #[inline(always)] #[unstable(feature = "unsafe_cell_raw_get", issue = "66358")] pub const fn raw_get(this: *const Self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 87a3d37..dcab2cd 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs
@@ -403,16 +403,20 @@ } /// An extended version of `escape_debug` that optionally permits escaping - /// Extended Grapheme codepoints. This allows us to format characters like - /// nonspacing marks better when they're at the start of a string. + /// Extended Grapheme codepoints, single quotes, and double quotes. This + /// allows us to format characters like nonspacing marks better when they're + /// at the start of a string, and allows escaping single quotes in + /// characters, and double quotes in strings. #[inline] - pub(crate) fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug { + pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - _ if escape_grapheme_extended && self.is_grapheme_extended() => { + '\\' => EscapeDefaultState::Backslash(self), + '"' if args.escape_double_quote => EscapeDefaultState::Backslash(self), + '\'' if args.escape_single_quote => EscapeDefaultState::Backslash(self), + _ if args.escape_grapheme_extended && self.is_grapheme_extended() => { EscapeDefaultState::Unicode(self.escape_unicode()) } _ if is_printable(self) => EscapeDefaultState::Char(self), @@ -458,7 +462,7 @@ #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { - self.escape_debug_ext(true) + self.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL) } /// Returns an iterator that yields the literal escape code of a character @@ -1565,6 +1569,25 @@ } } +pub(crate) struct EscapeDebugExtArgs { + /// Escape Extended Grapheme codepoints? + pub(crate) escape_grapheme_extended: bool, + + /// Escape single quotes? + pub(crate) escape_single_quote: bool, + + /// Escape double quotes? + pub(crate) escape_double_quote: bool, +} + +impl EscapeDebugExtArgs { + pub(crate) const ESCAPE_ALL: Self = Self { + escape_grapheme_extended: true, + escape_single_quote: true, + escape_double_quote: true, + }; +} + #[inline] const fn len_utf8(code: u32) -> usize { if code < MAX_ONE_B {
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 788fafa..25a7c1d 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs
@@ -45,6 +45,8 @@ use crate::fmt::{self, Write}; use crate::iter::FusedIterator; +pub(crate) use self::methods::EscapeDebugExtArgs; + // UTF-8 ranges and tags for encoding characters const TAG_CONT: u8 = 0b1000_0000; const TAG_TWO_B: u8 = 0b1100_0000;
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5bab1fb..f8b16b6 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs
@@ -274,6 +274,7 @@ // // This should never be implemented by hand. #[doc(hidden)] + #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605 #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} @@ -282,7 +283,7 @@ /// Derive macro generating an impl of the trait `Eq`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] +#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)] pub macro Eq($item:item) { /* compiler built-in */ } @@ -334,7 +335,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_eq(), false); @@ -343,7 +343,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_eq(self) -> bool { matches!(self, Equal) } @@ -353,7 +354,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_ne(), true); @@ -362,7 +362,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ne(self) -> bool { !matches!(self, Equal) } @@ -372,7 +373,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_lt(), true); @@ -381,7 +381,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_lt(self) -> bool { matches!(self, Less) } @@ -391,7 +392,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_gt(), false); @@ -400,7 +400,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_gt(self) -> bool { matches!(self, Greater) } @@ -410,7 +411,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_le(), true); @@ -419,7 +419,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_le(self) -> bool { !matches!(self, Greater) } @@ -429,7 +430,6 @@ /// # Examples /// /// ``` - /// #![feature(ordering_helpers)] /// use std::cmp::Ordering; /// /// assert_eq!(Ordering::Less.is_ge(), false); @@ -438,7 +438,8 @@ /// ``` #[inline] #[must_use] - #[unstable(feature = "ordering_helpers", issue = "79885")] + #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] + #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ge(self) -> bool { !matches!(self, Less) } @@ -981,7 +982,11 @@ #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn le(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Less | Equal)) + // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`. + // FIXME: The root cause was fixed upstream in LLVM with: + // https://github.com/llvm/llvm-project/commit/9bad7de9a3fb844f1ca2965f35d0c2a3d1e11775 + // Revert this workaround once support for LLVM 12 gets dropped. + !matches!(self.partial_cmp(other), None | Some(Greater)) } /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. @@ -1058,8 +1063,6 @@ /// # Examples /// /// ``` -/// #![feature(cmp_min_max_by)] -/// /// use std::cmp; /// /// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1); @@ -1067,7 +1070,7 @@ /// ``` #[inline] #[must_use] -#[unstable(feature = "cmp_min_max_by", issue = "64460")] +#[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v1, @@ -1082,8 +1085,6 @@ /// # Examples /// /// ``` -/// #![feature(cmp_min_max_by)] -/// /// use std::cmp; /// /// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1); @@ -1091,7 +1092,7 @@ /// ``` #[inline] #[must_use] -#[unstable(feature = "cmp_min_max_by", issue = "64460")] +#[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) } @@ -1124,8 +1125,6 @@ /// # Examples /// /// ``` -/// #![feature(cmp_min_max_by)] -/// /// use std::cmp; /// /// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); @@ -1133,7 +1132,7 @@ /// ``` #[inline] #[must_use] -#[unstable(feature = "cmp_min_max_by", issue = "64460")] +#[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v2, @@ -1148,8 +1147,6 @@ /// # Examples /// /// ``` -/// #![feature(cmp_min_max_by)] -/// /// use std::cmp; /// /// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2); @@ -1157,7 +1154,7 @@ /// ``` #[inline] #[must_use] -#[unstable(feature = "cmp_min_max_by", issue = "64460")] +#[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) }
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 5b11361..a522b7d 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs
@@ -45,8 +45,10 @@ macro_rules! impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl From<$Small> for $Large { + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn from(small: $Small) -> Self { small as Self @@ -383,8 +385,10 @@ macro_rules! nzint_impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl From<$Small> for $Large { + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn from(small: $Small) -> Self { // SAFETY: input type guarantees the value is non-zero @@ -450,10 +454,12 @@ macro_rules! nzint_impl_try_from_int { ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => { #[$attr] - #[doc = $doc] impl TryFrom<$Int> for $NonZeroInt { type Error = TryFromIntError; + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn try_from(value: $Int) -> Result<Self, Self::Error> { Self::new(value).ok_or(TryFromIntError(())) @@ -489,10 +495,12 @@ macro_rules! nzint_impl_try_from_nzint { ($From:ty => $To:ty, $doc: expr) => { #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")] - #[doc = $doc] impl TryFrom<$From> for $To { type Error = TryFromIntError; + // Rustdocs on the impl block show a "[+] show undocumented items" toggle. + // Rustdocs on functions do not. + #[doc = $doc] #[inline] fn try_from(value: $From) -> Result<Self, Self::Error> { TryFrom::try_from(value.get()).map(|v| {
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs index 9302baa..b208ddd 100644 --- a/library/core/src/ffi.rs +++ b/library/core/src/ffi.rs
@@ -53,7 +53,7 @@ #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for c_void { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("c_void") + f.debug_struct("c_void").finish() } }
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index d95d43f..b660788 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs
@@ -165,7 +165,6 @@ /// # Examples /// /// ``` - /// # #![feature(debug_non_exhaustive)] /// use std::fmt; /// /// struct Bar { @@ -186,31 +185,22 @@ /// "Bar { bar: 10, .. }", /// ); /// ``` - #[unstable(feature = "debug_non_exhaustive", issue = "67364")] + #[stable(feature = "debug_non_exhaustive", since = "1.53.0")] pub fn finish_non_exhaustive(&mut self) -> fmt::Result { self.result = self.result.and_then(|_| { - // Draw non-exhaustive dots (`..`), and open brace if necessary (no fields). - if self.is_pretty() { - if !self.has_fields { - self.fmt.write_str(" {\n")?; - } - let mut slot = None; - let mut state = Default::default(); - let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state); - writer.write_str("..\n")?; - } else { - if self.has_fields { - self.fmt.write_str(", ..")?; + if self.has_fields { + if self.is_pretty() { + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + self.fmt.write_str("}") } else { - self.fmt.write_str(" { ..")?; + self.fmt.write_str(", .. }") } - } - if self.is_pretty() { - self.fmt.write_str("}")? } else { - self.fmt.write_str(" }")?; + self.fmt.write_str(" { .. }") } - Ok(()) }); self.result }
diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 5908da4..ece3cde 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs
@@ -54,21 +54,14 @@ } // Common code of floating point Debug and Display. -fn float_to_decimal_common<T>( - fmt: &mut Formatter<'_>, - num: &T, - negative_zero: bool, - min_precision: usize, -) -> Result +fn float_to_decimal_common<T>(fmt: &mut Formatter<'_>, num: &T, min_precision: usize) -> Result where T: flt2dec::DecodableFloat, { let force_sign = fmt.sign_plus(); - let sign = match (force_sign, negative_zero) { - (false, false) => flt2dec::Sign::Minus, - (false, true) => flt2dec::Sign::MinusRaw, - (true, false) => flt2dec::Sign::MinusPlus, - (true, true) => flt2dec::Sign::MinusPlusRaw, + let sign = match force_sign { + false => flt2dec::Sign::Minus, + true => flt2dec::Sign::MinusPlus, }; if let Some(precision) = fmt.precision { @@ -156,14 +149,14 @@ #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_decimal_common(fmt, self, true, 1) + float_to_decimal_common(fmt, self, 1) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result { - float_to_decimal_common(fmt, self, false, 0) + float_to_decimal_common(fmt, self, 0) } }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 2df5e56..87042d9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs
@@ -3,6 +3,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; +use crate::char::EscapeDebugExtArgs; +use crate::iter; use crate::marker::PhantomData; use crate::mem; use crate::num::flt2dec; @@ -1087,7 +1089,7 @@ match args.fmt { None => { // We can use default formatting parameters for all arguments. - for (arg, piece) in args.args.iter().zip(args.pieces.iter()) { + for (arg, piece) in iter::zip(args.args, args.pieces) { formatter.buf.write_str(*piece)?; (arg.formatter)(arg.value, &mut formatter)?; idx += 1; @@ -1096,7 +1098,7 @@ Some(fmt) => { // Every spec has a corresponding argument that is preceded by // a string piece. - for (arg, piece) in fmt.iter().zip(args.pieces.iter()) { + for (arg, piece) in iter::zip(fmt, args.pieces) { formatter.buf.write_str(*piece)?; // SAFETY: arg and args.args come from the same Arguments, // which guarantees the indexes are always within bounds. @@ -2054,7 +2056,11 @@ f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { - let esc = c.escape_debug(); + let esc = c.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: true, + escape_single_quote: false, + escape_double_quote: true, + }); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&self[from..i])?; @@ -2080,7 +2086,11 @@ impl Debug for char { fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_char('\'')?; - for c in self.escape_debug() { + for c in self.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: true, + escape_single_quote: true, + escape_double_quote: false, + }) { f.write_char(c)? } f.write_char('\'') @@ -2210,7 +2220,7 @@ #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Debug for PhantomData<T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - f.pad("PhantomData") + f.debug_struct("PhantomData").finish() } } @@ -2258,9 +2268,9 @@ } #[stable(feature = "core_impl_debug", since = "1.9.0")] -impl<T: ?Sized + Debug> Debug for UnsafeCell<T> { +impl<T: ?Sized> Debug for UnsafeCell<T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - f.pad("UnsafeCell") + f.debug_struct("UnsafeCell").finish_non_exhaustive() } }
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index e9a99dd..cc4cf54 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs
@@ -24,7 +24,8 @@ /// `.await` the value. /// /// [`Waker`]: crate::task::Waker -#[doc(spotlight)] +#[cfg_attr(bootstrap, doc(spotlight))] +#[cfg_attr(not(bootstrap), doc(notable_trait))] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"]
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 7bfa58d..77d3a35 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs
@@ -175,6 +175,21 @@ /// Feeds a slice of this type into the given [`Hasher`]. /// + /// This method is meant as a convenience, but its implementation is + /// also explicitly left unspecified. It isn't guaranteed to be + /// equivalent to repeated calls of [`hash`] and implementations of + /// [`Hash`] should keep that in mind and call [`hash`] themselves + /// if the slice isn't treated as a whole unit in the [`PartialEq`] + /// implementation. + /// + /// For example, a [`VecDeque`] implementation might naïvely call + /// [`as_slices`] and then [`hash_slice`] on each slice, but this + /// is wrong since the two slices can change with a call to + /// [`make_contiguous`] without affecting the [`PartialEq`] + /// result. Since these slices aren't treated as singular + /// units, and instead part of a larger deque, this method cannot + /// be used. + /// /// # Examples /// /// ``` @@ -186,6 +201,12 @@ /// Hash::hash_slice(&numbers, &mut hasher); /// println!("Hash is {:x}!", hasher.finish()); /// ``` + /// + /// [`VecDeque`]: ../../std/collections/struct.VecDeque.html + /// [`as_slices`]: ../../std/collections/struct.VecDeque.html#method.as_slices + /// [`make_contiguous`]: ../../std/collections/struct.VecDeque.html#method.make_contiguous + /// [`hash`]: Hash::hash + /// [`hash_slice`]: Hash::hash_slice #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where @@ -221,6 +242,11 @@ /// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher` /// instances are used in conjunction with the [`Hash`] trait. /// +/// This trait makes no assumptions about how the various `write_*` methods are +/// defined and implementations of [`Hash`] should not assume that they work one +/// way or another. You cannot assume, for example, that a [`write_u32`] call is +/// equivalent to four calls of [`write_u8`]. +/// /// # Examples /// /// ``` @@ -240,6 +266,7 @@ /// [`finish`]: Hasher::finish /// [`write`]: Hasher::write /// [`write_u8`]: Hasher::write_u8 +/// [`write_u32`]: Hasher::write_u32 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Returns the hash value for the values written so far. @@ -507,7 +534,7 @@ #[stable(since = "1.9.0", feature = "core_impl_debug")] impl<H> fmt::Debug for BuildHasherDefault<H> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("BuildHasherDefault") + f.debug_struct("BuildHasherDefault").finish() } } @@ -691,29 +718,9 @@ impl<T: ?Sized> Hash for *const T { #[inline] fn hash<H: Hasher>(&self, state: &mut H) { - #[cfg(not(bootstrap))] - { - let (address, metadata) = self.to_raw_parts(); - state.write_usize(address as usize); - metadata.hash(state); - } - #[cfg(bootstrap)] - { - if mem::size_of::<Self>() == mem::size_of::<usize>() { - // Thin pointer - state.write_usize(*self as *const () as usize); - } else { - // Fat pointer - // SAFETY: we are accessing the memory occupied by `self` - // which is guaranteed to be valid. - // This assumes a fat pointer can be represented by a `(usize, usize)`, - // which is safe to do in `std` because it is shipped and kept in sync - // with the implementation of fat pointers in `rustc`. - let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) }; - state.write_usize(a); - state.write_usize(b); - } - } + let (address, metadata) = self.to_raw_parts(); + state.write_usize(address as usize); + metadata.hash(state); } } @@ -721,29 +728,9 @@ impl<T: ?Sized> Hash for *mut T { #[inline] fn hash<H: Hasher>(&self, state: &mut H) { - #[cfg(not(bootstrap))] - { - let (address, metadata) = self.to_raw_parts(); - state.write_usize(address as usize); - metadata.hash(state); - } - #[cfg(bootstrap)] - { - if mem::size_of::<Self>() == mem::size_of::<usize>() { - // Thin pointer - state.write_usize(*self as *const () as usize); - } else { - // Fat pointer - // SAFETY: we are accessing the memory occupied by `self` - // which is guaranteed to be valid. - // This assumes a fat pointer can be represented by a `(usize, usize)`, - // which is safe to do in `std` because it is shipped and kept in sync - // with the implementation of fat pointers in `rustc`. - let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) }; - state.write_usize(a); - state.write_usize(b); - } - } + let (address, metadata) = self.to_raw_parts(); + state.write_usize(address as usize); + metadata.hash(state); } } }
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 3137295..f7aec73 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs
@@ -154,7 +154,7 @@ /// [`std::convert::identity`]: crate::convert::identity #[cfg_attr(not(miri), inline)] #[cfg_attr(miri, inline(never))] -#[unstable(feature = "test", issue = "50297")] +#[unstable(feature = "bench_black_box", issue = "64102")] #[cfg_attr(miri, allow(unused_mut))] pub fn black_box<T>(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 073210c..175fc2e 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs
@@ -1543,7 +1543,7 @@ /// let num_trailing = unsafe { cttz_nonzero(x) }; /// assert_eq!(num_trailing, 3); /// ``` - #[rustc_const_unstable(feature = "const_cttz", issue = "none")] + #[rustc_const_stable(feature = "const_cttz", since = "1.53.0")] pub fn cttz_nonzero<T: Copy>(x: T) -> T; /// Reverses the bytes in an integer type `T`. @@ -1843,7 +1843,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); } // FIXME: Perform these checks only at run time
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 41a7b13..61d8351 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs
@@ -51,6 +51,9 @@ #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::zip::TrustedRandomAccess; +#[unstable(feature = "iter_zip", issue = "83574")] +pub use self::zip::zip; + /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that /// * the iterator source `S` itself implements `SourceIter<Source = S>` @@ -191,3 +194,26 @@ self.try_fold(init, ok(fold)).unwrap() } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<S: Iterator, I, E> SourceIter for ResultShunt<'_, I, E> +where + I: SourceIter<Source = S>, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to +// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that +// at least one item will be moved out from the underlying source. +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I, T, E> InPlaceIterable for ResultShunt<'_, I, E> where + I: Iterator<Item = Result<T, E>> + InPlaceIterable +{ +}
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 4330144..0d860ae 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs
@@ -1,4 +1,4 @@ -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::iter::{adapters::SourceIter, FusedIterator, TrustedLen}; use crate::ops::Try; /// An iterator with a `peek()` that returns an optional reference to the next @@ -233,7 +233,6 @@ /// Basic usage: /// /// ``` - /// #![feature(peekable_peek_mut)] /// let mut iter = [1, 2, 3].iter().peekable(); /// /// // Like with `peek()`, we can see into the future without advancing the iterator. @@ -251,7 +250,7 @@ /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]); /// ``` #[inline] - #[unstable(feature = "peekable_peek_mut", issue = "78302")] + #[stable(feature = "peekable_peek_mut", since = "1.53.0")] pub fn peek_mut(&mut self) -> Option<&mut I::Item> { let iter = &mut self.iter; self.peeked.get_or_insert_with(|| iter.next()).as_mut() @@ -334,6 +333,3 @@ unsafe { SourceIter::as_inner(&mut self.iter) } } } - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index ea7a809..2f8f504 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs
@@ -5,8 +5,8 @@ /// An iterator that iterates two other iterators simultaneously. /// -/// This `struct` is created by [`Iterator::zip`]. See its documentation -/// for more. +/// This `struct` is created by [`zip`] or [`Iterator::zip`]. +/// See their documentation for more. #[derive(Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -33,6 +33,37 @@ } } +/// Converts the arguments to iterators and zips them. +/// +/// See the documentation of [`Iterator::zip`] for more. +/// +/// # Examples +/// +/// ``` +/// #![feature(iter_zip)] +/// use std::iter::zip; +/// +/// let xs = [1, 2, 3]; +/// let ys = [4, 5, 6]; +/// for (x, y) in zip(&xs, &ys) { +/// println!("x:{}, y:{}", x, y); +/// } +/// +/// // Nested zips are also possible: +/// let zs = [7, 8, 9]; +/// for ((x, y), z) in zip(zip(&xs, &ys), &zs) { +/// println!("x:{}, y:{}, z:{}", x, y, z); +/// } +/// ``` +#[unstable(feature = "iter_zip", issue = "83574")] +pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter> +where + A: IntoIterator, + B: IntoIterator, +{ + ZipImpl::new(a.into_iter(), b.into_iter()) +} + #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> Iterator for Zip<A, B> where
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index c57ba2b..2a179f0 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs
@@ -389,6 +389,8 @@ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, }; +#[unstable(feature = "iter_zip", issue = "83574")] +pub use self::adapters::zip; #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::adapters::Cloned; #[stable(feature = "iter_copied", since = "1.36.0")]
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index cc80e06..4b293c5 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs
@@ -3,7 +3,7 @@ use crate::mem; use crate::ops::{self, Try}; -use super::{FusedIterator, TrustedLen}; +use super::{FusedIterator, TrustedLen, TrustedRandomAccess}; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -493,6 +493,18 @@ )*) } +/// Safety: This macro must only be used on types that are `Copy` and result in ranges +/// which have an exact `size_hint()` where the upper bound must not be `None`. +macro_rules! unsafe_range_trusted_random_access_impl { + ($($t:ty)*) => ($( + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe impl TrustedRandomAccess for ops::Range<$t> { + const MAY_HAVE_SIDE_EFFECT: bool = false; + } + )*) +} + macro_rules! range_incl_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -553,6 +565,18 @@ fn max(mut self) -> Option<A> { self.next_back() } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + // Additionally Self: TrustedRandomAccess is only implemented for Copy types + // which means even repeated reads of the same index would be safe. + unsafe { Step::forward_unchecked(self.start.clone(), idx) } + } } // These macros generate `ExactSizeIterator` impls for various range types. @@ -574,6 +598,23 @@ u32 i32 } + +unsafe_range_trusted_random_access_impl! { + usize u8 u16 + isize i8 i16 +} + +#[cfg(target_pointer_width = "32")] +unsafe_range_trusted_random_access_impl! { + u32 i32 +} + +#[cfg(target_pointer_width = "64")] +unsafe_range_trusted_random_access_impl! { + u32 i32 + u64 i64 +} + range_incl_exact_iter_impl! { u8 i8
diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs index 5d4a9fe..919c564 100644 --- a/library/core/src/iter/sources/empty.rs +++ b/library/core/src/iter/sources/empty.rs
@@ -36,7 +36,7 @@ #[stable(feature = "core_impl_debug", since = "1.9.0")] impl<T> fmt::Debug for Empty<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Empty") + f.debug_struct("Empty").finish() } }
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 1ae6d15..13a2e24 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs
@@ -198,6 +198,7 @@ /// } /// ``` #[rustc_diagnostic_item = "IntoIterator"] +#[cfg_attr(not(bootstrap), rustc_skip_array_during_method_dispatch)] #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated over.
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index a07750f..da9e5fd 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs
@@ -81,8 +81,8 @@ ), on( _Self = "[]", - label = "borrow the array with `&` or call `.iter()` on it to iterate over it", - note = "arrays are not iterators, but slices like the following are: `&[1, 2, 3]`" + label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`", + note = "see <https://github.com/rust-lang/rust/pull/65819> for more details" ), on( _Self = "{integral}", @@ -92,7 +92,8 @@ label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] -#[doc(spotlight)] +#[cfg_attr(bootstrap, doc(spotlight))] +#[cfg_attr(not(bootstrap), doc(notable_trait))] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { @@ -936,20 +937,16 @@ Enumerate::new(self) } - /// Creates an iterator which can use [`peek`] to look at the next element of - /// the iterator without consuming it. + /// Creates an iterator which can use the [`peek`] and [`peek_mut`] methods + /// to look at the next element of the iterator without consuming it. See + /// their documentation for more information. /// - /// Adds a [`peek`] method to an iterator. See its documentation for - /// more information. + /// Note that the underlying iterator is still advanced when [`peek`] or + /// [`peek_mut`] are called for the first time: In order to retrieve the + /// next element, [`next`] is called on the underlying iterator, hence any + /// side effects (i.e. anything other than fetching the next value) of + /// the [`next`] method will occur. /// - /// Note that the underlying iterator is still advanced when [`peek`] is - /// called for the first time: In order to retrieve the next element, - /// [`next`] is called on the underlying iterator, hence any side effects (i.e. - /// anything other than fetching the next value) of the [`next`] method - /// will occur. - /// - /// [`peek`]: Peekable::peek - /// [`next`]: Iterator::next /// /// # Examples /// @@ -976,6 +973,32 @@ /// assert_eq!(iter.peek(), None); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Using [`peek_mut`] to mutate the next item without advancing the + /// iterator: + /// + /// ``` + /// let xs = [1, 2, 3]; + /// + /// let mut iter = xs.iter().peekable(); + /// + /// // `peek_mut()` lets us see into the future + /// assert_eq!(iter.peek_mut(), Some(&mut &1)); + /// assert_eq!(iter.peek_mut(), Some(&mut &1)); + /// assert_eq!(iter.next(), Some(&1)); + /// + /// if let Some(mut p) = iter.peek_mut() { + /// assert_eq!(*p, &2); + /// // put a value into the iterator + /// *p = &1000; + /// } + /// + /// // The value reappears as the iterator continues + /// assert_eq!(iter.collect::<Vec<_>>(), vec![&1000, &3]); + /// ``` + /// [`peek`]: Peekable::peek + /// [`peek_mut`]: Peekable::peek_mut + /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn peekable(self) -> Peekable<Self> @@ -1228,7 +1251,11 @@ /// Creates an iterator that skips the first `n` elements. /// - /// After they have been consumed, the rest of the elements are yielded. + /// `skip(n)` skips elements until `n` elements are skipped or the end of the + /// iterator is reached (whichever happens first). After that, all the remaining + /// elements are yielded. In particular, if the original iterator is too short, + /// then the returned iterator is empty. + /// /// Rather than overriding this method directly, instead override the `nth` method. /// /// # Examples @@ -1252,7 +1279,14 @@ Skip::new(self, n) } - /// Creates an iterator that yields its first `n` elements. + /// Creates an iterator that yields the first `n` elements, or fewer + /// if the underlying iterator ends sooner. + /// + /// `take(n)` yields elements until `n` elements are yielded or the end of + /// the iterator is reached (whichever happens first). + /// The returned iterator is a prefix of length `n` if the original iterator + /// contains at least `n` elements, otherwise it contains all of the + /// (fewer than `n`) elements of the original iterator. /// /// # Examples /// @@ -1461,7 +1495,12 @@ /// [`Some(T)`] again. `fuse()` adapts an iterator, ensuring that after a /// [`None`] is given, it will always return [`None`] forever. /// + /// Note that the [`Fuse`] wrapper is a no-op on iterators that implement + /// the [`FusedIterator`] trait. `fuse()` may therefore behave incorrectly + /// if the [`FusedIterator`] trait is improperly implemented. + /// /// [`Some(T)`]: Some + /// [`FusedIterator`]: crate::iter::FusedIterator /// /// # Examples /// @@ -1612,31 +1651,16 @@ /// Basic usage: /// /// ``` - /// let a = [1, 2, 3]; + /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter(); /// - /// let iter = a.iter(); + /// // Take the first two words. + /// let hello_world: Vec<_> = words.by_ref().take(2).collect(); + /// assert_eq!(hello_world, vec!["hello", "world"]); /// - /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i); - /// - /// assert_eq!(sum, 6); - /// - /// // if we try to use iter again, it won't work. The following line - /// // gives "error: use of moved value: `iter` - /// // assert_eq!(iter.next(), None); - /// - /// // let's try that again - /// let a = [1, 2, 3]; - /// - /// let mut iter = a.iter(); - /// - /// // instead, we add in a .by_ref() - /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i); - /// - /// assert_eq!(sum, 3); - /// - /// // now this is just fine: - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), None); + /// // Collect the rest of the words. + /// // We can only do this because we used `by_ref` earlier. + /// let of_rust: Vec<_> = words.collect(); + /// assert_eq!(of_rust, vec!["of", "Rust"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self @@ -2109,7 +2133,6 @@ /// ``` /// /// [`reduce()`]: Iterator::reduce - #[doc(alias = "reduce")] #[doc(alias = "inject")] #[inline] #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8e35adc..d1329b8 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs
@@ -79,14 +79,14 @@ #![feature(const_int_unchecked_arith)] #![feature(const_mut_refs)] #![feature(const_refs_to_cell)] -#![feature(const_cttz)] #![feature(const_panic)] #![feature(const_pin)] -#![feature(const_fn)] +#![cfg_attr(bootstrap, feature(const_fn))] #![feature(const_fn_union)] #![feature(const_impl_trait)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] +#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))] #![feature(const_option)] #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] @@ -109,9 +109,9 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] -#![feature(doc_spotlight)] +#![cfg_attr(bootstrap, feature(doc_spotlight))] +#![cfg_attr(not(bootstrap), feature(doc_notable_trait))] #![feature(duration_consts_2)] -#![feature(duration_saturating_ops)] #![feature(extended_key_value_attributes)] #![feature(extern_types)] #![feature(fundamental)] @@ -126,9 +126,9 @@ #![feature(exhaustive_patterns)] #![feature(no_core)] #![feature(auto_traits)] -#![feature(or_patterns)] +#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(prelude_import)] -#![cfg_attr(not(bootstrap), feature(ptr_metadata))] +#![feature(ptr_metadata)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] @@ -138,6 +138,7 @@ #![feature(stmt_expr_attributes)] #![feature(str_split_as_str)] #![feature(str_split_inclusive_as_str)] +#![feature(char_indices_offset)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] @@ -165,8 +166,8 @@ #![feature(const_caller_location)] #![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 +#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605 #![feature(int_error_matching)] -#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))] #![deny(unsafe_op_in_unsafe_fn)] #[prelude_import] @@ -298,8 +299,8 @@ unused_imports, unsafe_op_in_unsafe_fn )] -#[cfg_attr(bootstrap, allow(non_autolinks))] -#[cfg_attr(not(bootstrap), allow(rustdoc::non_autolinks))] +#[cfg_attr(bootstrap, allow(rustdoc::non_autolinks))] +#[cfg_attr(not(bootstrap), allow(rustdoc::bare_urls))] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[allow(clashing_extern_declarations)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a0a8eec..66efa3c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs
@@ -1301,7 +1301,6 @@ } /// Attribute macro used to apply derive macros. - #[cfg(not(bootstrap))] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] pub macro derive($item:item) { @@ -1363,7 +1362,6 @@ } /// Expands all `#[cfg]` and `#[cfg_attr]` attributes in the code fragment it's applied to. - #[cfg(not(bootstrap))] #[unstable( feature = "cfg_eval", issue = "82679",
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 85e0e72..fb95734 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs
@@ -765,7 +765,7 @@ /// [`pin` module]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( - on(_Self = "std::future::Future", note = "consider using `Box::pin`",), + note = "consider using `Box::pin`", message = "`{Self}` cannot be unpinned" )] #[lang = "unpin"]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index cb07293..4d7d475 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs
@@ -190,6 +190,8 @@ /// let ptr = uninit.as_mut_ptr(); /// /// // Initializing the `name` field +/// // Using `write` instead of assignment via `=` to not call `drop` on the +/// // old, uninitialized value. /// unsafe { addr_of_mut!((*ptr).name).write("Bob".to_string()); } /// /// // Initializing the `list` field @@ -319,9 +321,9 @@ /// Create a new array of `MaybeUninit<T>` items, in an uninitialized state. /// /// Note: in a future Rust version this method may become unnecessary - /// when array literal syntax allows - /// [repeating const expressions](https://github.com/rust-lang/rust/issues/49147). - /// The example below could then use `let mut buf = [MaybeUninit::<u8>::uninit(); 32];`. + /// when Rust allows + /// [inline const expressions](https://github.com/rust-lang/rust/issues/76001). + /// The example below could then use `let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];`. /// /// # Examples /// @@ -734,22 +736,22 @@ /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// - /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] } + /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] } /// # #[cfg(FALSE)] /// extern "C" { /// /// Initializes *all* the bytes of the input buffer. - /// fn initialize_buffer(buf: *mut [u8; 2048]); + /// fn initialize_buffer(buf: *mut [u8; 1024]); /// } /// - /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit(); + /// let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); /// /// // Initialize `buf`: /// unsafe { initialize_buffer(buf.as_mut_ptr()); } /// // Now we know that `buf` has been initialized, so we could `.assume_init()` it. - /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes. + /// // However, using `.assume_init()` may trigger a `memcpy` of the 1024 bytes. /// // To assert our buffer has been initialized without copying it, we upgrade - /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: - /// let buf: &mut [u8; 2048] = unsafe { + /// // the `&mut MaybeUninit<[u8; 1024]>` to a `&mut [u8; 1024]`: + /// let buf: &mut [u8; 1024] = unsafe { /// // SAFETY: `buf` has been initialized. /// buf.assume_init_mut() /// };
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index c4f0d91..c6750c5 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs
@@ -297,7 +297,7 @@ #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] -#[rustc_const_stable(feature = "const_size_of", since = "1.32.0")] +#[rustc_const_stable(feature = "const_size_of", since = "1.24.0")] pub const fn size_of<T>() -> usize { intrinsics::size_of::<T>() } @@ -440,7 +440,7 @@ #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] -#[rustc_const_stable(feature = "const_align_of", since = "1.32.0")] +#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")] pub const fn align_of<T>() -> usize { intrinsics::min_align_of::<T>() } @@ -884,7 +884,6 @@ /// ``` /// /// [`RefCell`]: crate::cell::RefCell -#[doc(alias = "delete")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop<T>(_x: T) {}
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 6a1a1e1..197b85f 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs
@@ -181,11 +181,12 @@ /// Adds `other` to itself and returns its own mutable reference. pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name { use crate::cmp; + use crate::iter; use crate::num::bignum::FullOps; let mut sz = cmp::max(self.size, other.size); let mut carry = false; - for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) { + for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) { let (c, v) = (*a).full_add(*b, carry); *a = v; carry = c; @@ -219,11 +220,12 @@ /// Subtracts `other` from itself and returns its own mutable reference. pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name { use crate::cmp; + use crate::iter; use crate::num::bignum::FullOps; let sz = cmp::max(self.size, other.size); let mut noborrow = true; - for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) { + for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) { let (c, v) = (*a).full_add(!*b, noborrow); *a = v; noborrow = c;
diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs index a5fbdc6..313b687 100644 --- a/library/core/src/num/dec2flt/algorithm.rs +++ b/library/core/src/num/dec2flt/algorithm.rs
@@ -62,10 +62,9 @@ // any `u16` unsafe { asm!( - "fldcw ({})", + "fldcw word ptr [{}]", in(reg) &cw, - // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. - options(att_syntax, nostack), + options(nostack), ) } } @@ -87,10 +86,9 @@ // any `u16` unsafe { asm!( - "fnstcw ({})", + "fnstcw word ptr [{}]", in(reg) &mut cw, - // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. - options(att_syntax, nostack), + options(nostack), ) }
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 20ac165..f008a64 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs
@@ -239,13 +239,15 @@ ParseResult::Valid(decimal) => convert(decimal)?, ParseResult::ShortcutToInf => T::INFINITY, ParseResult::ShortcutToZero => T::ZERO, - ParseResult::Invalid => match s { - "inf" => T::INFINITY, - "NaN" => T::NAN, - _ => { + ParseResult::Invalid => { + if s.eq_ignore_ascii_case("nan") { + T::NAN + } else if s.eq_ignore_ascii_case("inf") || s.eq_ignore_ascii_case("infinity") { + T::INFINITY + } else { return Err(pfe_invalid()); } - }, + } }; match sign {
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 690247b..0d6d919 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs
@@ -500,7 +500,6 @@ /// Returns `true` if the number is [subnormal]. /// /// ``` - /// #![feature(is_subnormal)] /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 /// let max = f32::MAX; /// let lower_than_min = 1.0e-40_f32; @@ -516,7 +515,7 @@ /// assert!(lower_than_min.is_subnormal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[unstable(feature = "is_subnormal", issue = "79288")] + #[stable(feature = "is_subnormal", since = "1.53.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] pub const fn is_subnormal(self) -> bool {
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 6d37372..42214e7 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs
@@ -499,7 +499,6 @@ /// Returns `true` if the number is [subnormal]. /// /// ``` - /// #![feature(is_subnormal)] /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64 /// let max = f64::MAX; /// let lower_than_min = 1.0e-308_f64; @@ -515,7 +514,7 @@ /// assert!(lower_than_min.is_subnormal()); /// ``` /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[unstable(feature = "is_subnormal", issue = "79288")] + #[stable(feature = "is_subnormal", since = "1.53.0")] #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] #[inline] pub const fn is_subnormal(self) -> bool {
diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index e8f9d65..93bdf50 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs
@@ -399,14 +399,10 @@ /// Sign formatting options. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Sign { - /// Prints `-` only for the negative non-zero values. - Minus, // -inf -1 0 0 1 inf nan - /// Prints `-` only for any negative values (including the negative zero). - MinusRaw, // -inf -1 -0 0 1 inf nan - /// Prints `-` for the negative non-zero values, or `+` otherwise. - MinusPlus, // -inf -1 +0 +0 +1 +inf nan - /// Prints `-` for any negative values (including the negative zero), or `+` otherwise. - MinusPlusRaw, // -inf -1 -0 +0 +1 +inf nan + /// Prints `-` for any negative value. + Minus, // -inf -1 -0 0 1 inf nan + /// Prints `-` for any negative value, or `+` otherwise. + MinusPlus, // -inf -1 -0 +0 +1 +inf nan } /// Returns the static byte string corresponding to the sign to be formatted. @@ -414,30 +410,14 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static str { match (*decoded, sign) { (FullDecoded::Nan, _) => "", - (FullDecoded::Zero, Sign::Minus) => "", - (FullDecoded::Zero, Sign::MinusRaw) => { + (_, Sign::Minus) => { if negative { "-" } else { "" } } - (FullDecoded::Zero, Sign::MinusPlus) => "+", - (FullDecoded::Zero, Sign::MinusPlusRaw) => { - if negative { - "-" - } else { - "+" - } - } - (_, Sign::Minus | Sign::MinusRaw) => { - if negative { - "-" - } else { - "" - } - } - (_, Sign::MinusPlus | Sign::MinusPlusRaw) => { + (_, Sign::MinusPlus) => { if negative { "-" } else {
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index ce9dca3..4b34113 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs
@@ -32,10 +32,9 @@ /// # Examples /// /// ``` - /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[unstable(feature = "int_bits_const", issue = "76904")] + #[stable(feature = "int_bits_const", since = "1.53.0")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. @@ -80,7 +79,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] - #[inline] + #[inline(always)] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } /// Returns the number of zeros in the binary representation of `self`. @@ -94,7 +93,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn count_zeros(self) -> u32 { (!self).count_ones() } @@ -112,7 +111,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() } @@ -130,7 +129,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() } @@ -148,7 +147,7 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] + #[inline(always)] pub const fn leading_ones(self) -> u32 { (self as $UnsignedT).leading_ones() } @@ -166,7 +165,7 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] + #[inline(always)] pub const fn trailing_ones(self) -> u32 { (self as $UnsignedT).trailing_ones() } @@ -190,7 +189,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn rotate_left(self, n: u32) -> Self { (self as $UnsignedT).rotate_left(n) as Self } @@ -215,7 +214,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn rotate_right(self, n: u32) -> Self { (self as $UnsignedT).rotate_right(n) as Self } @@ -235,7 +234,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } @@ -255,8 +254,8 @@ #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")] /// ``` #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[rustc_const_stable(feature = "const_int_methods", since = "1.37.0")] + #[inline(always)] #[must_use] pub const fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self @@ -417,7 +416,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_add(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_add`. @@ -455,7 +454,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_sub`. @@ -493,7 +492,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_mul`. @@ -742,7 +741,7 @@ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn saturating_add(self, rhs: Self) -> Self { intrinsics::saturating_add(self, rhs) } @@ -763,7 +762,7 @@ #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn saturating_sub(self, rhs: Self) -> Self { intrinsics::saturating_sub(self, rhs) } @@ -784,7 +783,7 @@ #[stable(feature = "saturating_neg", since = "1.45.0")] #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] + #[inline(always)] pub const fn saturating_neg(self) -> Self { intrinsics::saturating_sub(0, self) } @@ -884,7 +883,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_add(self, rhs: Self) -> Self { intrinsics::wrapping_add(self, rhs) } @@ -904,7 +903,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_sub(self, rhs: Self) -> Self { intrinsics::wrapping_sub(self, rhs) } @@ -924,7 +923,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_mul(self, rhs: Self) -> Self { intrinsics::wrapping_mul(self, rhs) } @@ -1082,7 +1081,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_shl(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -1111,7 +1110,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_shr(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -1226,7 +1225,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1250,7 +1249,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1273,7 +1272,7 @@ #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1589,11 +1588,11 @@ /// Calculates the quotient of Euclidean division of `self` by `rhs`. /// - /// This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, - /// with `0 <= self.rem_euclid(rhs) < rhs`. + /// This computes the integer `q` such that `self = q * rhs + r`, with + /// `r = self.rem_euclid(rhs)` and `0 <= r < abs(rhs)`. /// - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. + /// In other words, the result is `self / rhs` rounded to the integer `q` + /// such that `self >= q * rhs`. /// If `self > 0`, this is equal to round towards zero (the default in Rust); /// if `self < 0`, this is equal to round towards +/- infinity. /// @@ -1726,7 +1725,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] - #[inline] + #[inline(always)] pub const fn signum(self) -> Self { match self { n if n > 0 => 1, @@ -1748,7 +1747,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn is_positive(self) -> bool { self > 0 } /// Returns `true` if `self` is negative and `false` if the number is zero or @@ -1764,7 +1763,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn is_negative(self) -> bool { self < 0 } /// Return the memory representation of this integer as a byte array in
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f0bd976..6032dc9 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs
@@ -2,6 +2,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::ascii; use crate::intrinsics; use crate::mem; use crate::str::FromStr; @@ -661,6 +662,31 @@ pub const fn is_ascii_control(&self) -> bool { matches!(*self, b'\0'..=b'\x1F' | b'\x7F') } + + /// Returns an iterator that produces an escaped version of a `u8`, + /// treating it as an ASCII character. + /// + /// The behavior is identical to [`ascii::escape_default`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(inherent_ascii_escape)] + /// + /// assert_eq!("0", b'0'.escape_ascii().to_string()); + /// assert_eq!("\\t", b'\t'.escape_ascii().to_string()); + /// assert_eq!("\\r", b'\r'.escape_ascii().to_string()); + /// assert_eq!("\\n", b'\n'.escape_ascii().to_string()); + /// assert_eq!("\\'", b'\''.escape_ascii().to_string()); + /// assert_eq!("\\\"", b'"'.escape_ascii().to_string()); + /// assert_eq!("\\\\", b'\\'.escape_ascii().to_string()); + /// assert_eq!("\\x9d", b'\x9d'.escape_ascii().to_string()); + /// ``` + #[unstable(feature = "inherent_ascii_escape", issue = "77174")] + #[inline] + pub fn escape_ascii(&self) -> ascii::EscapeDefault { + ascii::escape_default(*self) + } } #[lang = "u16"]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 111feb7..6b9b435 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs
@@ -23,7 +23,7 @@ } macro_rules! nonzero_integers { - ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { + ( $( #[$stability: meta] #[$const_new_unchecked_stability: meta] $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -48,7 +48,7 @@ /// /// The value must not be zero. #[$stability] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + #[$const_new_unchecked_stability] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. @@ -146,18 +146,18 @@ } nonzero_integers! { - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); } macro_rules! from_str_radix_nzint_impl { @@ -191,13 +191,12 @@ /// Basic usage: /// /// ``` - /// #![feature(nonzero_leading_trailing_zeros)] #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", stringify!($LeadingTestExpr), ").unwrap();")] /// /// assert_eq!(n.leading_zeros(), 0); /// ``` - #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] - #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[inline] pub const fn leading_zeros(self) -> u32 { // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero @@ -214,13 +213,12 @@ /// Basic usage: /// /// ``` - /// #![feature(nonzero_leading_trailing_zeros)] #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")] /// /// assert_eq!(n.trailing_zeros(), 3); /// ``` - #[unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] - #[rustc_const_unstable(feature = "nonzero_leading_trailing_zeros", issue = "79143")] + #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] + #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[inline] pub const fn trailing_zeros(self) -> u32 { // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 7393e7f..08d9161 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs
@@ -32,10 +32,9 @@ /// # Examples /// /// ``` - /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[unstable(feature = "int_bits_const", issue = "76904")] + #[stable(feature = "int_bits_const", since = "1.53.0")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. @@ -80,7 +79,7 @@ #[rustc_const_stable(feature = "const_math", since = "1.32.0")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] - #[inline] + #[inline(always)] pub const fn count_ones(self) -> u32 { intrinsics::ctpop(self as $ActualT) as u32 } @@ -96,7 +95,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn count_zeros(self) -> u32 { (!self).count_ones() } @@ -114,7 +113,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn leading_zeros(self) -> u32 { intrinsics::ctlz(self as $ActualT) as u32 } @@ -133,7 +132,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn trailing_zeros(self) -> u32 { intrinsics::cttz(self) as u32 } @@ -151,7 +150,7 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] + #[inline(always)] pub const fn leading_ones(self) -> u32 { (!self).leading_zeros() } @@ -170,7 +169,7 @@ /// ``` #[stable(feature = "leading_trailing_ones", since = "1.46.0")] #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] + #[inline(always)] pub const fn trailing_ones(self) -> u32 { (!self).trailing_zeros() } @@ -194,7 +193,7 @@ #[rustc_const_stable(feature = "const_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn rotate_left(self, n: u32) -> Self { intrinsics::rotate_left(self, n as $SelfT) } @@ -219,7 +218,7 @@ #[rustc_const_stable(feature = "const_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn rotate_right(self, n: u32) -> Self { intrinsics::rotate_right(self, n as $SelfT) } @@ -238,7 +237,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn swap_bytes(self) -> Self { intrinsics::bswap(self as $ActualT) as Self } @@ -258,8 +257,8 @@ #[doc = concat!("assert_eq!(0, 0", stringify!($SelfT), ".reverse_bits());")] /// ``` #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[rustc_const_stable(feature = "const_math", since = "1.37.0")] + #[inline(always)] #[must_use] pub const fn reverse_bits(self) -> Self { intrinsics::bitreverse(self as $ActualT) as Self @@ -285,7 +284,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] { @@ -317,7 +316,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] { @@ -349,7 +348,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] { @@ -381,7 +380,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] { @@ -427,7 +426,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_add(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_add`. @@ -465,7 +464,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_sub`. @@ -503,7 +502,7 @@ )] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { // SAFETY: the caller must uphold the safety contract for // `unchecked_mul`. @@ -728,7 +727,7 @@ #[must_use = "this returns the result of the operation, \ without modifying the original"] #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] + #[inline(always)] pub const fn saturating_add(self, rhs: Self) -> Self { intrinsics::saturating_add(self, rhs) } @@ -748,7 +747,7 @@ #[must_use = "this returns the result of the operation, \ without modifying the original"] #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] + #[inline(always)] pub const fn saturating_sub(self, rhs: Self) -> Self { intrinsics::saturating_sub(self, rhs) } @@ -814,7 +813,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_add(self, rhs: Self) -> Self { intrinsics::wrapping_add(self, rhs) } @@ -834,7 +833,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_sub(self, rhs: Self) -> Self { intrinsics::wrapping_sub(self, rhs) } @@ -857,7 +856,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_mul(self, rhs: Self) -> Self { intrinsics::wrapping_mul(self, rhs) } @@ -879,7 +878,7 @@ #[rustc_const_stable(feature = "const_wrapping_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_div(self, rhs: Self) -> Self { self / rhs } @@ -904,7 +903,7 @@ #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { self / rhs } @@ -927,7 +926,7 @@ #[rustc_const_stable(feature = "const_wrapping_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_rem(self, rhs: Self) -> Self { self % rhs } @@ -953,7 +952,7 @@ #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { self % rhs } @@ -1009,7 +1008,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_shl(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -1041,7 +1040,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn wrapping_shr(self, rhs: u32) -> Self { // SAFETY: the masking by the bitsize of the type ensures that we do not shift // out of bounds @@ -1107,7 +1106,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1132,7 +1131,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1159,7 +1158,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) @@ -1183,7 +1182,7 @@ /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")] /// ``` - #[inline] + #[inline(always)] #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_overflowing_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ @@ -1213,7 +1212,7 @@ /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")] /// ``` - #[inline] + #[inline(always)] #[stable(feature = "euclidean_division", since = "1.38.0")] #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ @@ -1240,7 +1239,7 @@ /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")] /// ``` - #[inline] + #[inline(always)] #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_overflowing_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ @@ -1270,7 +1269,7 @@ /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")] /// ``` - #[inline] + #[inline(always)] #[stable(feature = "euclidean_division", since = "1.38.0")] #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ @@ -1294,7 +1293,7 @@ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true));")] /// ``` - #[inline] + #[inline(always)] #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] pub const fn overflowing_neg(self) -> (Self, bool) { @@ -1321,7 +1320,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) } @@ -1346,7 +1345,7 @@ #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) } @@ -1459,7 +1458,7 @@ #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] #[rustc_inherit_overflow_checks] pub const fn div_euclid(self, rhs: Self) -> Self { self / rhs @@ -1487,7 +1486,7 @@ #[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[inline(always)] #[rustc_inherit_overflow_checks] pub const fn rem_euclid(self, rhs: Self) -> Self { self % rhs @@ -1505,7 +1504,7 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn is_power_of_two(self) -> bool { self.count_ones() == 1 }
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 92090d8..a0577b2 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs
@@ -456,9 +456,13 @@ } macro_rules! div_impl_integer { - ($($t:ty)*) => ($( + ($(($($t:ty)*) => $panic:expr),*) => ($($( /// This operation rounds towards zero, truncating any /// fractional part of the exact result. + /// + /// # Panics + /// + #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] impl Div for $t { type Output = $t; @@ -468,10 +472,13 @@ } forward_ref_binop! { impl Div, div for $t, $t } - )*) + )*)*) } -div_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +div_impl_integer! { + (usize u8 u16 u32 u64 u128) => "This operation will panic if `other == 0`.", + (isize i8 i16 i32 i64 i128) => "This operation will panic if `other == 0` or the division results in overflow." +} macro_rules! div_impl_float { ($($t:ty)*) => ($( @@ -549,9 +556,13 @@ } macro_rules! rem_impl_integer { - ($($t:ty)*) => ($( + ($(($($t:ty)*) => $panic:expr),*) => ($($( /// This operation satisfies `n % d == n - (n / d) * d`. The /// result has the same sign as the left operand. + /// + /// # Panics + /// + #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { type Output = $t; @@ -561,10 +572,13 @@ } forward_ref_binop! { impl Rem, rem for $t, $t } - )*) + )*)*) } -rem_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +rem_impl_integer! { + (usize u8 u16 u32 u64 u128) => "This operation will panic if `other == 0`.", + (isize i8 i16 i32 i64 i128) => "This operation will panic if `other == 0` or if `self / other` results in overflow." +} macro_rules! rem_impl_float { ($($t:ty)*) => ($(
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 2f78ba8..ecaff05 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs
@@ -1,4 +1,5 @@ -use crate::ops::Try; +use crate::convert; +use crate::ops::{self, Try}; /// Used to tell an operation whether it should exit early or go on as usual. /// @@ -81,6 +82,35 @@ } } +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<B, C> ops::TryV2 for ControlFlow<B, C> { + type Output = C; + type Residual = ControlFlow<B, convert::Infallible>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + ControlFlow::Continue(output) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + ControlFlow::Continue(c) => ControlFlow::Continue(c), + ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<B, C> ops::FromResidual for ControlFlow<B, C> { + #[inline] + fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self { + match residual { + ControlFlow::Break(b) => ControlFlow::Break(b), + } + } +} + impl<B, C> ControlFlow<B, C> { /// Returns `true` if this is a `Break` variant. ///
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 10e3ce6..dcf3ce0 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs
@@ -65,7 +65,7 @@ /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "deref_target"] - #[cfg_attr(not(bootstrap), lang = "deref_target")] + #[lang = "deref_target"] type Target: ?Sized; /// Dereferences the value.
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index ce7d1c3..f4b1ec3 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs
@@ -78,7 +78,7 @@ /// /// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error. /// -/// If you'd like explicitly call the destructor of a value, [`mem::drop`] can be used instead. +/// If you'd like to explicitly call the destructor of a value, [`mem::drop`] can be used instead. /// /// [`mem::drop`]: drop ///
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index a8dea4e..964378c 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs
@@ -61,6 +61,10 @@ type Output: ?Sized; /// Performs the indexing (`container[index]`) operation. + /// + /// # Panics + /// + /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] fn index(&self, index: Idx) -> &Self::Output; @@ -161,6 +165,10 @@ #[doc(alias = "[]")] pub trait IndexMut<Idx: ?Sized>: Index<Idx> { /// Performs the mutable indexing (`container[index]`) operation. + /// + /// # Panics + /// + /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 354ad6b..1b07936 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs
@@ -148,6 +148,7 @@ mod index; mod range; mod r#try; +mod try_trait; mod unsize; #[stable(feature = "rust1", since = "1.0.0")] @@ -184,6 +185,12 @@ #[unstable(feature = "try_trait", issue = "42327")] pub use self::r#try::Try; +#[unstable(feature = "try_trait_v2", issue = "84277")] +pub use self::try_trait::FromResidual; + +#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] +pub use self::try_trait::Try as TryV2; + #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState};
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs new file mode 100644 index 0000000..0c819b0 --- /dev/null +++ b/library/core/src/ops/try_trait.rs
@@ -0,0 +1,243 @@ +use crate::ops::ControlFlow; + +/// The `?` operator and `try {}` blocks. +/// +/// `try_*` methods typically involve a type implementing this trait. For +/// example, the closures passed to [`Iterator::try_fold`] and +/// [`Iterator::try_for_each`] must return such a type. +/// +/// `Try` types are typically those containing two or more categories of values, +/// some subset of which are so commonly handled via early returns that it's +/// worth providing a terse (but still visible) syntax to make that easy. +/// +/// This is most often seen for error handling with [`Result`] and [`Option`]. +/// The quintessential implementation of this trait is on [`ControlFlow`]. +/// +/// # Using `Try` in Generic Code +/// +/// `Iterator::try_fold` was stabilized to call back in Rust 1.27, but +/// this trait is much newer. To illustrate the various associated types and +/// methods, let's implement our own version. +/// +/// As a reminder, an infallible version of a fold looks something like this: +/// ``` +/// fn simple_fold<A, T>( +/// iter: impl Iterator<Item = T>, +/// mut accum: A, +/// mut f: impl FnMut(A, T) -> A, +/// ) -> A { +/// for x in iter { +/// accum = f(accum, x); +/// } +/// accum +/// } +/// ``` +/// +/// So instead of `f` returning just an `A`, we'll need it to return some other +/// type that produces an `A` in the "don't short circuit" path. Conveniently, +/// that's also the type we need to return from the function. +/// +/// Let's add a new generic parameter `R` for that type, and bound it to the +/// output type that we want: +/// ``` +/// # #![feature(try_trait_v2)] +/// # #![feature(try_trait_transition)] +/// # use std::ops::TryV2 as Try; +/// fn simple_try_fold_1<A, T, R: Try<Output = A>>( +/// iter: impl Iterator<Item = T>, +/// mut accum: A, +/// mut f: impl FnMut(A, T) -> R, +/// ) -> R { +/// todo!() +/// } +/// ``` +/// +/// If we get through the entire iterator, we need to wrap up the accumulator +/// into the return type using [`Try::from_output`]: +/// ``` +/// # #![feature(try_trait_v2)] +/// # #![feature(try_trait_transition)] +/// # #![feature(control_flow_enum)] +/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// fn simple_try_fold_2<A, T, R: Try<Output = A>>( +/// iter: impl Iterator<Item = T>, +/// mut accum: A, +/// mut f: impl FnMut(A, T) -> R, +/// ) -> R { +/// for x in iter { +/// let cf = f(accum, x).branch(); +/// match cf { +/// ControlFlow::Continue(a) => accum = a, +/// ControlFlow::Break(_) => todo!(), +/// } +/// } +/// R::from_output(accum) +/// } +/// ``` +/// +/// We'll also need [`FromResidual::from_residual`] to turn the residual back +/// into the original type. But because it's a supertrait of `Try`, we don't +/// need to mention it in the bounds. All types which implement `Try` can be +/// recreated from their corresponding residual, so we'll just call it: +/// ``` +/// # #![feature(try_trait_v2)] +/// # #![feature(try_trait_transition)] +/// # #![feature(control_flow_enum)] +/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>( +/// iter: impl Iterator<Item = T>, +/// mut accum: A, +/// mut f: impl FnMut(A, T) -> R, +/// ) -> R { +/// for x in iter { +/// let cf = f(accum, x).branch(); +/// match cf { +/// ControlFlow::Continue(a) => accum = a, +/// ControlFlow::Break(r) => return R::from_residual(r), +/// } +/// } +/// R::from_output(accum) +/// } +/// ``` +/// +/// But this "call `branch`, then `match` on it, and `return` if it was a +/// `Break`" is exactly what happens inside the `?` operator. So rather than +/// do all this manually, we can just use `?` instead: +/// ```compile_fail (enable again once ? converts to the new trait) +/// # #![feature(try_trait_v2)] +/// # #![feature(try_trait_transition)] +/// # use std::ops::TryV2 as Try; +/// fn simple_try_fold<A, T, R: Try<Output = A>>( +/// iter: impl Iterator<Item = T>, +/// mut accum: A, +/// mut f: impl FnMut(A, T) -> R, +/// ) -> R { +/// for x in iter { +/// accum = f(accum, x)?; +/// } +/// R::from_output(accum) +/// } +/// ``` +#[unstable(feature = "try_trait_v2", issue = "84277")] +pub trait Try: FromResidual { + /// The type of the value produced by `?` when *not* short-circuiting. + #[unstable(feature = "try_trait_v2", issue = "84277")] + type Output; + + /// The type of the value passed to [`FromResidual::from_residual`] + /// as part of `?` when short-circuiting. + /// + /// This represents the possible values of the `Self` type which are *not* + /// represented by the `Output` type. + /// + /// # Note to Implementors + /// + /// The choice of this type is critical to interconversion. + /// Unlike the `Output` type, which will often be a raw generic type, + /// this type is typically a newtype of some sort to "color" the type + /// so that it's distinguishable from the residuals of other types. + /// + /// This is why `Result<T, E>::Residual` is not `E`, but `Result<Infallible, E>`. + /// That way it's distinct from `ControlFlow<E>::Residual`, for example, + /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`. + /// + /// If you're making a generic type `Foo<T>` that implements `Try<Output = T>`, + /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` + /// type: that type will have a "hole" in the correct place, and will maintain the + /// "foo-ness" of the residual so other types need to opt-in to interconversion. + #[unstable(feature = "try_trait_v2", issue = "84277")] + type Residual; + + /// Constructs the type from its `Output` type. + /// + /// This should be implemented consistently with the `branch` method + /// such that applying the `?` operator will get back the original value: + /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_trait_v2)] + /// #![feature(control_flow_enum)] + /// #![feature(try_trait_transition)] + /// use std::ops::TryV2 as Try; + /// + /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); + /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4)); + /// assert_eq!( + /// <std::ops::ControlFlow<String, _> as Try>::from_output(5), + /// std::ops::ControlFlow::Continue(5), + /// ); + /// + /// # fn make_question_mark_work() -> Option<()> { + /// assert_eq!(Option::from_output(4)?, 4); + /// # None } + /// # make_question_mark_work(); + /// + /// // This is used, for example, on the accumulator in `try_fold`: + /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); + /// assert_eq!(r, Some(4)); + /// ``` + #[unstable(feature = "try_trait_v2", issue = "84277")] + fn from_output(output: Self::Output) -> Self; + + /// Used in `?` to decide whether the operator should produce a value + /// (because this returned [`ControlFlow::Continue`]) + /// or propagate a value back to the caller + /// (because this returned [`ControlFlow::Break`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(try_trait_v2)] + /// #![feature(control_flow_enum)] + /// #![feature(try_trait_transition)] + /// use std::ops::{ControlFlow, TryV2 as Try}; + /// + /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3))); + /// + /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None)); + /// + /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!( + /// ControlFlow::<_, String>::Break(3).branch(), + /// ControlFlow::Break(ControlFlow::Break(3)), + /// ); + /// ``` + #[unstable(feature = "try_trait_v2", issue = "84277")] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; +} + +/// Used to specify which residuals can be converted into which [`Try`] types. +/// +/// Every `Try` type needs to be recreatable from its own associated +/// `Residual` type, but can also have additional `FromResidual` implementations +/// to support interconversion with other `Try` types. +#[unstable(feature = "try_trait_v2", issue = "84277")] +pub trait FromResidual<R = <Self as Try>::Residual> { + /// Constructs the type from a compatible `Residual` type. + /// + /// This should be implemented consistently with the `branch` method such + /// that applying the `?` operator will get back an equivalent residual: + /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. + /// (It may not be an *identical* residual when interconversion is involved.) + /// + /// # Examples + /// + /// ``` + /// #![feature(try_trait_v2)] + /// #![feature(control_flow_enum)] + /// use std::ops::{ControlFlow, FromResidual}; + /// + /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3)); + /// assert_eq!(Option::<String>::from_residual(None), None); + /// assert_eq!( + /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)), + /// ControlFlow::Break(5), + /// ); + /// ``` + #[unstable(feature = "try_trait_v2", issue = "84277")] + fn from_residual(residual: R) -> Self; +}
diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f1a0f45..04551dd 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs
@@ -150,8 +150,8 @@ use crate::iter::{FromIterator, FusedIterator, TrustedLen}; use crate::pin::Pin; use crate::{ - fmt, hint, mem, - ops::{self, Deref, DerefMut}, + convert, hint, mem, + ops::{self, ControlFlow, Deref, DerefMut}, }; /// The `Option` type. See [the module level documentation](self) for more. @@ -489,8 +489,8 @@ } } - /// Applies a function to the contained value (if any), - /// or returns the provided default (if not). + /// Returns the provided default result (if none), + /// or applies a function to the contained value (if any). /// /// Arguments passed to `map_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`map_or_else`], @@ -516,8 +516,8 @@ } } - /// Applies a function to the contained value (if any), - /// or computes a default (if not). + /// Computes a default function result (if none), or + /// applies a different function to the contained value (if any). /// /// # Examples /// @@ -594,36 +594,6 @@ } } - /// Inserts `value` into the option then returns a mutable reference to it. - /// - /// If the option already contains a value, the old value is dropped. - /// - /// # Example - /// - /// ``` - /// #![feature(option_insert)] - /// - /// let mut opt = None; - /// let val = opt.insert(1); - /// assert_eq!(*val, 1); - /// assert_eq!(opt.unwrap(), 1); - /// let val = opt.insert(2); - /// assert_eq!(*val, 2); - /// *val = 3; - /// assert_eq!(opt.unwrap(), 3); - /// ``` - #[inline] - #[unstable(feature = "option_insert", reason = "newly added", issue = "78271")] - pub fn insert(&mut self, value: T) -> &mut T { - *self = Some(value); - - match self { - Some(v) => v, - // SAFETY: the code above just filled the option - None => unsafe { hint::unreachable_unchecked() }, - } - } - ///////////////////////////////////////////////////////////////////////// // Iterator constructors ///////////////////////////////////////////////////////////////////////// @@ -851,12 +821,46 @@ } ///////////////////////////////////////////////////////////////////////// - // Entry-like operations to insert if None and return a reference + // Entry-like operations to insert a value and return a reference ///////////////////////////////////////////////////////////////////////// + /// Inserts `value` into the option then returns a mutable reference to it. + /// + /// If the option already contains a value, the old value is dropped. + /// + /// See also [`Option::get_or_insert`], which doesn't update the value if + /// the option already contains [`Some`]. + /// + /// # Example + /// + /// ``` + /// let mut opt = None; + /// let val = opt.insert(1); + /// assert_eq!(*val, 1); + /// assert_eq!(opt.unwrap(), 1); + /// let val = opt.insert(2); + /// assert_eq!(*val, 2); + /// *val = 3; + /// assert_eq!(opt.unwrap(), 3); + /// ``` + #[inline] + #[stable(feature = "option_insert", since = "1.53.0")] + pub fn insert(&mut self, value: T) -> &mut T { + *self = Some(value); + + match self { + Some(v) => v, + // SAFETY: the code above just filled the option + None => unsafe { hint::unreachable_unchecked() }, + } + } + /// Inserts `value` into the option if it is [`None`], then /// returns a mutable reference to the contained value. /// + /// See also [`Option::insert`], which updates the value even if + /// the option already contains [`Some`]. + /// /// # Examples /// /// ``` @@ -1121,90 +1125,6 @@ } } -impl<T: fmt::Debug> Option<T> { - /// Consumes `self` while expecting [`None`] and returning nothing. - /// - /// # Panics - /// - /// Panics if the value is a [`Some`], with a panic message including the - /// passed message, and the content of the [`Some`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(option_expect_none)] - /// - /// use std::collections::HashMap; - /// let mut squares = HashMap::new(); - /// for i in -10..=10 { - /// // This will not panic, since all keys are unique. - /// squares.insert(i, i * i).expect_none("duplicate key"); - /// } - /// ``` - /// - /// ```should_panic - /// #![feature(option_expect_none)] - /// - /// use std::collections::HashMap; - /// let mut sqrts = HashMap::new(); - /// for i in -10..=10 { - /// // This will panic, since both negative and positive `i` will - /// // insert the same `i * i` key, returning the old `Some(i)`. - /// sqrts.insert(i * i, i).expect_none("duplicate key"); - /// } - /// ``` - #[inline] - #[track_caller] - #[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")] - pub fn expect_none(self, msg: &str) { - if let Some(val) = self { - expect_none_failed(msg, &val); - } - } - - /// Consumes `self` while expecting [`None`] and returning nothing. - /// - /// # Panics - /// - /// Panics if the value is a [`Some`], with a custom panic message provided - /// by the [`Some`]'s value. - /// - /// [`Some(v)`]: Some - /// - /// # Examples - /// - /// ``` - /// #![feature(option_unwrap_none)] - /// - /// use std::collections::HashMap; - /// let mut squares = HashMap::new(); - /// for i in -10..=10 { - /// // This will not panic, since all keys are unique. - /// squares.insert(i, i * i).unwrap_none(); - /// } - /// ``` - /// - /// ```should_panic - /// #![feature(option_unwrap_none)] - /// - /// use std::collections::HashMap; - /// let mut sqrts = HashMap::new(); - /// for i in -10..=10 { - /// // This will panic, since both negative and positive `i` will - /// // insert the same `i * i` key, returning the old `Some(i)`. - /// sqrts.insert(i * i, i).unwrap_none(); - /// } - /// ``` - #[inline] - #[track_caller] - #[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")] - pub fn unwrap_none(self) { - if let Some(val) = self { - expect_none_failed("called `Option::unwrap_none()` on a `Some` value", &val); - } - } -} - impl<T: Default> Option<T> { /// Returns the contained [`Some`] value or a default /// @@ -1321,14 +1241,6 @@ panic!("{}", msg) } -// This is a separate function to reduce the code size of .expect_none() itself. -#[inline(never)] -#[cold] -#[track_caller] -fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { - panic!("{}: {:?}", msg, value) -} - ///////////////////////////////////////////////////////////////////////////// // Trait implementations ///////////////////////////////////////////////////////////////////////////// @@ -1752,6 +1664,35 @@ } } +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T> ops::TryV2 for Option<T> { + type Output = T; + type Residual = Option<convert::Infallible>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + Some(output) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + Some(v) => ControlFlow::Continue(v), + None => ControlFlow::Break(None), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T> ops::FromResidual for Option<T> { + #[inline] + fn from_residual(residual: Option<convert::Infallible>) -> Self { + match residual { + None => None, + } + } +} + impl<T> Option<Option<T>> { /// Converts from `Option<Option<T>>` to `Option<T>` ///
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index b2de0e1..3d88829 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs
@@ -6,7 +6,7 @@ //! as moving an object with pointers to itself will invalidate them, which could cause undefined //! behavior. //! -//! At a high level, a [`Pin<P>`] ensures that the pointee of any pointer type +//! At a high level, a <code>[Pin]\<P></code> ensures that the pointee of any pointer type //! `P` has a stable location in memory, meaning it cannot be moved elsewhere //! and its memory cannot be deallocated until it gets dropped. We say that the //! pointee is "pinned". Things get more subtle when discussing types that @@ -14,13 +14,15 @@ //! for more details. //! //! By default, all types in Rust are movable. Rust allows passing all types by-value, -//! and common smart-pointer types such as [`Box<T>`] and `&mut T` allow replacing and -//! moving the values they contain: you can move out of a [`Box<T>`], or you can use [`mem::swap`]. -//! [`Pin<P>`] wraps a pointer type `P`, so [`Pin`]`<`[`Box`]`<T>>` functions much like a regular -//! [`Box<T>`]: when a [`Pin`]`<`[`Box`]`<T>>` gets dropped, so do its contents, and the memory gets -//! deallocated. Similarly, [`Pin`]`<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does -//! not let clients actually obtain a [`Box<T>`] or `&mut T` to pinned data, which implies that you -//! cannot use operations such as [`mem::swap`]: +//! and common smart-pointer types such as <code>[Box]\<T></code> and <code>[&mut] T</code> allow +//! replacing and moving the values they contain: you can move out of a <code>[Box]\<T></code>, +//! or you can use [`mem::swap`]. <code>[Pin]\<P></code> wraps a pointer type `P`, so +//! <code>[Pin]<[Box]\<T>></code> functions much like a regular <code>[Box]\<T></code>: +//! when a <code>[Pin]<[Box]\<T>></code> gets dropped, so do its contents, and the memory gets +//! deallocated. Similarly, <code>[Pin]<[&mut] T></code> is a lot like <code>[&mut] T</code>. +//! However, <code>[Pin]\<P></code> does not let clients actually obtain a <code>[Box]\<T></code> +//! or <code>[&mut] T</code> to pinned data, which implies that you cannot use operations such +//! as [`mem::swap`]: //! //! ``` //! use std::pin::Pin; @@ -32,18 +34,18 @@ //! } //! ``` //! -//! It is worth reiterating that [`Pin<P>`] does *not* change the fact that a Rust compiler -//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, [`Pin<P>`] -//! prevents certain *values* (pointed to by pointers wrapped in [`Pin<P>`]) from being -//! moved by making it impossible to call methods that require `&mut T` on them -//! (like [`mem::swap`]). +//! It is worth reiterating that <code>[Pin]\<P></code> does *not* change the fact that a Rust +//! compiler considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, +//! <code>[Pin]\<P></code> prevents certain *values* (pointed to by pointers wrapped in +//! <code>[Pin]\<P></code>) from being moved by making it impossible to call methods that require +//! <code>[&mut] T</code> on them (like [`mem::swap`]). //! -//! [`Pin<P>`] can be used to wrap any pointer type `P`, and as such it interacts with -//! [`Deref`] and [`DerefMut`]. A [`Pin<P>`] where `P: Deref` should be considered -//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a [`Pin`]`<`[`Box`]`<T>>` is -//! an owned pointer to a pinned `T`, and a [`Pin`]`<`[`Rc`]`<T>>` is a reference-counted -//! pointer to a pinned `T`. -//! For correctness, [`Pin<P>`] relies on the implementations of [`Deref`] and +//! <code>[Pin]\<P></code> can be used to wrap any pointer type `P`, and as such it interacts with +//! [`Deref`] and [`DerefMut`]. A <code>[Pin]\<P></code> where <code>P: [Deref]</code> should be +//! considered as a "`P`-style pointer" to a pinned <code>P::[Target]</code> – so, a +//! <code>[Pin]<[Box]\<T>></code> is an owned pointer to a pinned `T`, and a +//! <code>[Pin]<[Rc]\<T>></code> is a reference-counted pointer to a pinned `T`. +//! For correctness, <code>[Pin]\<P></code> relies on the implementations of [`Deref`] and //! [`DerefMut`] not to move out of their `self` parameter, and only ever to //! return a pointer to pinned data when they are called on a pinned pointer. //! @@ -53,19 +55,19 @@ //! rely on having a stable address. This includes all the basic types (like //! [`bool`], [`i32`], and references) as well as types consisting solely of these //! types. Types that do not care about pinning implement the [`Unpin`] -//! auto-trait, which cancels the effect of [`Pin<P>`]. For `T: Unpin`, -//! [`Pin`]`<`[`Box`]`<T>>` and [`Box<T>`] function identically, as do [`Pin`]`<&mut T>` and -//! `&mut T`. +//! auto-trait, which cancels the effect of <code>[Pin]\<P></code>. For <code>T: [Unpin]</code>, +//! <code>[Pin]<[Box]\<T>></code> and <code>[Box]\<T></code> function identically, as do +//! <code>[Pin]<[&mut] T></code> and <code>[&mut] T</code>. //! -//! Note that pinning and [`Unpin`] only affect the pointed-to type `P::Target`, not the pointer -//! type `P` itself that got wrapped in [`Pin<P>`]. For example, whether or not [`Box<T>`] is -//! [`Unpin`] has no effect on the behavior of [`Pin`]`<`[`Box`]`<T>>` (here, `T` is the -//! pointed-to type). +//! Note that pinning and [`Unpin`] only affect the pointed-to type <code>P::[Target]</code>, +//! not the pointer type `P` itself that got wrapped in <code>[Pin]\<P></code>. For example, +//! whether or not <code>[Box]\<T></code> is [`Unpin`] has no effect on the behavior of +//! <code>[Pin]<[Box]\<T>></code> (here, `T` is the pointed-to type). //! //! # Example: self-referential struct //! //! Before we go into more details to explain the guarantees and choices -//! associated with `Pin<T>`, we discuss some examples for how it might be used. +//! associated with <code>[Pin]\<P></code>, we discuss some examples for how it might be used. //! Feel free to [skip to where the theoretical discussion continues](#drop-guarantee). //! //! ```rust @@ -129,7 +131,7 @@ //! //! To make this work, every element has pointers to its predecessor and successor in //! the list. Elements can only be added when they are pinned, because moving the elements -//! around would invalidate the pointers. Moreover, the [`Drop`] implementation of a linked +//! around would invalidate the pointers. Moreover, the [`Drop`][Drop] implementation of a linked //! list element will patch the pointers of its predecessor and successor to remove itself //! from the list. //! @@ -149,8 +151,8 @@ //! when [`drop`] is called*. Only once [`drop`] returns or panics, the memory may be reused. //! //! Memory can be "invalidated" by deallocation, but also by -//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements -//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without +//! replacing a <code>[Some]\(v)</code> by [`None`], or calling [`Vec::set_len`] to "kill" some +//! elements off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without //! calling the destructor first. None of this is allowed for pinned data without calling [`drop`]. //! //! This is exactly the kind of guarantee that the intrusive linked list from the previous @@ -158,25 +160,25 @@ //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still //! completely okay not ever to call [`drop`] on a pinned element (e.g., you can still -//! call [`mem::forget`] on a [`Pin`]`<`[`Box`]`<T>>`). In the example of the doubly-linked +//! call [`mem::forget`] on a <code>[Pin]<[Box]\<T>></code>). In the example of the doubly-linked //! list, that element would just stay in the list. However you may not free or reuse the storage //! *without calling [`drop`]*. //! //! # `Drop` implementation //! //! If your type uses pinning (such as the two examples above), you have to be careful -//! when implementing [`Drop`]. The [`drop`] function takes `&mut self`, but this +//! when implementing [`Drop`][Drop]. The [`drop`] function takes <code>[&mut] self</code>, but this //! is called *even if your type was previously pinned*! It is as if the //! compiler automatically called [`Pin::get_unchecked_mut`]. //! //! This can never cause a problem in safe code because implementing a type that //! relies on pinning requires unsafe code, but be aware that deciding to make //! use of pinning in your type (for example by implementing some operation on -//! [`Pin`]`<&Self>` or [`Pin`]`<&mut Self>`) has consequences for your [`Drop`] -//! implementation as well: if an element of your type could have been pinned, -//! you must treat [`Drop`] as implicitly taking [`Pin`]`<&mut Self>`. +//! <code>[Pin]<[&]Self></code> or <code>[Pin]<[&mut] Self></code>) has consequences for your +//! [`Drop`][Drop]implementation as well: if an element of your type could have been pinned, +//! you must treat [`Drop`][Drop] as implicitly taking <code>[Pin]<[&mut] Self></code>. //! -//! For example, you could implement `Drop` as follows: +//! For example, you could implement [`Drop`][Drop] as follows: //! //! ```rust,no_run //! # use std::pin::Pin; @@ -204,18 +206,18 @@ //! # Projections and Structural Pinning //! //! When working with pinned structs, the question arises how one can access the -//! fields of that struct in a method that takes just [`Pin`]`<&mut Struct>`. +//! fields of that struct in a method that takes just <code>[Pin]<[&mut] Struct></code>. //! The usual approach is to write helper methods (so called *projections*) -//! that turn [`Pin`]`<&mut Struct>` into a reference to the field, but what -//! type should that reference have? Is it [`Pin`]`<&mut Field>` or `&mut Field`? +//! that turn <code>[Pin]<[&mut] Struct></code> into a reference to the field, but what type should +//! that reference have? Is it <code>[Pin]<[&mut] Field></code> or <code>[&mut] Field</code>? //! The same question arises with the fields of an `enum`, and also when considering -//! container/wrapper types such as [`Vec<T>`], [`Box<T>`], or [`RefCell<T>`]. -//! (This question applies to both mutable and shared references, we just -//! use the more common case of mutable references here for illustration.) +//! container/wrapper types such as <code>[Vec]\<T></code>, <code>[Box]\<T></code>, +//! or <code>[RefCell]\<T></code>. (This question applies to both mutable and shared references, +//! we just use the more common case of mutable references here for illustration.) //! -//! It turns out that it is actually up to the author of the data structure -//! to decide whether the pinned projection for a particular field turns -//! [`Pin`]`<&mut Struct>` into [`Pin`]`<&mut Field>` or `&mut Field`. There are some +//! It turns out that it is actually up to the author of the data structure to decide whether +//! the pinned projection for a particular field turns <code>[Pin]<[&mut] Struct></code> +//! into <code>[Pin]<[&mut] Field></code> or <code>[&mut] Field</code>. There are some //! constraints though, and the most important constraint is *consistency*: //! every field can be *either* projected to a pinned reference, *or* have //! pinning removed as part of the projection. If both are done for the same field, @@ -230,12 +232,12 @@ //! ## Pinning *is not* structural for `field` //! //! It may seem counter-intuitive that the field of a pinned struct might not be pinned, -//! but that is actually the easiest choice: if a [`Pin`]`<&mut Field>` is never created, +//! but that is actually the easiest choice: if a <code>[Pin]<[&mut] Field></code> is never created, //! nothing can go wrong! So, if you decide that some field does not have structural pinning, //! all you have to ensure is that you never create a pinned reference to that field. //! //! Fields without structural pinning may have a projection method that turns -//! [`Pin`]`<&mut Struct>` into `&mut Field`: +//! <code>[Pin]<[&mut] Struct></code> into <code>[&mut] Field</code>: //! //! ```rust,no_run //! # use std::pin::Pin; @@ -249,16 +251,16 @@ //! } //! ``` //! -//! You may also `impl Unpin for Struct` *even if* the type of `field` +//! You may also <code>impl [Unpin] for Struct</code> *even if* the type of `field` //! is not [`Unpin`]. What that type thinks about pinning is not relevant -//! when no [`Pin`]`<&mut Field>` is ever created. +//! when no <code>[Pin]<[&mut] Field></code> is ever created. //! //! ## Pinning *is* structural for `field` //! //! The other option is to decide that pinning is "structural" for `field`, //! meaning that if the struct is pinned then so is the field. //! -//! This allows writing a projection that creates a [`Pin`]`<&mut Field>`, thus +//! This allows writing a projection that creates a <code>[Pin]<[&mut] Field></code>, thus //! witnessing that the field is pinned: //! //! ```rust,no_run @@ -278,34 +280,36 @@ //! 1. The struct must only be [`Unpin`] if all the structural fields are //! [`Unpin`]. This is the default, but [`Unpin`] is a safe trait, so as the author of //! the struct it is your responsibility *not* to add something like -//! `impl<T> Unpin for Struct<T>`. (Notice that adding a projection operation +//! <code>impl\<T> [Unpin] for Struct\<T></code>. (Notice that adding a projection operation //! requires unsafe code, so the fact that [`Unpin`] is a safe trait does not break -//! the principle that you only have to worry about any of this if you use `unsafe`.) +//! the principle that you only have to worry about any of this if you use [`unsafe`].) //! 2. The destructor of the struct must not move structural fields out of its argument. This -//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes -//! `&mut self`, but the struct (and hence its fields) might have been pinned before. -//! You have to guarantee that you do not move a field inside your [`Drop`] implementation. -//! In particular, as explained previously, this means that your struct must *not* -//! be `#[repr(packed)]`. +//! is the exact point that was raised in the [previous section][drop-impl]: [`drop`] takes +//! <code>[&mut] self</code>, but the struct (and hence its fields) might have been pinned +//! before. You have to guarantee that you do not move a field inside your [`Drop`][Drop] +//! implementation. In particular, as explained previously, this means that your struct +//! must *not* be `#[repr(packed)]`. //! See that section for how to write [`drop`] in a way that the compiler can help you //! not accidentally break pinning. //! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: //! once your struct is pinned, the memory that contains the //! content is not overwritten or deallocated without calling the content's destructors. -//! This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of [`VecDeque<T>`] -//! can fail to call [`drop`] on all elements if one of the destructors panics. This violates -//! the [`Drop`] guarantee, because it can lead to elements being deallocated without -//! their destructor being called. ([`VecDeque<T>`] has no pinning projections, so this +//! This can be tricky, as witnessed by <code>[VecDeque]\<T></code>: the destructor of +//! <code>[VecDeque]\<T></code> can fail to call [`drop`] on all elements if one of the +//! destructors panics. This violates the [`Drop`][Drop] guarantee, because it can lead to +//! elements being deallocated without their destructor being called. +//! (<code>[VecDeque]\<T></code> has no pinning projections, so this //! does not cause unsoundness.) //! 4. You must not offer any other operations that could lead to data being moved out of //! the structural fields when your type is pinned. For example, if the struct contains an -//! [`Option<T>`] and there is a `take`-like operation with type -//! `fn(Pin<&mut Struct<T>>) -> Option<T>`, -//! that operation can be used to move a `T` out of a pinned `Struct<T>` -- which means +//! <code>[Option]\<T></code> and there is a [`take`][Option::take]-like operation with type +//! <code>fn([Pin]<[&mut] Struct\<T>>) -> [Option]\<T></code>, +//! that operation can be used to move a `T` out of a pinned `Struct<T>` – which means //! pinning cannot be structural for the field holding this data. //! -//! For a more complex example of moving data out of a pinned type, imagine if [`RefCell<T>`] -//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. +//! For a more complex example of moving data out of a pinned type, +//! imagine if <code>[RefCell]\<T></code> had a method +//! <code>fn get_pin_mut(self: [Pin]<[&mut] Self>) -> [Pin]<[&mut] T></code>. //! Then we could do the following: //! ```compile_fail //! fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>>) { @@ -315,60 +319,65 @@ //! let content = &mut *b; // And here we have `&mut T` to the same data. //! } //! ``` -//! This is catastrophic, it means we can first pin the content of the [`RefCell<T>`] -//! (using `RefCell::get_pin_mut`) and then move that content using the mutable -//! reference we got later. +//! This is catastrophic, it means we can first pin the content of the +//! <code>[RefCell]\<T></code> (using <code>[RefCell]::get_pin_mut</code>) and then move that +//! content using the mutable reference we got later. //! //! ## Examples //! -//! For a type like [`Vec<T>`], both possibilities (structural pinning or not) make sense. -//! A [`Vec<T>`] with structural pinning could have `get_pin`/`get_pin_mut` methods to get -//! pinned references to elements. However, it could *not* allow calling -//! [`pop`][Vec::pop] on a pinned [`Vec<T>`] because that would move the (structurally pinned) -//! contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also move the -//! contents. +//! For a type like <code>[Vec]\<T></code>, both possibilities (structural pinning or not) make +//! sense. A <code>[Vec]\<T></code> with structural pinning could have `get_pin`/`get_pin_mut` +//! methods to get pinned references to elements. However, it could *not* allow calling +//! [`pop`][Vec::pop] on a pinned <code>[Vec]\<T></code> because that would move the (structurally +//! pinned) contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also +//! move the contents. //! -//! A [`Vec<T>`] without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents -//! are never pinned and the [`Vec<T>`] itself is fine with being moved as well. +//! A <code>[Vec]\<T></code> without structural pinning could +//! <code>impl\<T> [Unpin] for [Vec]\<T></code>, because the contents are never pinned +//! and the <code>[Vec]\<T></code> itself is fine with being moved as well. //! At that point pinning just has no effect on the vector at all. //! //! In the standard library, pointer types generally do not have structural pinning, -//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`. -//! It makes sense to do this for pointer types, because moving the `Box<T>` -//! does not actually move the `T`: the [`Box<T>`] can be freely movable (aka `Unpin`) even if -//! the `T` is not. In fact, even [`Pin`]`<`[`Box`]`<T>>` and [`Pin`]`<&mut T>` are always -//! [`Unpin`] themselves, for the same reason: their contents (the `T`) are pinned, but the -//! pointers themselves can be moved without moving the pinned data. For both [`Box<T>`] and -//! [`Pin`]`<`[`Box`]`<T>>`, whether the content is pinned is entirely independent of whether the +//! and thus they do not offer pinning projections. This is why <code>[Box]\<T>: [Unpin]</code> +//! holds for all `T`. It makes sense to do this for pointer types, because moving the +//! <code>[Box]\<T></code> does not actually move the `T`: the <code>[Box]\<T></code> can be freely +//! movable (aka [`Unpin`]) even if the `T` is not. In fact, even <code>[Pin]<[Box]\<T>></code> and +//! <code>[Pin]<[&mut] T></code> are always [`Unpin`] themselves, for the same reason: +//! their contents (the `T`) are pinned, but the pointers themselves can be moved without moving +//! the pinned data. For both <code>[Box]\<T></code> and <code>[Pin]<[Box]\<T>></code>, +//! whether the content is pinned is entirely independent of whether the //! pointer is pinned, meaning pinning is *not* structural. //! //! When implementing a [`Future`] combinator, you will usually need structural pinning //! for the nested futures, as you need to get pinned references to them to call [`poll`]. //! But if your combinator contains any other data that does not need to be pinned, //! you can make those fields not structural and hence freely access them with a -//! mutable reference even when you just have [`Pin`]`<&mut Self>` (such as in your own +//! mutable reference even when you just have <code>[Pin]<[&mut] Self></code> (such as in your own //! [`poll`] implementation). //! -//! [`Deref`]: crate::ops::Deref -//! [`DerefMut`]: crate::ops::DerefMut -//! [`mem::swap`]: crate::mem::swap -//! [`mem::forget`]: crate::mem::forget -//! [`Box<T>`]: ../../std/boxed/struct.Box.html -//! [`Vec<T>`]: ../../std/vec/struct.Vec.html -//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len -//! [`Box`]: ../../std/boxed/struct.Box.html -//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop -//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push -//! [`Rc`]: ../../std/rc/struct.Rc.html -//! [`RefCell<T>`]: crate::cell::RefCell -//! [`drop`]: Drop::drop -//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html -//! [`Some(v)`]: Some -//! [`ptr::write`]: crate::ptr::write -//! [`Future`]: crate::future::Future +//! [Deref]: crate::ops::Deref "ops::Deref" +//! [`Deref`]: crate::ops::Deref "ops::Deref" +//! [Target]: crate::ops::Deref::Target "ops::Deref::Target" +//! [`DerefMut`]: crate::ops::DerefMut "ops::DerefMut" +//! [`mem::swap`]: crate::mem::swap "mem::swap" +//! [`mem::forget`]: crate::mem::forget "mem::forget" +//! [Vec]: ../../std/vec/struct.Vec.html "Vec" +//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len "Vec::set_len" +//! [Box]: ../../std/boxed/struct.Box.html "Box" +//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop "Vec::pop" +//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" +//! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" +//! [RefCell]: crate::cell::RefCell "cell::RefCell" +//! [`drop`]: Drop::drop "Drop::drop" +//! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" +//! [`ptr::write`]: crate::ptr::write "ptr::write" +//! [`Future`]: crate::future::Future "future::Future" //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee -//! [`poll`]: crate::future::Future::poll +//! [`poll`]: crate::future::Future::poll "future::Future::poll" +//! [&]: ../../std/primitive.reference.html "shared reference" +//! [&mut]: ../../std/primitive.reference.html "mutable reference" +//! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" #![stable(feature = "pin", since = "1.33.0")]
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 7d33ca8..c89fe57 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs
@@ -67,7 +67,6 @@ bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable, }; -#[cfg(not(bootstrap))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[doc(no_inline)] pub use crate::macros::builtin::derive; @@ -80,7 +79,6 @@ #[doc(no_inline)] pub use crate::macros::builtin::cfg_accessible; -#[cfg(not(bootstrap))] #[unstable( feature = "cfg_eval", issue = "82679",
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index b511466..b9b2ba9 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs
@@ -51,7 +51,6 @@ /// Decompose a (possibly wide) pointer into is address and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts`]. - #[cfg(not(bootstrap))] #[unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] @@ -184,8 +183,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -210,6 +208,7 @@ /// enables more aggressive compiler optimizations. /// /// [`wrapping_offset`]: #method.wrapping_offset + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -227,7 +226,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, @@ -245,9 +244,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -265,10 +263,8 @@ /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other /// words, leaving the allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`offset`]: #method.offset + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -292,7 +288,7 @@ #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const fn wrapping_offset(self, count: isize) -> *const T where T: Sized, @@ -314,8 +310,7 @@ /// Behavior: /// /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * Both pointers must be *derived from* a pointer to the same object. /// (See below for an example.) @@ -345,6 +340,7 @@ /// such large allocations either.) /// /// [`add`]: #method.add + /// [allocated object]: crate::ptr#allocated-object /// /// # Panics /// @@ -468,8 +464,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -494,6 +489,7 @@ /// enables more aggressive compiler optimizations. /// /// [`wrapping_add`]: #method.wrapping_add + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -511,7 +507,7 @@ #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -532,8 +528,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset cannot exceed `isize::MAX` **bytes**. /// @@ -558,6 +553,7 @@ /// enables more aggressive compiler optimizations. /// /// [`wrapping_sub`]: #method.wrapping_sub + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -594,9 +590,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -614,10 +609,8 @@ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the /// allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`add`]: #method.add + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -641,7 +634,7 @@ #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, @@ -659,9 +652,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -679,10 +671,8 @@ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the /// allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`sub`]: #method.sub + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -734,7 +724,7 @@ /// #![feature(set_ptr_value)] /// # use core::fmt::Debug; /// let arr: [i32; 3] = [1, 2, 3]; - /// let mut ptr = &arr[0] as *const dyn Debug; + /// let mut ptr = arr.as_ptr() as *const dyn Debug; /// let thin = ptr as *const u8; /// unsafe { /// ptr = ptr.set_ptr_value(thin.add(8)); @@ -924,13 +914,6 @@ #[unstable(feature = "slice_ptr_len", issue = "71146")] #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] pub const fn len(self) -> usize { - #[cfg(bootstrap)] - { - // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout. - // Only `std` can make this guarantee. - unsafe { Repr { rust: self }.raw }.len - } - #[cfg(not(bootstrap))] metadata(self) } @@ -997,7 +980,7 @@ /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes, /// and it must be properly aligned. This means in particular: /// - /// * The entire memory range of this slice must be contained within a single allocated object! + /// * The entire memory range of this slice must be contained within a single [allocated object]! /// Slices can never span across multiple allocated objects. /// /// * The pointer must be aligned even for zero-length slices. One @@ -1019,6 +1002,7 @@ /// See also [`slice::from_raw_parts`][]. /// /// [valid]: crate::ptr#safety + /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index fd24469..28044e0 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs
@@ -55,6 +55,14 @@ //! has size 0, i.e., even if memory is not actually touched. Consider using //! [`NonNull::dangling`] in such cases. //! +//! ## Allocated object +//! +//! For several operations, such as [`offset`] or field projections (`expr.field`), the notion of an +//! "allocated object" becomes relevant. An allocated object is a contiguous region of memory. +//! Common examples of allocated objects include stack-allocated variables (each variable is a +//! separate allocated object), heap allocations (each allocation created by the global allocator is +//! a separate allocated object), and `static` variables. +//! //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html @@ -82,11 +90,8 @@ #[doc(inline)] pub use crate::intrinsics::write_bytes; -#[cfg(not(bootstrap))] mod metadata; -#[cfg(not(bootstrap))] pub(crate) use metadata::PtrRepr; -#[cfg(not(bootstrap))] #[unstable(feature = "ptr_metadata", issue = "81513")] pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin}; @@ -205,7 +210,8 @@ #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] -#[rustc_const_stable(feature = "const_ptr_null", since = "1.32.0")] +#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] +#[rustc_diagnostic_item = "ptr_null"] pub const fn null<T>() -> *const T { 0 as *const T } @@ -223,38 +229,12 @@ #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] -#[rustc_const_stable(feature = "const_ptr_null", since = "1.32.0")] +#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] +#[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut<T>() -> *mut T { 0 as *mut T } -#[cfg(bootstrap)] -#[repr(C)] -pub(crate) union Repr<T> { - pub(crate) rust: *const [T], - rust_mut: *mut [T], - pub(crate) raw: FatPtr<T>, -} - -#[cfg(bootstrap)] -#[repr(C)] -pub(crate) struct FatPtr<T> { - data: *const T, - pub(crate) len: usize, -} - -#[cfg(bootstrap)] -// Manual impl needed to avoid `T: Clone` bound. -impl<T> Clone for FatPtr<T> { - fn clone(&self) -> Self { - *self - } -} - -#[cfg(bootstrap)] -// Manual impl needed to avoid `T: Copy` bound. -impl<T> Copy for FatPtr<T> {} - /// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. @@ -279,14 +259,6 @@ #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { - #[cfg(bootstrap)] - { - // SAFETY: Accessing the value from the `Repr` union is safe since *const [T] - // and FatPtr have the same memory layouts. Only std can make this - // guarantee. - unsafe { Repr { raw: FatPtr { data, len } }.rust } - } - #[cfg(not(bootstrap))] from_raw_parts(data.cast(), len) } @@ -319,13 +291,6 @@ #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { - #[cfg(bootstrap)] - { - // SAFETY: Accessing the value from the `Repr` union is safe since *mut [T] - // and FatPtr have the same memory layouts - unsafe { Repr { raw: FatPtr { data, len } }.rust_mut } - } - #[cfg(not(bootstrap))] from_raw_parts_mut(data.cast(), len) } @@ -464,19 +429,32 @@ #[inline] pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { - // For types smaller than the block optimization below, - // just swap directly to avoid pessimizing codegen. - if mem::size_of::<T>() < 32 { - // SAFETY: the caller must guarantee that `x` and `y` are valid - // for writes, properly aligned, and non-overlapping. - unsafe { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); + // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary + // reinterpretation of values as (chunkable) byte arrays, and the loop in the + // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back + // into the (unoptimized) direct swapping implementation, so we disable it. + // FIXME(eddyb) the block optimization also prevents MIR optimizations from + // understanding `mem::replace`, `Option::take`, etc. - a better overall + // solution might be to make `swap_nonoverlapping` into an intrinsic, which + // a backend can choose to implement using the block optimization, or not. + #[cfg(not(target_arch = "spirv"))] + { + // Only apply the block optimization in `swap_nonoverlapping_bytes` for types + // at least as large as the block size, to avoid pessimizing codegen. + if mem::size_of::<T>() >= 32 { + // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`. + unsafe { swap_nonoverlapping(x, y, 1) }; + return; } - } else { - // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`. - unsafe { swap_nonoverlapping(x, y, 1) }; + } + + // Direct swapping, for the cases not going through the block optimization. + // SAFETY: the caller must guarantee that `x` and `y` are valid + // for writes, properly aligned, and non-overlapping. + unsafe { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); } } @@ -765,6 +743,7 @@ /// unaligned: 0x01020304, /// }; /// +/// #[allow(unaligned_references)] /// let v = unsafe { /// // Here we attempt to take the address of a 32-bit integer which is not aligned. /// let unaligned = @@ -962,6 +941,7 @@ /// let v = 0x01020304; /// let mut packed: Packed = unsafe { std::mem::zeroed() }; /// +/// #[allow(unaligned_references)] /// let v = unsafe { /// // Here we attempt to take the address of a 32-bit integer which is not aligned. /// let unaligned = @@ -1516,6 +1496,10 @@ /// as all other references. This macro can create a raw pointer *without* creating /// a reference first. /// +/// Note, however, that the `expr` in `addr_of!(expr)` is still subject to all +/// the usual rules. In particular, `addr_of!(*ptr::null())` is Undefined +/// Behavior because it dereferences a NULL pointer. +/// /// # Example /// /// ``` @@ -1532,6 +1516,10 @@ /// let raw_f2 = ptr::addr_of!(packed.f2); /// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); /// ``` +/// +/// See [`addr_of_mut`] for how to create a pointer to unininitialized data. +/// Doing that with `addr_of` would not make much sense since one could only +/// read the data, and that would be Undefined Behavior. #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)] @@ -1548,7 +1536,13 @@ /// as all other references. This macro can create a raw pointer *without* creating /// a reference first. /// -/// # Example +/// Note, however, that the `expr` in `addr_of_mut!(expr)` is still subject to all +/// the usual rules. In particular, `addr_of_mut!(*ptr::null_mut())` is Undefined +/// Behavior because it dereferences a NULL pointer. +/// +/// # Examples +/// +/// **Creating a pointer to unaligned data:** /// /// ``` /// use std::ptr; @@ -1565,6 +1559,23 @@ /// unsafe { raw_f2.write_unaligned(42); } /// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. /// ``` +/// +/// **Creating a pointer to uninitialized data:** +/// +/// ```rust +/// use std::{ptr, mem::MaybeUninit}; +/// +/// struct Demo { +/// field: bool, +/// } +/// +/// let mut uninit = MaybeUninit::<Demo>::uninit(); +/// // `&uninit.as_mut().field` would create a reference to an uninitialized `bool`, +/// // and thus be Undefined Behavior! +/// let f1_ptr = unsafe { ptr::addr_of_mut!((*uninit.as_mut_ptr()).field) }; +/// unsafe { f1_ptr.write(true); } +/// let init = unsafe { uninit.assume_init() }; +/// ``` #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] #[allow_internal_unstable(raw_ref_op)]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index a9de233..16f6efc 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs
@@ -50,7 +50,6 @@ /// Decompose a (possibly wide) pointer into is address and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts_mut`]. - #[cfg(not(bootstrap))] #[unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] @@ -189,8 +188,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -215,6 +213,7 @@ /// enables more aggressive compiler optimizations. /// /// [`wrapping_offset`]: #method.wrapping_offset + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -232,7 +231,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, @@ -251,9 +250,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -271,10 +269,8 @@ /// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other /// words, leaving the allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`offset`]: #method.offset + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -298,7 +294,7 @@ #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const fn wrapping_offset(self, count: isize) -> *mut T where T: Sized, @@ -485,8 +481,7 @@ /// Behavior: /// /// * Both the starting and other pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * Both pointers must be *derived from* a pointer to the same object. /// (See below for an example.) @@ -516,6 +511,7 @@ /// such large allocations either.) /// /// [`add`]: #method.add + /// [allocated object]: crate::ptr#allocated-object /// /// # Panics /// @@ -575,8 +571,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -618,7 +613,7 @@ #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -639,8 +634,7 @@ /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same allocated object. Note that in Rust, - /// every (stack-allocated) variable is considered a separate allocated object. + /// byte past the end of the same [allocated object]. /// /// * The computed offset cannot exceed `isize::MAX` **bytes**. /// @@ -665,6 +659,7 @@ /// enables more aggressive compiler optimizations. /// /// [`wrapping_sub`]: #method.wrapping_sub + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -701,9 +696,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -721,10 +715,8 @@ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the /// allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`add`]: #method.add + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -748,7 +740,7 @@ #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] - #[inline] + #[inline(always)] pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, @@ -766,9 +758,8 @@ /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer remains attached to the same allocated object that `self` points to. - /// It may *not* be used to access a different allocated object. Note that in Rust, every - /// (stack-allocated) variable is considered a separate allocated object. + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` /// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still @@ -786,10 +777,8 @@ /// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the /// allocated object and then re-entering it later is permitted. /// - /// If you need to cross object boundaries, cast the pointer to an integer and - /// do the arithmetic there. - /// /// [`sub`]: #method.sub + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -841,7 +830,7 @@ /// #![feature(set_ptr_value)] /// # use core::fmt::Debug; /// let mut arr: [i32; 3] = [1, 2, 3]; - /// let mut ptr = &mut arr[0] as *mut dyn Debug; + /// let mut ptr = arr.as_mut_ptr() as *mut dyn Debug; /// let thin = ptr as *mut u8; /// unsafe { /// ptr = ptr.set_ptr_value(thin.add(8)); @@ -1184,13 +1173,6 @@ #[unstable(feature = "slice_ptr_len", issue = "71146")] #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] pub const fn len(self) -> usize { - #[cfg(bootstrap)] - { - // SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout. - // Only `std` can make this guarantee. - unsafe { Repr { rust_mut: self }.raw }.len - } - #[cfg(not(bootstrap))] metadata(self) } @@ -1260,7 +1242,7 @@ /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes, /// and it must be properly aligned. This means in particular: /// - /// * The entire memory range of this slice must be contained within a single allocated object! + /// * The entire memory range of this slice must be contained within a single [allocated object]! /// Slices can never span across multiple allocated objects. /// /// * The pointer must be aligned even for zero-length slices. One @@ -1282,6 +1264,7 @@ /// See also [`slice::from_raw_parts`][]. /// /// [valid]: crate::ptr#safety + /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> { @@ -1310,7 +1293,7 @@ /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()` /// many bytes, and it must be properly aligned. This means in particular: /// - /// * The entire memory range of this slice must be contained within a single allocated object! + /// * The entire memory range of this slice must be contained within a single [allocated object]! /// Slices can never span across multiple allocated objects. /// /// * The pointer must be aligned even for zero-length slices. One @@ -1332,6 +1315,7 @@ /// See also [`slice::from_raw_parts_mut`][]. /// /// [valid]: crate::ptr#safety + /// [allocated object]: crate::ptr#allocated-object #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]> {
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8d533cd..e525f61 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs
@@ -72,7 +72,7 @@ /// sentinel value. Types that lazily allocate must track initialization by /// some other means. #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.32.0")] + #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")] #[inline] pub const fn dangling() -> Self { // SAFETY: mem::align_of() returns a non-zero usize which is then casted @@ -110,7 +110,7 @@ /// [the module documentation]: crate::ptr#safety #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_ref(&self) -> &MaybeUninit<T> { + pub unsafe fn as_uninit_ref<'a>(&self) -> &'a MaybeUninit<T> { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &*self.cast().as_ptr() } @@ -142,7 +142,7 @@ /// [the module documentation]: crate::ptr#safety #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_mut(&mut self) -> &mut MaybeUninit<T> { + pub unsafe fn as_uninit_mut<'a>(&mut self) -> &'a mut MaybeUninit<T> { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &mut *self.cast().as_ptr() } @@ -156,7 +156,7 @@ /// /// `ptr` must be non-null. #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.32.0")] + #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")] #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { // SAFETY: the caller must guarantee that `ptr` is non-null. @@ -181,7 +181,6 @@ /// See the documentation of [`std::ptr::from_raw_parts`] for more details. /// /// [`std::ptr::from_raw_parts`]: crate::ptr::from_raw_parts - #[cfg(not(bootstrap))] #[unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] @@ -198,7 +197,6 @@ /// Decompose a (possibly wide) pointer into is address and metadata components. /// /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`]. - #[cfg(not(bootstrap))] #[unstable(feature = "ptr_metadata", issue = "81513")] #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] @@ -244,7 +242,7 @@ /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] - pub unsafe fn as_ref(&self) -> &T { + pub unsafe fn as_ref<'a>(&self) -> &'a T { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &*self.as_ptr() } @@ -280,7 +278,7 @@ /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { + pub unsafe fn as_mut<'a>(&mut self) -> &'a mut T { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a mutable reference. unsafe { &mut *self.as_ptr() } @@ -288,7 +286,7 @@ /// Casts to a pointer of another type. #[stable(feature = "nonnull_cast", since = "1.27.0")] - #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.32.0")] + #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.36.0")] #[inline] pub const fn cast<U>(self) -> NonNull<U> { // SAFETY: `self` is a `NonNull` pointer which is necessarily non-null @@ -427,7 +425,7 @@ /// [valid]: crate::ptr#safety #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_slice(&self) -> &[MaybeUninit<T>] { + pub unsafe fn as_uninit_slice<'a>(&self) -> &'a [MaybeUninit<T>] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) } } @@ -488,7 +486,7 @@ /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_slice_mut(&self) -> &mut [MaybeUninit<T>] { + pub unsafe fn as_uninit_slice_mut<'a>(&self) -> &'a mut [MaybeUninit<T>] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) } }
diff --git a/library/core/src/raw.rs b/library/core/src/raw.rs index 1227d9b..6d1e28f 100644 --- a/library/core/src/raw.rs +++ b/library/core/src/raw.rs
@@ -1,5 +1,9 @@ #![allow(missing_docs)] #![unstable(feature = "raw", issue = "27751")] +#![rustc_deprecated( + since = "1.53.0", + reason = "use pointer metadata APIs instead https://github.com/rust-lang/rust/issues/81513" +)] //! Contains struct definitions for the layout of compiler built-in types. //!
diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 2ce8a70..e0071f8 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs
@@ -228,7 +228,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; -use crate::ops::{self, Deref, DerefMut}; +use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). @@ -506,8 +506,8 @@ } } - /// Applies a function to the contained value (if [`Ok`]), - /// or returns the provided default (if [`Err`]). + /// Returns the provided default (if [`Err`]), or + /// applies a function to the contained value (if [`Ok`]), /// /// Arguments passed to `map_or` are eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`map_or_else`], @@ -533,9 +533,9 @@ } } - /// Maps a `Result<T, E>` to `U` by applying a function to a - /// contained [`Ok`] value, or a fallback function to a - /// contained [`Err`] value. + /// Maps a `Result<T, E>` to `U` by applying a fallback function to a + /// contained [`Err`] value, or a default function to a + /// contained [`Ok`] value. /// /// This function can be used to unpack a successful result /// while handling an error. @@ -1167,6 +1167,42 @@ } } +#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] +impl<T: Into<!>, E> Result<T, E> { + /// Returns the contained [`Err`] value, but never panics. + /// + /// Unlike [`unwrap_err`], this method is known to never panic on the + /// result types it is implemented for. Therefore, it can be used + /// instead of `unwrap_err` as a maintainability safeguard that will fail + /// to compile if the ok type of the `Result` is later changed + /// to a type that can actually occur. + /// + /// [`unwrap_err`]: Result::unwrap_err + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(never_type)] + /// # #![feature(unwrap_infallible)] + /// + /// fn only_bad_news() -> Result<!, String> { + /// Err("Oops, it failed".into()) + /// } + /// + /// let error: String = only_bad_news().into_err(); + /// println!("{}", error); + /// ``` + #[inline] + pub fn into_err(self) -> E { + match self { + Ok(x) => x.into(), + Err(e) => e, + } + } +} + impl<T: Deref, E> Result<T, E> { /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`. /// @@ -1610,3 +1646,32 @@ Err(v) } } + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E> ops::TryV2 for Result<T, E> { + type Output = T; + type Residual = Result<convert::Infallible, E>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + Ok(output) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + Ok(v) => ControlFlow::Continue(v), + Err(e) => ControlFlow::Break(Err(e)), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { + #[inline] + fn from_residual(residual: Result<convert::Infallible, E>) -> Self { + match residual { + Err(e) => Err(From::from(e)), + } + } +}
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 42032bc..906dcb1 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs
@@ -1,6 +1,10 @@ //! Operations on ASCII `[u8]`. +use crate::ascii; +use crate::fmt::{self, Write}; +use crate::iter; use crate::mem; +use crate::ops; #[lang = "slice_u8"] #[cfg(not(test))] @@ -19,7 +23,7 @@ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b)) } /// Converts this slice to its ASCII upper case equivalent in-place. @@ -55,6 +59,95 @@ byte.make_ascii_lowercase(); } } + + /// Returns an iterator that produces an escaped version of this slice, + /// treating it as an ASCII string. + /// + /// # Examples + /// + /// ``` + /// #![feature(inherent_ascii_escape)] + /// + /// let s = b"0\t\r\n'\"\\\x9d"; + /// let escaped = s.escape_ascii().to_string(); + /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); + /// ``` + #[unstable(feature = "inherent_ascii_escape", issue = "77174")] + pub fn escape_ascii(&self) -> EscapeAscii<'_> { + EscapeAscii { inner: self.iter().flat_map(EscapeByte) } + } +} + +impl_fn_for_zst! { + #[derive(Clone)] + struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault { + ascii::escape_default(*byte) + }; +} + +/// An iterator over the escaped version of a byte slice. +/// +/// This `struct` is created by the [`slice::escape_ascii`] method. See its +/// documentation for more information. +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +#[derive(Clone)] +pub struct EscapeAscii<'a> { + inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>, +} + +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> iter::Iterator for EscapeAscii<'a> { + type Item = u8; + #[inline] + fn next(&mut self) -> Option<u8> { + self.inner.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } + #[inline] + fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R + where + Fold: FnMut(Acc, Self::Item) -> R, + R: ops::Try<Ok = Acc>, + { + self.inner.try_fold(init, fold) + } + #[inline] + fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } + #[inline] + fn last(mut self) -> Option<u8> { + self.next_back() + } +} + +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> { + fn next_back(&mut self) -> Option<u8> { + self.inner.next_back() + } +} +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {} +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> iter::FusedIterator for EscapeAscii<'a> {} +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> fmt::Display for EscapeAscii<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.clone().try_for_each(|b| f.write_char(b as char)) + } +} +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +impl<'a> fmt::Debug for EscapeAscii<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EscapeAscii").finish_non_exhaustive() + } } /// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index c92b37b..f722430 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs
@@ -81,6 +81,8 @@ impl Sealed for ops::RangeInclusive<usize> {} #[stable(feature = "slice_get_slice", since = "1.28.0")] impl Sealed for ops::RangeToInclusive<usize> {} + #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] + impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {} } /// A helper trait used for indexing operations. @@ -546,3 +548,113 @@ ops::Range { start, end } } + +/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking +fn into_range_unchecked( + len: usize, + (start, end): (ops::Bound<usize>, ops::Bound<usize>), +) -> ops::Range<usize> { + use ops::Bound; + let start = match start { + Bound::Included(i) => i, + Bound::Excluded(i) => i + 1, + Bound::Unbounded => 0, + }; + let end = match end { + Bound::Included(i) => i + 1, + Bound::Excluded(i) => i, + Bound::Unbounded => len, + }; + start..end +} + +/// Convert pair of `ops::Bound`s into `ops::Range`. +/// Returns `None` on overflowing indices. +fn into_range( + len: usize, + (start, end): (ops::Bound<usize>, ops::Bound<usize>), +) -> Option<ops::Range<usize>> { + use ops::Bound; + let start = match start { + Bound::Included(start) => start, + Bound::Excluded(start) => start.checked_add(1)?, + Bound::Unbounded => 0, + }; + + let end = match end { + Bound::Included(end) => end.checked_add(1)?, + Bound::Excluded(end) => end, + Bound::Unbounded => len, + }; + + // Don't bother with checking `start < end` and `end <= len` + // since these checks are handled by `Range` impls + + Some(start..end) +} + +/// Convert pair of `ops::Bound`s into `ops::Range`. +/// Panics on overflowing indices. +fn into_slice_range( + len: usize, + (start, end): (ops::Bound<usize>, ops::Bound<usize>), +) -> ops::Range<usize> { + use ops::Bound; + let start = match start { + Bound::Included(start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(end) => end, + Bound::Unbounded => len, + }; + + // Don't bother with checking `start < end` and `end <= len` + // since these checks are handled by `Range` impls + + start..end +} + +#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] +unsafe impl<T> SliceIndex<[T]> for (ops::Bound<usize>, ops::Bound<usize>) { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&Self::Output> { + into_range(slice.len(), self)?.get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + into_range(slice.len(), self)?.get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { into_range_unchecked(slice.len(), self).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &Self::Output { + into_slice_range(slice.len(), self).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + into_slice_range(slice.len(), self).index_mut(slice) + } +}
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index c82b76d..1ee662c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs
@@ -286,7 +286,6 @@ /// Basic usage: /// /// ``` - /// # #![feature(slice_iter_mut_as_slice)] /// let mut slice: &mut [usize] = &mut [1, 2, 3]; /// /// // First, we get the iterator: @@ -299,12 +298,19 @@ /// // Now `as_slice` returns "[2, 3]": /// assert_eq!(iter.as_slice(), &[2, 3]); /// ``` - #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] pub fn as_slice(&self) -> &[T] { self.make_slice() } } +#[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] +impl<T> AsRef<[T]> for IterMut<'_, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} /// An internal abstraction over the splitting iterators, so that
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 417a106..ec28cdd 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs
@@ -81,6 +81,9 @@ #[unstable(feature = "slice_range", issue = "76393")] pub use index::range; +#[unstable(feature = "inherent_ascii_escape", issue = "77174")] +pub use ascii::EscapeAscii; + #[lang = "slice"] #[cfg(not(test))] impl<T> [T] { @@ -94,28 +97,19 @@ /// ``` #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] + #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) #[rustc_allow_const_fn_unstable(const_fn_union)] pub const fn len(&self) -> usize { - #[cfg(bootstrap)] - { - // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout. - // Only `std` can make this guarantee. - unsafe { crate::ptr::Repr { rust: self }.raw.len } - } - #[cfg(not(bootstrap))] - { - // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable. - // As of this writing this causes a "Const-stable functions can only call other - // const-stable functions" error. + // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable. + // As of this writing this causes a "Const-stable functions can only call other + // const-stable functions" error. - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents<T> have the same memory layouts. Only std can make this - // guarantee. - unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata } - } + // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T + // and PtrComponents<T> have the same memory layouts. Only std can make this + // guarantee. + unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata } } /// Returns `true` if the slice has a length of 0. @@ -127,7 +121,7 @@ /// assert!(!a.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.32.0")] + #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] #[inline] pub const fn is_empty(&self) -> bool { self.len() == 0 @@ -145,8 +139,9 @@ /// assert_eq!(None, w.first()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn first(&self) -> Option<&T> { + pub const fn first(&self) -> Option<&T> { if let [first, ..] = self { Some(first) } else { None } } @@ -163,8 +158,9 @@ /// assert_eq!(x, &[5, 1, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn first_mut(&mut self) -> Option<&mut T> { + pub const fn first_mut(&mut self) -> Option<&mut T> { if let [first, ..] = self { Some(first) } else { None } } @@ -181,8 +177,9 @@ /// } /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn split_first(&self) -> Option<(&T, &[T])> { + pub const fn split_first(&self) -> Option<(&T, &[T])> { if let [first, tail @ ..] = self { Some((first, tail)) } else { None } } @@ -201,8 +198,9 @@ /// assert_eq!(x, &[3, 4, 5]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { if let [first, tail @ ..] = self { Some((first, tail)) } else { None } } @@ -219,8 +217,9 @@ /// } /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn split_last(&self) -> Option<(&T, &[T])> { + pub const fn split_last(&self) -> Option<(&T, &[T])> { if let [init @ .., last] = self { Some((last, init)) } else { None } } @@ -239,8 +238,9 @@ /// assert_eq!(x, &[4, 5, 3]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { if let [init @ .., last] = self { Some((last, init)) } else { None } } @@ -256,8 +256,9 @@ /// assert_eq!(None, w.last()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn last(&self) -> Option<&T> { + pub const fn last(&self) -> Option<&T> { if let [.., last] = self { Some(last) } else { None } } @@ -274,8 +275,9 @@ /// assert_eq!(x, &[0, 1, 10]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] #[inline] - pub fn last_mut(&mut self) -> Option<&mut T> { + pub const fn last_mut(&mut self) -> Option<&mut T> { if let [.., last] = self { Some(last) } else { None } } @@ -2204,6 +2206,8 @@ } else if cmp == Greater { right = mid; } else { + // SAFETY: same as the `get_unchecked` above + unsafe { crate::intrinsics::assume(mid < self.len()) }; return Ok(mid); } @@ -2252,8 +2256,7 @@ // in crate `alloc`, and as such doesn't exists yet when building `core`. // links to downstream crate: #74481. Since primitives are only documented in // libstd (#73423), this never leads to broken links in practice. - #[cfg_attr(not(bootstrap), allow(rustdoc::broken_intra_doc_links))] - #[cfg_attr(bootstrap, allow(broken_intra_doc_links))] + #[allow(rustdoc::broken_intra_doc_links)] #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
diff --git a/library/core/src/slice/specialize.rs b/library/core/src/slice/specialize.rs index 16a9588..425cf71 100644 --- a/library/core/src/slice/specialize.rs +++ b/library/core/src/slice/specialize.rs
@@ -1,3 +1,4 @@ +use crate::mem::{size_of, transmute_copy}; use crate::ptr::write_bytes; pub(super) trait SpecFill<T> { @@ -17,42 +18,18 @@ } impl<T: Copy> SpecFill<T> for [T] { - default fn spec_fill(&mut self, value: T) { - for item in self.iter_mut() { - *item = value; - } - } -} - -impl SpecFill<u8> for [u8] { - fn spec_fill(&mut self, value: u8) { - // SAFETY: this is slice of u8 - unsafe { - let ptr = self.as_mut_ptr(); - let len = self.len(); - write_bytes(ptr, value, len); - } - } -} - -impl SpecFill<i8> for [i8] { - fn spec_fill(&mut self, value: i8) { - // SAFETY: this is slice of i8 - unsafe { - let ptr = self.as_mut_ptr(); - let len = self.len(); - write_bytes(ptr, value as u8, len); - } - } -} - -impl SpecFill<bool> for [bool] { - fn spec_fill(&mut self, value: bool) { - // SAFETY: this is slice of bool - unsafe { - let ptr = self.as_mut_ptr(); - let len = self.len(); - write_bytes(ptr, value as u8, len); + fn spec_fill(&mut self, value: T) { + if size_of::<T>() == 1 { + // SAFETY: The size_of check above ensures that values are 1 byte wide, as required + // for the transmute and write_bytes + unsafe { + let value: u8 = transmute_copy(&value); + write_bytes(self.as_mut_ptr(), value, self.len()); + } + } else { + for item in self.iter_mut() { + *item = value; + } } } }
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 4eac017..724137a 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs
@@ -189,6 +189,30 @@ pub fn as_str(&self) -> &'a str { self.iter.as_str() } + + /// Returns the byte position of the next character, or the length + /// of the underlying string if there are no more characters. + /// + /// # Examples + /// + /// ``` + /// #![feature(char_indices_offset)] + /// let mut chars = "a楽".char_indices(); + /// + /// assert_eq!(chars.offset(), 0); + /// assert_eq!(chars.next(), Some((0, 'a'))); + /// + /// assert_eq!(chars.offset(), 1); + /// assert_eq!(chars.next(), Some((1, '楽'))); + /// + /// assert_eq!(chars.offset(), 4); + /// assert_eq!(chars.next(), None); + /// ``` + #[inline] + #[unstable(feature = "char_indices_offset", issue = "83871")] + pub fn offset(&self) -> usize { + self.front_offset + } } /// An iterator over the bytes of a string slice. @@ -1359,7 +1383,7 @@ #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for EncodeUtf16<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") + f.debug_struct("EncodeUtf16").finish_non_exhaustive() } }
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 67c074b..95dd549 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs
@@ -15,7 +15,7 @@ use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; -use crate::char; +use crate::char::{self, EscapeDebugExtArgs}; use crate::mem; use crate::slice::{self, SliceIndex}; @@ -140,7 +140,7 @@ /// ``` #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_str_len", since = "1.32.0")] + #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] #[inline] pub const fn len(&self) -> usize { self.as_bytes().len() @@ -161,7 +161,7 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_str_is_empty", since = "1.32.0")] + #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -217,7 +217,7 @@ /// assert_eq!(b"bors", bytes); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "str_as_bytes", since = "1.39.0")] #[inline(always)] #[allow(unused_attributes)] #[rustc_allow_const_fn_unstable(const_fn_transmute)] @@ -2342,7 +2342,7 @@ EscapeDebug { inner: chars .next() - .map(|first| first.escape_debug_ext(true)) + .map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)) .into_iter() .flatten() .chain(chars.flat_map(CharEscapeDebugContinue)), @@ -2460,7 +2460,11 @@ #[derive(Clone)] struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { - c.escape_debug_ext(false) + c.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: false, + escape_single_quote: true, + escape_double_quote: true + }) }; #[derive(Clone)]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index ca39224..f1a1155 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs
@@ -78,7 +78,7 @@ //! ``` //! use std::sync::Arc; //! use std::sync::atomic::{AtomicUsize, Ordering}; -//! use std::thread; +//! use std::{hint, thread}; //! //! fn main() { //! let spinlock = Arc::new(AtomicUsize::new(1)); @@ -89,7 +89,9 @@ //! }); //! //! // Wait for the other thread to release the lock -//! while spinlock.load(Ordering::SeqCst) != 0 {} +//! while spinlock.load(Ordering::SeqCst) != 0 { +//! hint::spin_loop(); +//! } //! //! if let Err(panic) = thread.join() { //! println!("Thread had an error: {:?}", panic); @@ -283,7 +285,7 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_atomic_new", since = "1.32.0")] + #[rustc_const_stable(feature = "const_atomic_new", since = "1.24.0")] pub const fn new(v: bool) -> AtomicBool { AtomicBool { v: UnsafeCell::new(v as u8) } } @@ -837,7 +839,6 @@ /// # Examples /// /// ```rust - /// #![feature(atomic_fetch_update)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let x = AtomicBool::new(false); @@ -847,7 +848,7 @@ /// assert_eq!(x.load(Ordering::SeqCst), false); /// ``` #[inline] - #[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")] + #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "8")] pub fn fetch_update<F>( &self, @@ -883,7 +884,7 @@ /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_atomic_new", since = "1.32.0")] + #[rustc_const_stable(feature = "const_atomic_new", since = "1.24.0")] pub const fn new(p: *mut T) -> AtomicPtr<T> { AtomicPtr { p: UnsafeCell::new(p) } } @@ -898,8 +899,10 @@ /// ``` /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let mut atomic_ptr = AtomicPtr::new(&mut 10); - /// *atomic_ptr.get_mut() = &mut 5; + /// let mut data = 10; + /// let mut atomic_ptr = AtomicPtr::new(&mut data); + /// let mut other_data = 5; + /// *atomic_ptr.get_mut() = &mut other_data; /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5); /// ``` #[inline] @@ -916,9 +919,11 @@ /// #![feature(atomic_from_mut)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// - /// let mut some_ptr = &mut 123 as *mut i32; + /// let mut data = 123; + /// let mut some_ptr = &mut data as *mut i32; /// let a = AtomicPtr::from_mut(&mut some_ptr); - /// a.store(&mut 456, Ordering::Relaxed); + /// let mut other_data = 456; + /// a.store(&mut other_data, Ordering::Relaxed); /// assert_eq!(unsafe { *some_ptr }, 456); /// ``` #[inline] @@ -944,7 +949,8 @@ /// ``` /// use std::sync::atomic::AtomicPtr; /// - /// let atomic_ptr = AtomicPtr::new(&mut 5); + /// let mut data = 5; + /// let atomic_ptr = AtomicPtr::new(&mut data); /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5); /// ``` #[inline] @@ -1220,7 +1226,6 @@ /// # Examples /// /// ```rust - /// #![feature(atomic_fetch_update)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// /// let ptr: *mut _ = &mut 5; @@ -1239,7 +1244,7 @@ /// assert_eq!(some_ptr.load(Ordering::SeqCst), new); /// ``` #[inline] - #[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")] + #[stable(feature = "atomic_fetch_update", since = "1.53.0")] #[cfg(target_has_atomic = "ptr")] pub fn fetch_update<F>( &self, @@ -2276,7 +2281,7 @@ stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_integer_atomics", since = "1.24.0"), stable(feature = "rust1", since = "1.0.0"), "isize", "", @@ -2296,7 +2301,7 @@ stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), + rustc_const_stable(feature = "const_integer_atomics", since = "1.24.0"), stable(feature = "rust1", since = "1.0.0"), "usize", "",
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 42c9d9f..2765c21 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs
@@ -1,6 +1,7 @@ #![stable(feature = "futures_api", since = "1.36.0")] -use crate::ops::Try; +use crate::convert; +use crate::ops::{self, ControlFlow, Try}; use crate::result::Result; /// Indicates whether a value is available or if the current task has been @@ -152,6 +153,36 @@ } } +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E> ops::TryV2 for Poll<Result<T, E>> { + type Output = Poll<T>; + type Residual = Result<convert::Infallible, E>; + + #[inline] + fn from_output(c: Self::Output) -> Self { + c.map(Ok) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + Poll::Ready(Ok(x)) => ControlFlow::Continue(Poll::Ready(x)), + Poll::Ready(Err(e)) => ControlFlow::Break(Err(e)), + Poll::Pending => ControlFlow::Continue(Poll::Pending), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> { + #[inline] + fn from_residual(x: Result<convert::Infallible, E>) -> Self { + match x { + Err(e) => Poll::Ready(Err(From::from(e))), + } + } +} + #[stable(feature = "futures_api", since = "1.36.0")] impl<T, E> Try for Poll<Option<Result<T, E>>> { type Ok = Poll<Option<T>>; @@ -177,3 +208,36 @@ x.map(|x| x.map(Ok)) } } + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E> ops::TryV2 for Poll<Option<Result<T, E>>> { + type Output = Poll<Option<T>>; + type Residual = Result<convert::Infallible, E>; + + #[inline] + fn from_output(c: Self::Output) -> Self { + c.map(|x| x.map(Ok)) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + Poll::Ready(Some(Ok(x))) => ControlFlow::Continue(Poll::Ready(Some(x))), + Poll::Ready(Some(Err(e))) => ControlFlow::Break(Err(e)), + Poll::Ready(None) => ControlFlow::Continue(Poll::Ready(None)), + Poll::Pending => ControlFlow::Continue(Poll::Pending), + } + } +} + +#[unstable(feature = "try_trait_v2", issue = "84277")] +impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> + for Poll<Option<Result<T, F>>> +{ + #[inline] + fn from_residual(x: Result<convert::Infallible, E>) -> Self { + match x { + Err(e) => Poll::Ready(Some(Err(From::from(e)))), + } + } +}
diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 8c0848c..bfea39e 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs
@@ -124,29 +124,32 @@ /// # Examples /// /// ``` - /// #![feature(duration_zero)] /// use std::time::Duration; /// /// let duration = Duration::ZERO; /// assert!(duration.is_zero()); /// assert_eq!(duration.as_nanos(), 0); /// ``` - #[unstable(feature = "duration_zero", issue = "73544")] + #[stable(feature = "duration_zero", since = "1.53.0")] pub const ZERO: Duration = Duration::from_nanos(0); /// The maximum duration. /// - /// It is roughly equal to a duration of 584,942,417,355 years. + /// May vary by platform as necessary. Must be able to contain the difference between + /// two instances of [`Instant`] or two instances of [`SystemTime`]. + /// This constraint gives it a value of about 584,942,417,355 years in practice, + /// which is currently used on all platforms. /// /// # 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")] + /// [`Instant`]: ../../std/time/struct.Instant.html + /// [`SystemTime`]: ../../std/time/struct.SystemTime.html + #[stable(feature = "duration_saturating_ops", since = "1.53.0")] pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1); /// Creates a new `Duration` from the specified number of whole seconds and @@ -269,7 +272,6 @@ /// # Examples /// /// ``` - /// #![feature(duration_zero)] /// use std::time::Duration; /// /// assert!(Duration::ZERO.is_zero()); @@ -281,7 +283,8 @@ /// assert!(!Duration::from_nanos(1).is_zero()); /// assert!(!Duration::from_secs(1).is_zero()); /// ``` - #[unstable(feature = "duration_zero", issue = "73544")] + #[stable(feature = "duration_zero", since = "1.53.0")] + #[rustc_const_stable(feature = "duration_zero", since = "1.53.0")] #[inline] pub const fn is_zero(&self) -> bool { self.secs == 0 && self.nanos == 0 @@ -479,14 +482,13 @@ /// # 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")] + #[stable(feature = "duration_saturating_ops", since = "1.53.0")] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_add(self, rhs: Duration) -> Duration { @@ -537,14 +539,12 @@ /// # Examples /// /// ``` - /// #![feature(duration_saturating_ops)] - /// #![feature(duration_zero)] /// 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::ZERO); /// ``` - #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[stable(feature = "duration_saturating_ops", since = "1.53.0")] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_sub(self, rhs: Duration) -> Duration { @@ -590,14 +590,13 @@ /// # 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")] + #[stable(feature = "duration_saturating_ops", since = "1.53.0")] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn saturating_mul(self, rhs: u32) -> Duration {
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 89c2a96..ce7480c 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs
@@ -1,25 +1,7 @@ -use core::array::{self, FixedSizeArray, IntoIter}; +use core::array::{self, IntoIter}; use core::convert::TryFrom; #[test] -fn fixed_size_array() { - let mut array = [0; 64]; - let mut zero_sized = [(); 64]; - let mut empty_array = [0; 0]; - let mut empty_zero_sized = [(); 0]; - - assert_eq!(FixedSizeArray::as_slice(&array).len(), 64); - assert_eq!(FixedSizeArray::as_slice(&zero_sized).len(), 64); - assert_eq!(FixedSizeArray::as_slice(&empty_array).len(), 0); - assert_eq!(FixedSizeArray::as_slice(&empty_zero_sized).len(), 0); - - assert_eq!(FixedSizeArray::as_mut_slice(&mut array).len(), 64); - assert_eq!(FixedSizeArray::as_mut_slice(&mut zero_sized).len(), 64); - assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0); - assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0); -} - -#[test] fn array_from_ref() { let value: String = "Hello World!".into(); let arr: &[String; 1] = array::from_ref(&value);
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 4158a4d..4acd059 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs
@@ -49,53 +49,3 @@ const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); } - -//#[test] -//fn write() { -// use core::ptr; -// -// const fn write_aligned() -> i32 { -// let mut res = 0; -// unsafe { -// ptr::write(&mut res as *mut _, 42); -// } -// res -// } -// const ALIGNED: i32 = write_aligned(); -// assert_eq!(ALIGNED, 42); -// -// const fn write_unaligned() -> [u16; 2] { -// let mut two_aligned = [0u16; 2]; -// unsafe { -// let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; -// ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); -// } -// two_aligned -// } -// const UNALIGNED: [u16; 2] = write_unaligned(); -// assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -//} - -//#[test] -//fn mut_ptr_write() { -// const fn aligned() -> i32 { -// let mut res = 0; -// unsafe { -// (&mut res as *mut i32).write(42); -// } -// res -// } -// const ALIGNED: i32 = aligned(); -// assert_eq!(ALIGNED, 42); -// -// const fn write_unaligned() -> [u16; 2] { -// let mut two_aligned = [0u16; 2]; -// unsafe { -// let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; -// unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); -// } -// two_aligned -// } -// const UNALIGNED: [u16; 2] = write_unaligned(); -// assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -//}
diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs index 129c121..7580010 100644 --- a/library/core/tests/fmt/builders.rs +++ b/library/core/tests/fmt/builders.rs
@@ -105,12 +105,7 @@ } assert_eq!("Foo { .. }", format!("{:?}", Foo)); - assert_eq!( - "Foo { - .. -}", - format!("{:#?}", Foo) - ); + assert_eq!("Foo { .. }", format!("{:#?}", Foo)); } #[test]
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs index ca5ae12..4cd7968 100644 --- a/library/core/tests/iter/adapters/chain.rs +++ b/library/core/tests/iter/adapters/chain.rs
@@ -174,14 +174,14 @@ fn test_iterator_chain_unfused() { // Chain shouldn't be fused in its second iterator, depending on direction let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true }); - iter.next().unwrap_none(); - iter.next().unwrap(); - iter.next().unwrap_none(); + assert!(iter.next().is_none()); + assert!(iter.next().is_some()); + assert!(iter.next().is_none()); let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty())); - iter.next_back().unwrap_none(); - iter.next_back().unwrap(); - iter.next_back().unwrap_none(); + assert!(iter.next_back().is_none()); + assert!(iter.next_back().is_some()); + assert!(iter.next_back().is_none()); } #[test]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b7fcc74..35e4d21 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs
@@ -1,6 +1,5 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] -#![feature(array_from_ref)] #![feature(array_methods)] #![feature(array_map)] #![feature(array_windows)] @@ -20,16 +19,12 @@ #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] -#![feature(debug_non_exhaustive)] #![feature(dec2flt)] #![feature(div_duration)] #![feature(duration_consts_2)] #![feature(duration_constants)] -#![feature(duration_saturating_ops)] -#![feature(duration_zero)] #![feature(exact_size_is_empty)] #![feature(extern_types)] -#![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] @@ -58,7 +53,6 @@ #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] -#![feature(cmp_min_max_by)] #![feature(iter_map_while)] #![feature(const_mut_refs)] #![feature(const_pin)] @@ -68,19 +62,14 @@ #![feature(unwrap_infallible)] #![feature(option_result_unwrap_unchecked)] #![feature(result_into_ok_or_err)] -#![feature(option_unwrap_none)] -#![feature(peekable_peek_mut)] -#![cfg_attr(not(bootstrap), feature(ptr_metadata))] +#![feature(ptr_metadata)] #![feature(once_cell)] #![feature(unsized_tuple_coercion)] -#![feature(int_bits_const)] -#![feature(nonzero_leading_trailing_zeros)] #![feature(const_option)] #![feature(integer_atomics)] #![feature(slice_group_by)] #![feature(trusted_random_access)] -#![cfg_attr(bootstrap, feature(unsafe_block_in_unsafe_fn))] -#![cfg_attr(not(bootstrap), feature(unsize))] +#![feature(unsize)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test;
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index c0b7503..dfdbc93 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs
@@ -97,6 +97,9 @@ assert_eq!(1, unsafe { transmute_copy(&1) }); } +// Remove this test when `std::raw` is removed. +// The replacement pointer metadata APIs are tested in library/core/tests/ptr.rs +#[allow(deprecated)] #[test] fn test_transmute() { trait Foo {
diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index 8e95249..960a7ca 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs
@@ -514,51 +514,38 @@ let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 0), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3.14"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3.14"); assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3.14"); assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); @@ -615,68 +602,48 @@ let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, (-4, 16), false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0"); assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, (0, 0), false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, (5, 9), false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, (0, 0), false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, (5, 9), false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, (-4, 16), true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, (-4, 16), true), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, (0, 0), true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (-9, -5), false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, (5, 9), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, (0, 0), true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (-9, -5), false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, (5, 9), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf"); assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, (-4, 16), false), "3.14"); assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, (-4, 16), false), "+3.14"); assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, (-4, 16), false), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, (-4, 16), false), "-3.14"); assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, (0, 0), false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, (-9, -5), true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, (5, 9), false), "+3.14e0"); + assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0"); assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, (0, 0), false), "-3.14e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, (-9, -5), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, (5, 9), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0"); assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, MinusRaw, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, (-4, 16), false), "+0.1"); assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusRaw, (-4, 16), false), "-0.1"); assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusPlusRaw, (-4, 16), false), "-0.1"); assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); - assert_eq!(to_string(f, 0.1, MinusRaw, (0, 0), false), "1e-1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (-9, -5), true), "+1E-1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, (5, 9), false), "+1e-1"); + assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1"); assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusRaw, (0, 0), false), "-1e-1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (-9, -5), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusPlusRaw, (5, 9), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1"); assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); @@ -734,68 +701,51 @@ let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 1, false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 1, true), "+0E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 1, false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0"); assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 2, false), "0.0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 2, true), "+0.0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 2, false), "+0.0e0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.0000000E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, false), "-0.0000000e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.0000000E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0"); + assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1, true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 1, true), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 8, true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 64, true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 1, false), "3e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 1, true), "+3E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 1, false), "+3e0"); + assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0"); assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 2, false), "-3.1e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0"); assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 3, false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 3, false), "+3.14e0"); + assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0"); assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 4, false), "-3.140e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0"); assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 1, true), "2E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 1, false), "+2e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 1, true), "+2E-1"); + assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1"); assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1"); assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 3, true), "1.95E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, false), "+1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 3, true), "+1.95E-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1"); assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 4, true), "-1.950E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1"); assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); @@ -1007,68 +957,48 @@ let f = &mut f_; assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 8), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 64), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf"); assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); assert_eq!(to_string(f, 3.14, Minus, 0), "3"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3"); assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3"); assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3"); assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); assert_eq!(to_string(f, 0.195, Minus, 0), "0"); - assert_eq!(to_string(f, 0.195, MinusRaw, 0), "0"); assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0), "+0"); assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.195, MinusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0), "-0"); assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); - assert_eq!(to_string(f, 0.195, MinusRaw, 2), "0.20"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3), "+0.195"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4), "+0.1950"); + assert_eq!(to_string(f, 0.195, Minus, 2), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950"); assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); - assert_eq!(to_string(f, -0.195, MinusRaw, 6), "-0.195000"); - assert_eq!(to_string(f, -0.195, MinusPlus, 7), "-0.1950000"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8), "-0.19500000"); + assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000"); assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); assert_eq!(to_string(f, 999.5, Minus, 1), "999.5");
diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs new file mode 100644 index 0000000..f6e5dfc --- /dev/null +++ b/library/core/tests/num/ieee754.rs
@@ -0,0 +1,158 @@ +//! IEEE 754 floating point compliance tests +//! +//! To understand IEEE 754's requirements on a programming language, one must understand that the +//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any +//! one component. That means the hardware, language, and even libraries are considered part of +//! conforming floating point support in a programming environment. +//! +//! A programming language's duty, accordingly, is: +//! 1. offer access to the hardware where the hardware offers support +//! 2. provide operations that fulfill the remaining requirements of the standard +//! 3. provide the ability to write additional software that can fulfill those requirements +//! +//! This may be fulfilled in any combination that the language sees fit. However, to claim that +//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without +//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined +//! as complete support for at least one specified floating point type as an "arithmetic" and +//! "interchange" format, plus specified type conversions to "external character sequences" and +//! integer types. +//! +//! For our purposes, +//! "interchange format" => f32, f64 +//! "arithmetic format" => f32, f64, and any "soft floats" +//! "external character sequence" => str from any float +//! "integer format" => {i,u}{8,16,32,64,128} +//! +//! None of these tests are against Rust's own implementation. They are only tests against the +//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. +//! Please consider this carefully when adding, removing, or reorganizing these tests. They are +//! here so that it is clear what tests are required by the standard and what can be changed. +use ::core::str::FromStr; + +// IEEE 754 for many tests is applied to specific bit patterns. +// These generally are not applicable to NaN, however. +macro_rules! assert_biteq { + ($lhs:expr, $rhs:expr) => { + assert_eq!($lhs.to_bits(), $rhs.to_bits()) + }; +} + +// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts +// of the formatting infrastructure, which makes it ideal for testing here. +#[allow(unused_macros)] +macro_rules! roundtrip { + ($f:expr => $t:ty) => { + ($f).to_string().parse::<$t>().unwrap() + }; +} + +macro_rules! assert_floats_roundtrip { + ($f:ident) => { + assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); + assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); + }; + ($f:expr) => { + assert_biteq!($f as f32, roundtrip!($f => f32)); + assert_biteq!($f as f64, roundtrip!($f => f64)); + } +} + +macro_rules! assert_floats_bitne { + ($lhs:ident, $rhs:ident) => { + assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); + assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); + }; + ($lhs:expr, $rhs:expr) => { + assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); + assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); + }; +} + +// We must preserve signs on all numbers. That includes zero. +// -0 and 0 are == normally, so test bit equality. +#[test] +fn preserve_signed_zero() { + assert_floats_roundtrip!(-0.0); + assert_floats_roundtrip!(0.0); + assert_floats_bitne!(0.0, -0.0); +} + +#[test] +fn preserve_signed_infinity() { + assert_floats_roundtrip!(INFINITY); + assert_floats_roundtrip!(NEG_INFINITY); + assert_floats_bitne!(INFINITY, NEG_INFINITY); +} + +#[test] +fn infinity_to_str() { + assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }); + assert!( + match f64::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }, + "Infinity must write to a string as some casing of inf or infinity, with an optional +." + ); +} + +#[test] +fn neg_infinity_to_str() { + assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }); + assert!( + match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }, + "Negative Infinity must write to a string as some casing of -inf or -infinity" + ) +} + +#[test] +fn nan_to_str() { + assert!( + match f32::NAN.to_string().to_lowercase().as_str() { + "nan" | "+nan" | "-nan" => true, + _ => false, + }, + "NaNs must write to a string as some casing of nan." + ) +} + +// "+"?("inf"|"infinity") in any case => Infinity +#[test] +fn infinity_from_str() { + assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); + // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd + assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); +} + +// "-inf"|"-infinity" in any case => Negative Infinity +#[test] +fn neg_infinity_from_str() { + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); +} + +// ("+"|"-"")?"s"?"nan" in any case => qNaN +#[test] +fn qnan_from_str() { + assert!("nan".parse::<f32>().unwrap().is_nan()); + assert!("-nan".parse::<f32>().unwrap().is_nan()); + assert!("+nan".parse::<f32>().unwrap().is_nan()); + assert!("+NAN".parse::<f32>().unwrap().is_nan()); + assert!("-NaN".parse::<f32>().unwrap().is_nan()); +}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index e66a73a..bbb6766 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs
@@ -32,6 +32,7 @@ mod ops; mod wrapping; +mod ieee754; mod nan; /// Adds the attribute to all items in the block.
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 224a58e..11af809 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs
@@ -1,8 +1,6 @@ use core::cell::RefCell; -#[cfg(not(bootstrap))] use core::ptr; use core::ptr::*; -#[cfg(not(bootstrap))] use std::fmt::{Debug, Display}; #[test] @@ -419,7 +417,6 @@ } #[test] -#[cfg(not(bootstrap))] fn ptr_metadata() { struct Unit; struct Pair<A, B: ?Sized>(A, B); @@ -478,7 +475,6 @@ } #[test] -#[cfg(not(bootstrap))] fn ptr_metadata_bounds() { fn metadata_eq_method_address<T: ?Sized>() -> usize { // The `Metadata` associated type has an `Ord` bound, so this is valid: @@ -510,7 +506,6 @@ } #[test] -#[cfg(not(bootstrap))] fn dyn_metadata() { #[derive(Debug)] #[repr(align(32))] @@ -530,7 +525,6 @@ } #[test] -#[cfg(not(bootstrap))] fn from_raw_parts() { let mut value = 5_u32; let address = &mut value as *mut _ as *mut (); @@ -557,7 +551,6 @@ } #[test] -#[cfg(not(bootstrap))] fn thin_box() { let foo = ThinBox::<dyn Display>::new(4); assert_eq!(foo.to_string(), "4");
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 5fcd7b4..c461ab3 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs
@@ -226,6 +226,28 @@ } #[test] +pub fn test_into_err() { + fn until_error_op() -> Result<!, isize> { + Err(666) + } + + assert_eq!(until_error_op().into_err(), 666); + + enum MyNeverToken {} + impl From<MyNeverToken> for ! { + fn from(never: MyNeverToken) -> ! { + match never {} + } + } + + fn until_error_op2() -> Result<MyNeverToken, isize> { + Err(667) + } + + assert_eq!(until_error_op2().into_err(), 667); +} + +#[test] fn test_try() { fn try_result_some() -> Option<u8> { let val = Ok(1)?;
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 7e19863..3a98cd9 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs
@@ -1280,6 +1280,9 @@ } )*) => {$( mod $case_name { + #[allow(unused_imports)] + use core::ops::Bound; + #[test] fn pass() { let mut v = $data; @@ -1376,6 +1379,24 @@ bad: data[7..=6]; message: "out of range"; } + + in mod boundpair_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[(Bound::Included(6), Bound::Unbounded)] == []; + good: data[(Bound::Unbounded, Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Unbounded, Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(0), Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(0), Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(2), Bound::Excluded(4))] == [2, 3]; + good: data[(Bound::Excluded(1), Bound::Included(4))] == [2, 3, 4]; + good: data[(Bound::Excluded(5), Bound::Excluded(6))] == []; + good: data[(Bound::Included(6), Bound::Excluded(6))] == []; + good: data[(Bound::Excluded(5), Bound::Included(5))] == []; + good: data[(Bound::Included(6), Bound::Included(5))] == []; + bad: data[(Bound::Unbounded, Bound::Included(6))]; + message: "out of range"; + } } panic_cases! { @@ -1416,6 +1437,14 @@ bad: data[4..=2]; message: "but ends at"; } + + in mod boundpair_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[(Bound::Included(4), Bound::Excluded(4))] == []; + bad: data[(Bound::Included(4), Bound::Excluded(3))]; + message: "but ends at"; + } } panic_cases! { @@ -1434,6 +1463,20 @@ bad: data[..= usize::MAX]; message: "maximum usize"; } + + in mod boundpair_overflow_end { + data: [0; 1]; + + bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))]; + message: "maximum usize"; + } + + in mod boundpair_overflow_start { + data: [0; 1]; + + bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)]; + message: "maximum usize"; + } } // panic_cases! }