diff options
Diffstat (limited to 'library/core')
96 files changed, 3562 insertions, 1393 deletions
diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs index 19864d2d4..3c01e2998 100644 --- a/library/core/benches/num/int_log/mod.rs +++ b/library/core/benches/num/int_log/mod.rs @@ -9,7 +9,7 @@ macro_rules! int_log_bench { for n in 0..(<$t>::BITS / 8) { for i in 1..=(100 as $t) { let x = black_box(i << (n * 8)); - black_box(x.log10()); + black_box(x.ilog10()); } } }); @@ -27,7 +27,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } @@ -44,7 +44,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 887246c60..6756eecd0 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -74,7 +74,7 @@ use crate::ptr; /// { /// return null_mut(); /// }; -/// (self.arena.get() as *mut u8).add(allocated) +/// self.arena.get().cast::<u8>().add(allocated) /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2f378836c..f03502429 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -1,4 +1,12 @@ +// Seemingly inconsequential code changes to this file can lead to measurable +// performance impact on compilation times, due at least in part to the fact +// that the layout code gets called from many instantiations of the various +// collections, resulting in having to optimize down excess IR multiple times. +// Your performance intuition is useless. Run perf. + use crate::cmp; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::mem::{self, ValidAlign}; use crate::ptr::NonNull; @@ -52,8 +60,8 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e., the rounded value must be less than - /// or equal to `usize::MAX`). + /// must not overflow isize (i.e., the rounded value must be + /// less than or equal to `isize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] @@ -62,6 +70,12 @@ impl Layout { return Err(LayoutError); } + // SAFETY: just checked that align is a power of two. + Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) }) + } + + #[inline(always)] + const fn max_size_for_align(align: ValidAlign) -> usize { // (power-of-two implies align != 0.) // Rounded up size is: @@ -76,13 +90,18 @@ impl Layout { // // Above implies that checking for summation overflow is both // necessary and sufficient. - if size > usize::MAX - (align - 1) { + isize::MAX as usize - (align.as_usize() - 1) + } + + /// Internal helper constructor to skip revalidating alignment validity. + #[inline] + const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> { + if size > Self::max_size_for_align(align) { return Err(LayoutError); } - // SAFETY: the conditions for `from_size_align_unchecked` have been - // checked above. - unsafe { Ok(Layout::from_size_align_unchecked(size, align)) } + // SAFETY: Layout::size invariants checked above. + Ok(Layout { size, align }) } /// Creates a layout, bypassing all checks. @@ -96,8 +115,8 @@ impl Layout { #[must_use] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - // SAFETY: the caller must ensure that `align` is a power of two. - Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } } + // SAFETY: the caller is required to uphold the preconditions. + unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } } } /// The minimum size in bytes for a memory block of this layout. @@ -116,7 +135,7 @@ impl Layout { without modifying the layout"] #[inline] pub const fn align(&self) -> usize { - self.align.as_nonzero().get() + self.align.as_usize() } /// Constructs a `Layout` suitable for holding a value of type `T`. @@ -126,10 +145,9 @@ impl Layout { #[inline] pub const fn new<T>() -> Self { let (size, align) = size_align::<T>(); - // SAFETY: the align is guaranteed by Rust to be a power of two and - // the size+align combo is guaranteed to fit in our address space. As a - // result use the unchecked constructor here to avoid inserting code - // that panics if it isn't optimized well enough. + // SAFETY: if the type is instantiated, rustc already ensures that its + // layout is valid. Use the unchecked constructor to avoid inserting a + // panicking codepath that needs to be optimized out. unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -141,7 +159,6 @@ impl Layout { #[inline] pub fn for_value<T: ?Sized>(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -176,7 +193,6 @@ impl Layout { pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -276,12 +292,11 @@ impl Layout { let pad = self.padding_needed_for(self.align()); // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let new_size = self.size() + pad; - // SAFETY: self.align is already known to be valid and new_size has been - // padded already. + // SAFETY: padded size is guaranteed to not exceed `isize::MAX`. unsafe { Layout::from_size_align_unchecked(new_size, self.align()) } } @@ -298,14 +313,13 @@ impl Layout { pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; - // SAFETY: self.align is already known to be valid and alloc_size has been - // padded already. - unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) } + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -356,13 +370,14 @@ impl Layout { #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { - let new_align = cmp::max(self.align(), next.align()); + let new_align = cmp::max(self.align, next.align); let pad = self.padding_needed_for(next.align()); let offset = self.size().checked_add(pad).ok_or(LayoutError)?; let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?; - let layout = Layout::from_size_align(new_size, new_align)?; + // The safe constructor is called here to enforce the isize size limit. + let layout = Layout::from_size_valid_align(new_size, new_align)?; Ok((layout, offset)) } @@ -382,7 +397,8 @@ impl Layout { #[inline] pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> { let size = self.size().checked_mul(n).ok_or(LayoutError)?; - Layout::from_size_align(size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(size, self.align) } /// Creates a layout describing the record for `self` followed by @@ -395,26 +411,39 @@ impl Layout { #[inline] pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> { let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; - Layout::from_size_align(new_size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(new_size, self.align) } /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `LayoutError`. + /// On arithmetic overflow or when the total size would exceed + /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn array<T>(n: usize) -> Result<Self, LayoutError> { - let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?; - - // SAFETY: - // - Size: `array_size` cannot be too big because `size_of::<T>()` must - // be a multiple of `align_of::<T>()`. Therefore, `array_size` - // rounded up to the nearest multiple of `align_of::<T>()` is just - // `array_size`. And `array_size` cannot be too big because it was - // just checked by the `checked_mul()`. - // - Alignment: `align_of::<T>()` will always give an acceptable - // (non-zero, power of two) alignment. - Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) }) + // Reduce the amount of code we need to monomorphize per `T`. + return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n); + + #[inline] + fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> { + // We need to check two things about the size: + // - That the total size won't overflow a `usize`, and + // - That the total size still fits in an `isize`. + // By using division we can check them both with a single threshold. + // That'd usually be a bad idea, but thankfully here the element size + // and alignment are constants, so the compiler will fold all of it. + if element_size != 0 && n > Layout::max_size_for_align(align) / element_size { + return Err(LayoutError); + } + + let array_size = element_size * n; + + // SAFETY: We just checked above that the `array_size` will not + // exceed `isize::MAX` even when rounded up to the alignment. + // And `ValidAlign` guarantees it's a power of two. + unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) } + } } } @@ -434,6 +463,10 @@ pub type LayoutErr = LayoutError; #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutError; +#[cfg(not(bootstrap))] +#[stable(feature = "alloc_layout", since = "1.28.0")] +impl Error for LayoutError {} + // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutError { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6cc6e359e..94efa7666 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -21,6 +21,8 @@ pub use self::layout::LayoutErr; #[stable(feature = "alloc_layout_error", since = "1.50.0")] pub use self::layout::LayoutError; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::ptr::{self, NonNull}; @@ -32,6 +34,14 @@ use crate::ptr::{self, NonNull}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; +#[cfg(not(bootstrap))] +#[unstable( + feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838" +)] +impl Error for AllocError {} + // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocError { diff --git a/library/core/src/any.rs b/library/core/src/any.rs index f20c497a1..1a379ecc1 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -1,7 +1,4 @@ -//! This module contains the `Any` trait, which enables dynamic typing -//! of any `'static` type through runtime reflection. It also contains the -//! `Provider` trait and accompanying API, which enable trait objects to provide -//! data based on typed requests, an alternate form of runtime reflection. +//! Utilities for dynamic typing or type reflection. //! //! # `Any` and `TypeId` //! @@ -799,7 +796,7 @@ pub trait Provider { /// impl Provider for SomeConcreteType { /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { /// demand.provide_ref::<str>(&self.field) - /// .provide_value::<i32>(|| self.num_field); + /// .provide_value::<i32>(self.num_field); /// } /// } /// ``` @@ -884,28 +881,55 @@ impl<'a> Demand<'a> { /// /// # Examples /// + /// Provides an `u8`. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// # struct SomeConcreteType { field: u8 } + /// + /// impl Provider for SomeConcreteType { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand.provide_value::<u8>(self.field); + /// } + /// } + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn provide_value<T>(&mut self, value: T) -> &mut Self + where + T: 'static, + { + self.provide::<tags::Value<T>>(value) + } + + /// Provide a value or other type with only static lifetimes computed using a closure. + /// + /// # Examples + /// /// Provides a `String` by cloning. /// /// ```rust - /// # #![feature(provide_any)] + /// #![feature(provide_any)] + /// /// use std::any::{Provider, Demand}; /// # struct SomeConcreteType { field: String } /// /// impl Provider for SomeConcreteType { /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { - /// demand.provide_value::<String>(|| self.field.clone()); + /// demand.provide_value_with::<String>(|| self.field.clone()); /// } /// } /// ``` #[unstable(feature = "provide_any", issue = "96024")] - pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self + pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self where T: 'static, { self.provide_with::<tags::Value<T>>(fulfil) } - /// Provide a reference, note that the referee type must be bounded by `'static`, + /// Provide a reference. The referee type must be bounded by `'static`, /// but may be unsized. /// /// # Examples @@ -913,7 +937,8 @@ impl<'a> Demand<'a> { /// Provides a reference to a field as a `&str`. /// /// ```rust - /// # #![feature(provide_any)] + /// #![feature(provide_any)] + /// /// use std::any::{Provider, Demand}; /// # struct SomeConcreteType { field: String } /// @@ -928,6 +953,40 @@ impl<'a> Demand<'a> { self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value) } + /// Provide a reference computed using a closure. The referee type + /// must be bounded by `'static`, but may be unsized. + /// + /// # Examples + /// + /// Provides a reference to a field as a `&str`. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// # struct SomeConcreteType { business: String, party: String } + /// # fn today_is_a_weekday() -> bool { true } + /// + /// impl Provider for SomeConcreteType { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand.provide_ref_with::<str>(|| { + /// if today_is_a_weekday() { + /// &self.business + /// } else { + /// &self.party + /// } + /// }); + /// } + /// } + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn provide_ref_with<T: ?Sized + 'static>( + &mut self, + fulfil: impl FnOnce() -> &'a T, + ) -> &mut Self { + self.provide_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil) + } + /// Provide a value with the given `Type` tag. fn provide<I>(&mut self, value: I::Reified) -> &mut Self where @@ -949,6 +1008,156 @@ impl<'a> Demand<'a> { } self } + + /// Check if the `Demand` would be satisfied if provided with a + /// value of the specified type. If the type does not match or has + /// already been provided, returns false. + /// + /// # Examples + /// + /// Check if an `u8` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// + /// struct Parent(Option<u8>); + /// + /// impl Provider for Parent { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// if let Some(v) = self.0 { + /// demand.provide_value::<u8>(v); + /// } + /// } + /// } + /// + /// struct Child { + /// parent: Parent, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option<u8> { + /// Some(99) + /// } + /// } + /// + /// impl Provider for Child { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// // In general, we don't know if this call will provide + /// // an `u8` value or not... + /// self.parent.provide(demand); + /// + /// // ...so we check to see if the `u8` is needed before + /// // we run our expensive computation. + /// if demand.would_be_satisfied_by_value_of::<u8>() { + /// if let Some(v) = self.an_expensive_computation() { + /// demand.provide_value::<u8>(v); + /// } + /// } + /// + /// // The demand will be satisfied now, regardless of if + /// // the parent provided the value or we did. + /// assert!(!demand.would_be_satisfied_by_value_of::<u8>()); + /// } + /// } + /// + /// let parent = Parent(Some(42)); + /// let child = Child { parent }; + /// assert_eq!(Some(42), std::any::request_value::<u8>(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent }; + /// assert_eq!(Some(99), std::any::request_value::<u8>(&child)); + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn would_be_satisfied_by_value_of<T>(&self) -> bool + where + T: 'static, + { + self.would_be_satisfied_by::<tags::Value<T>>() + } + + /// Check if the `Demand` would be satisfied if provided with a + /// reference to a value of the specified type. If the type does + /// not match or has already been provided, returns false. + /// + /// # Examples + /// + /// Check if a `&str` still needs to be provided and then provides + /// it. + /// + /// ```rust + /// #![feature(provide_any)] + /// + /// use std::any::{Provider, Demand}; + /// + /// struct Parent(Option<String>); + /// + /// impl Provider for Parent { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// if let Some(v) = &self.0 { + /// demand.provide_ref::<str>(v); + /// } + /// } + /// } + /// + /// struct Child { + /// parent: Parent, + /// name: String, + /// } + /// + /// impl Child { + /// // Pretend that this takes a lot of resources to evaluate. + /// fn an_expensive_computation(&self) -> Option<&str> { + /// Some(&self.name) + /// } + /// } + /// + /// impl Provider for Child { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// // In general, we don't know if this call will provide + /// // a `str` reference or not... + /// self.parent.provide(demand); + /// + /// // ...so we check to see if the `&str` is needed before + /// // we run our expensive computation. + /// if demand.would_be_satisfied_by_ref_of::<str>() { + /// if let Some(v) = self.an_expensive_computation() { + /// demand.provide_ref::<str>(v); + /// } + /// } + /// + /// // The demand will be satisfied now, regardless of if + /// // the parent provided the reference or we did. + /// assert!(!demand.would_be_satisfied_by_ref_of::<str>()); + /// } + /// } + /// + /// let parent = Parent(Some("parent".into())); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("parent"), std::any::request_ref::<str>(&child)); + /// + /// let parent = Parent(None); + /// let child = Child { parent, name: "child".into() }; + /// assert_eq!(Some("child"), std::any::request_ref::<str>(&child)); + /// ``` + #[unstable(feature = "provide_any", issue = "96024")] + pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool + where + T: ?Sized + 'static, + { + self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>() + } + + fn would_be_satisfied_by<I>(&self) -> bool + where + I: tags::Type<'a>, + { + matches!(self.0.downcast::<I>(), Some(TaggedOption(None))) + } } #[unstable(feature = "provide_any", issue = "96024")] @@ -1053,6 +1262,21 @@ impl<'a> dyn Erased<'a> + 'a { /// Returns some reference to the dynamic value if it is tagged with `I`, /// or `None` otherwise. #[inline] + fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>> + where + I: tags::Type<'a>, + { + if self.tag_id() == TypeId::of::<I>() { + // SAFETY: Just checked whether we're pointing to an I. + Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() }) + } else { + None + } + } + + /// Returns some mutable reference to the dynamic value if it is tagged with `I`, + /// or `None` otherwise. + #[inline] fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>> where I: tags::Type<'a>, diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 33f7f494e..b2c895f88 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable { )+}; } -// SAFETY: All the ordinary integer types allow all bit patterns as distinct values +// SAFETY: All the ordinary integer types have no padding, and are not pointers. is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -// SAFETY: bool and char have *niches*, but no *padding*, so this is sound +// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this +// is sound is_raw_eq_comparable!(bool, char); -// SAFETY: Similarly, the non-zero types have a niche, but no undef, +// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, // and they compare like their underlying numeric type. is_raw_eq_comparable!( NonZeroU8, diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c9823a136..9effb3790 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -1,4 +1,4 @@ -//! Helper functions and types for fixed-length arrays. +//! Utilities for the array primitive type. //! //! *[See also the array primitive type](array).* @@ -7,6 +7,8 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; @@ -119,6 +121,15 @@ impl fmt::Display for TryFromSliceError { } } +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromSliceError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + impl TryFromSliceError { #[unstable( feature = "array_error_internals", diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index f7a8aa0d9..7667a6508 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -6,6 +6,12 @@ impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. /// + /// Arguments passed to `then_some` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use + /// [`then`], which is lazily evaluated. + /// + /// [`then`]: bool::then + /// /// # Examples /// /// ``` diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index 58eabecf3..8378611eb 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -1,4 +1,4 @@ -//! A module for working with borrowed data. +//! Utilities for working with borrowed data. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 71297acd1..dc8ea66cc 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -1,5 +1,7 @@ //! UTF-8 and UTF-16 decoding iterators +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use super::from_u32_unchecked; @@ -121,3 +123,12 @@ impl fmt::Display for DecodeUtf16Error { write!(f, "unpaired surrogate found: {:x}", self.code) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl Error for DecodeUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "unpaired surrogate found" + } +} diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index eae567cad..b7a63b7c6 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -746,10 +746,19 @@ impl char { /// assert!(!'中'.is_lowercase()); /// assert!(!' '.is_lowercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase(); + /// assert!(!CAPITAL_DELTA_IS_LOWERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_lowercase(self) -> bool { + pub const fn is_lowercase(self) -> bool { match self { 'a'..='z' => true, c => c > '\x7f' && unicode::Lowercase(c), @@ -779,10 +788,19 @@ impl char { /// assert!(!'中'.is_uppercase()); /// assert!(!' '.is_uppercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase(); + /// assert!(CAPITAL_DELTA_IS_UPPERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_uppercase(self) -> bool { + pub const fn is_uppercase(self) -> bool { match self { 'A'..='Z' => true, c => c > '\x7f' && unicode::Uppercase(c), @@ -892,8 +910,7 @@ impl char { /// /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric /// characters, and `No` for other numeric characters) are specified in the [Unicode Character - /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三' - /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`. + /// Database][ucd] [`UnicodeData.txt`]. /// /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'. /// If you want everything including characters with overlapping purposes then you might want to use diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 0df23e7bb..72d63ac4b 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -1,4 +1,6 @@ -//! A character type. +//! Utilities for the `char` primitive type. +//! +//! *[See also the `char` primitive type](primitive@char).* //! //! The `char` type represents a single character. More specifically, since //! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode @@ -36,6 +38,8 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Write}; use crate::iter::FusedIterator; @@ -582,3 +586,7 @@ impl fmt::Display for TryFromCharError { "unicode code point out of range".fmt(fmt) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "u8_from_char", since = "1.59.0")] +impl Error for TryFromCharError {} diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 20bb67687..d9f2d3d64 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1,6 +1,6 @@ -//! Functionality for ordering and comparison. +//! Utilities for comparing and ordering values. //! -//! This module contains various tools for ordering and comparing values. In +//! This module contains various tools for comparing and ordering values. In //! summary: //! //! * [`Eq`] and [`PartialEq`] are traits that allow you to define total and @@ -23,6 +23,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::marker::Destruct; +use crate::marker::StructuralPartialEq; use self::Ordering::*; @@ -38,8 +39,10 @@ use self::Ordering::*; /// /// Implementations must ensure that `eq` and `ne` are consistent with each other: /// -/// - `a != b` if and only if `!(a == b)` -/// (ensured by the default implementation). +/// - `a != b` if and only if `!(a == b)`. +/// +/// The default implementation of `ne` provides this consistency and is almost +/// always sufficient. It should not be overridden without very good reason. /// /// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also /// be consistent with `PartialEq` (see the documentation of those traits for the exact @@ -225,7 +228,8 @@ pub trait PartialEq<Rhs: ?Sized = Self> { #[stable(feature = "rust1", since = "1.0.0")] fn eq(&self, other: &Rhs) -> bool; - /// This method tests for `!=`. + /// This method tests for `!=`. The default implementation is almost always + /// sufficient, and should not be overridden without very good reason. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -335,7 +339,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> { /// let result = 2.cmp(&1); /// assert_eq!(Ordering::Greater, result); /// ``` -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, Eq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] #[repr(i8)] pub enum Ordering { @@ -882,6 +886,18 @@ pub macro Ord($item:item) { } #[stable(feature = "rust1", since = "1.0.0")] +impl StructuralPartialEq for Ordering {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] +impl const PartialEq for Ordering { + #[inline] + fn eq(&self, other: &Self) -> bool { + (*self as i32).eq(&(*other as i32)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] impl const Ord for Ordering { #[inline] @@ -1139,11 +1155,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn le(&self, other: &Rhs) -> bool { - // 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)) + matches!(self.partial_cmp(other), Some(Less | Equal)) } /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4ae..05637c166 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,6 +34,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{Hash, Hasher}; @@ -556,6 +558,7 @@ where #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for T { /// Returns the argument unchanged. + #[inline(always)] fn from(t: T) -> T { t } @@ -715,6 +718,14 @@ impl fmt::Display for Infallible { } } +#[cfg(not(bootstrap))] +#[stable(feature = "str_parse_error2", since = "1.8.0")] +impl Error for Infallible { + fn description(&self) -> &str { + match *self {} + } +} + #[stable(feature = "convert_infallible", since = "1.34.0")] impl PartialEq for Infallible { fn eq(&self, _: &Infallible) -> bool { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 1ce00828b..b53cd6074 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -1,4 +1,4 @@ -//! The `Default` trait for types which may have meaningful default values. +//! The `Default` trait for types with a default value. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/error.md b/library/core/src/error.md new file mode 100644 index 000000000..891abebbf --- /dev/null +++ b/library/core/src/error.md @@ -0,0 +1,137 @@ +Interfaces for working with Errors. + +# Error Handling In Rust + +The Rust language provides two complementary systems for constructing / +representing, reporting, propagating, reacting to, and discarding errors. +These responsibilities are collectively known as "error handling." The +components of the first system, the panic runtime and interfaces, are most +commonly used to represent bugs that have been detected in your program. The +components of the second system, `Result`, the error traits, and user +defined types, are used to represent anticipated runtime failure modes of +your program. + +## The Panic Interfaces + +The following are the primary interfaces of the panic system and the +responsibilities they cover: + +* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +* [`PanicInfo`] (Reporting) +* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) + +The following are the primary interfaces of the error system and the +responsibilities they cover: + +* [`Result`] (Propagating, Reacting) +* The [`Error`] trait (Reporting) +* User defined types (Constructing / Representing) +* [`match`] and [`downcast`] (Reacting) +* The question mark operator ([`?`]) (Propagating) +* The partially stable [`Try`] traits (Propagating, Constructing) +* [`Termination`] (Reporting) + +## Converting Errors into Panics + +The panic and error systems are not entirely distinct. Often times errors +that are anticipated runtime failures in an API might instead represent bugs +to a caller. For these situations the standard library provides APIs for +constructing panics with an `Error` as it's source. + +* [`Result::unwrap`] +* [`Result::expect`] + +These functions are equivalent, they either return the inner value if the +`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +as the source. The only difference between them is that with `expect` you +provide a panic error message to be printed alongside the source, whereas +`unwrap` has a default message indicating only that you unwraped an `Err`. + +Of the two, `expect` is generally preferred since its `msg` field allows you +to convey your intent and assumptions which makes tracking down the source +of a panic easier. `unwrap` on the other hand can still be a good fit in +situations where you can trivially show that a piece of code will never +panic, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early +prototyping. + +# Common Message Styles + +There are two common styles for how people word `expect` messages. Using +the message to present information to users encountering a panic +("expect as error message") or using the message to present information +to developers debugging the panic ("expect as precondition"). + +In the former case the expect message is used to describe the error that +has occurred which is considered a bug. Consider the following example: + +```should_panic +// Read environment variable, panic if it is not present +let path = std::env::var("IMPORTANT_PATH").unwrap(); +``` + +In the "expect as error message" style we would use expect to describe +that the environment variable was not set when it should have been: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` is not set"); +``` + +In the "expect as precondition" style, we would instead describe the +reason we _expect_ the `Result` should be `Ok`. With this style we would +prefer to write: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +``` + +The "expect as error message" style does not work as well with the +default output of the std panic hooks, and often ends up repeating +information that is already communicated by the source error being +unwrapped: + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +``` + +In this example we end up mentioning that an env variable is not set, +followed by our source message that says the env is not present, the +only additional information we're communicating is the name of the +environment variable being checked. + +The "expect as precondition" style instead focuses on source code +readability, making it easier to understand what must have gone wrong in +situations where panics are being used to represent bugs exclusively. +Also, by framing our expect in terms of what "SHOULD" have happened to +prevent the source error, we end up introducing new information that is +independent from our source error. + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +``` + +In this example we are communicating not only the name of the +environment variable that should have been set, but also an explanation +for why it should have been set, and we let the source error display as +a clear contradiction to our expectation. + +**Hint**: If you're having trouble remembering how to phrase +expect-as-precondition style error messages remember to focus on the word +"should" as in "env variable should be set by blah" or "the given binary +should be available and executable by the current user". + +[`panic_any`]: ../../std/panic/fn.panic_any.html +[`PanicInfo`]: crate::panic::PanicInfo +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +[`resume_unwind`]: ../../std/panic/fn.resume_unwind.html +[`downcast`]: crate::error::Error +[`Termination`]: ../../std/process/trait.Termination.html +[`Try`]: crate::ops::Try +[panic hook]: ../../std/panic/fn.set_hook.html +[`set_hook`]: ../../std/panic/fn.set_hook.html +[`take_hook`]: ../../std/panic/fn.take_hook.html +[panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html> +[`match`]: ../../std/keyword.match.html +[`?`]: ../../std/result/index.html#the-question-mark-operator- diff --git a/library/core/src/error.rs b/library/core/src/error.rs new file mode 100644 index 000000000..4a8efe15e --- /dev/null +++ b/library/core/src/error.rs @@ -0,0 +1,508 @@ +#![doc = include_str!("error.md")] +#![unstable(feature = "error_in_core", issue = "none")] + +#[cfg(test)] +mod tests; + +use crate::any::{Demand, Provider, TypeId}; +use crate::fmt::{Debug, Display}; + +/// `Error` is a trait representing the basic expectations for error values, +/// i.e., values of type `E` in [`Result<T, E>`]. +/// +/// Errors must describe themselves through the [`Display`] and [`Debug`] +/// traits. Error messages are typically concise lowercase sentences without +/// trailing punctuation: +/// +/// ``` +/// let err = "NaN".parse::<u32>().unwrap_err(); +/// assert_eq!(err.to_string(), "invalid digit found in string"); +/// ``` +/// +/// Errors may provide cause information. [`Error::source()`] is generally +/// used when errors cross "abstraction boundaries". If one module must report +/// an error that is caused by an error from a lower-level module, it can allow +/// accessing that error via [`Error::source()`]. This makes it possible for the +/// high-level module to provide its own errors while also revealing some of the +/// implementation for debugging. +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[rustc_has_incoherent_inherent_impls] +pub trait Error: Debug + Display { + /// The lower-level source of this error, if any. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// source: SuperErrorSideKick, + /// } + /// + /// impl fmt::Display for SuperError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperError is here!") + /// } + /// } + /// + /// impl Error for SuperError { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// Some(&self.source) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick; + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick {} + /// + /// fn get_super_error() -> Result<(), SuperError> { + /// Err(SuperError { source: SuperErrorSideKick }) + /// } + /// + /// fn main() { + /// match get_super_error() { + /// Err(e) => { + /// println!("Error: {e}"); + /// println!("Caused by: {}", e.source().unwrap()); + /// } + /// _ => println!("No error"), + /// } + /// } + /// ``` + #[stable(feature = "error_source", since = "1.30.0")] + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } + + /// Gets the `TypeId` of `self`. + #[doc(hidden)] + #[unstable( + feature = "error_type_id", + reason = "this is memory-unsafe to override in user code", + issue = "60784" + )] + fn type_id(&self, _: private::Internal) -> TypeId + where + Self: 'static, + { + TypeId::of::<Self>() + } + + /// ``` + /// if let Err(e) = "xc".parse::<u32>() { + /// // Print `e` itself, no need for description(). + /// eprintln!("Error: {e}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")] + fn description(&self) -> &str { + "description() is deprecated; use Display" + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated( + since = "1.33.0", + note = "replaced by Error::source, which can support downcasting" + )] + #[allow(missing_docs)] + fn cause(&self) -> Option<&dyn Error> { + self.source() + } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + /// demand + /// .provide_ref::<MyBacktrace>(&self.backtrace) + /// .provide_ref::<dyn std::error::Error + 'static>(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, demand: &mut Demand<'a>) {} +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl<E> Provider for E +where + E: Error + ?Sized, +{ + fn provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.provide(demand) + } +} + +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + +#[unstable(feature = "never_type", issue = "35121")] +impl Error for ! {} + +impl<'a> dyn Error + 'a { + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> { + core::any::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&'a self) -> Option<T> { + core::any::request_value(self) + } +} + +// Copied from `any.rs`. +impl dyn Error + 'static { + /// Returns `true` if the inner type is the same as `T`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is<T: Error + 'static>(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = TypeId::of::<T>(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(private::Internal); + + // Compare both `TypeId`s on equality. + t == concrete + } + + /// Returns some reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { + if self.is::<T>() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&*(self as *const dyn Error as *const T)) } + } else { + None + } + } + + /// Returns some mutable reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { + if self.is::<T>() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) } + } else { + None + } + } +} + +impl dyn Error + 'static + Send { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is<T: Error + 'static>(&self) -> bool { + <dyn Error + 'static>::is::<T>(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { + <dyn Error + 'static>::downcast_ref::<T>(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { + <dyn Error + 'static>::downcast_mut::<T>(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> { + <dyn Error>::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&self) -> Option<T> { + <dyn Error>::request_value(self) + } +} + +impl dyn Error + 'static + Send + Sync { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is<T: Error + 'static>(&self) -> bool { + <dyn Error + 'static>::is::<T>(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { + <dyn Error + 'static>::downcast_ref::<T>(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { + <dyn Error + 'static>::downcast_mut::<T>(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> { + <dyn Error>::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&self) -> Option<T> { + <dyn Error>::request_value(self) + } +} + +impl dyn Error { + /// Returns an iterator starting with the current error and continuing with + /// recursively calling [`Error::source`]. + /// + /// If you want to omit the current error and only use its sources, + /// use `skip(1)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option<Box<dyn Error + 'static>>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// + /// // let err : Box<Error> = b.into(); // or + /// let err = &b as &(dyn Error); + /// + /// let mut iter = err.sources(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "error_iter", issue = "58520")] + #[inline] + pub fn sources(&self) -> Source<'_> { + // You may think this method would be better in the Error trait, and you'd be right. + // Unfortunately that doesn't work, not because of the object safety rules but because we + // save a reference to self in Sources below as a trait object. If this method was + // declared in Error, then self would have the type &T where T is some concrete type which + // implements Error. We would need to coerce self to have type &dyn Error, but that requires + // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error + // since that would forbid Error trait objects, and we can't put that bound on the method + // because that means the method can't be called on trait objects (we'd also need the + // 'static bound, but that isn't allowed because methods with bounds on Self other than + // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible. + + Source { current: Some(self) } + } +} + +/// An iterator over an [`Error`] and its sources. +/// +/// If you want to omit the initial error and only process +/// its sources, use `skip(1)`. +#[unstable(feature = "error_iter", issue = "58520")] +#[derive(Clone, Debug)] +pub struct Source<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> Iterator for Source<'a> { + type Item = &'a (dyn Error + 'static); + + fn next(&mut self) -> Option<Self::Item> { + let current = self.current; + self.current = self.current.and_then(Error::source); + current + } +} + +#[stable(feature = "error_by_ref", since = "1.51.0")] +impl<'a, T: Error + ?Sized> Error for &'a T { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn provide<'b>(&'b self, demand: &mut Demand<'b>) { + Error::provide(&**self, demand); + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for crate::fmt::Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already mutably borrowed" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowMutError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already borrowed" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for crate::char::CharTryFromError { + #[allow(deprecated)] + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl Error for crate::char::ParseCharError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl Error for crate::time::FromFloatSecsError {} + +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for crate::ffi::FromBytesWithNulError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] +impl Error for crate::ffi::FromBytesUntilNulError {} diff --git a/library/core/src/ffi/c_double.md b/library/core/src/ffi/c_double.md index 57f453482..d49e29b6e 100644 --- a/library/core/src/ffi/c_double.md +++ b/library/core/src/ffi/c_double.md @@ -1,6 +1,6 @@ Equivalent to C's `double` type. -This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. +This type will almost always be [`f64`], which is guaranteed to be an [IEEE 754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. -[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[IEEE 754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 [`float`]: c_float diff --git a/library/core/src/ffi/c_float.md b/library/core/src/ffi/c_float.md index 61e2abc05..36374ef43 100644 --- a/library/core/src/ffi/c_float.md +++ b/library/core/src/ffi/c_float.md @@ -1,5 +1,5 @@ Equivalent to C's `float` type. -This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. +This type will almost always be [`f32`], which is guaranteed to be an [IEEE 754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. -[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 +[IEEE 754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 82e63a7fe..21f80ec02 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -1,7 +1,6 @@ -use crate::ascii; use crate::cmp::Ordering; use crate::ffi::c_char; -use crate::fmt::{self, Write}; +use crate::fmt; use crate::intrinsics; use crate::ops; use crate::slice; @@ -121,10 +120,10 @@ enum FromBytesWithNulErrorKind { } impl FromBytesWithNulError { - fn interior_nul(pos: usize) -> FromBytesWithNulError { + const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - fn not_nul_terminated() -> FromBytesWithNulError { + const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -161,11 +160,7 @@ impl fmt::Display for FromBytesUntilNulError { #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"")?; - for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { - f.write_char(byte as char)?; - } - write!(f, "\"") + write!(f, "\"{}\"", self.to_bytes().escape_ascii()) } } @@ -299,7 +294,8 @@ impl CStr { /// ``` /// #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] - pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { + #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] + pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) => { @@ -348,7 +344,8 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) if nul_pos + 1 == bytes.len() => { @@ -387,6 +384,7 @@ impl CStr { #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] #[rustc_allow_const_fn_unstable(const_eval_select)] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + #[inline] fn rt_impl(bytes: &[u8]) -> &CStr { // Chance at catching some UB at runtime with debug builds. debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); @@ -497,7 +495,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); // SAFETY: to_bytes_with_nul returns slice with length at least 1 unsafe { bytes.get_unchecked(..bytes.len() - 1) } @@ -524,7 +523,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes_with_nul(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } @@ -547,7 +547,8 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 32d1a4e55..7da49b04a 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> { } impl fmt::Write for PadAdapter<'_, '_> { - fn write_str(&mut self, mut s: &str) -> fmt::Result { - while !s.is_empty() { + fn write_str(&mut self, s: &str) -> fmt::Result { + for s in s.split_inclusive('\n') { if self.state.on_newline { self.buf.write_str(" ")?; } - let split = match s.find('\n') { - Some(pos) => { - self.state.on_newline = true; - pos + 1 - } - None => { - self.state.on_newline = false; - s.len() - } - }; - self.buf.write_str(&s[..split])?; - s = &s[split..]; + self.state.on_newline = s.ends_with('\n'); + self.buf.write_str(s)?; } Ok(()) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 372141e09..905212eb3 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -119,6 +119,10 @@ pub trait Write { /// /// This function will return an instance of [`Error`] on error. /// + /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying + /// destination encounters some error preventing it from accepting more text; it should + /// generally be propagated rather than handled, at least when implementing formatting traits. + /// /// # Examples /// /// ``` @@ -1815,7 +1819,7 @@ impl<'a> Formatter<'a> { /// write!(formatter, /// "Foo({}{})", /// if self.0 < 0 { '-' } else { '+' }, - /// self.0) + /// self.0.abs()) /// } else { /// write!(formatter, "Foo({})", self.0) /// } @@ -1823,6 +1827,7 @@ impl<'a> Formatter<'a> { /// } /// /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)"); /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] @@ -2562,7 +2567,7 @@ macro_rules! tuple { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index db2a52332..90cb79739 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -5,7 +5,9 @@ use crate::task::{Context, Poll}; /// Creates a future that wraps a function returning [`Poll`]. /// -/// Polling the future delegates to the wrapped function. +/// Polling the future delegates to the wrapped function. If the returned future is pinned, then the +/// captured environment of the wrapped function is also pinned in-place, so as long as the closure +/// does not move out of its captures it can soundly create pinned references to them. /// /// # Examples /// @@ -41,7 +43,7 @@ pub struct PollFn<F> { } #[stable(feature = "future_poll_fn", since = "1.64.0")] -impl<F> Unpin for PollFn<F> {} +impl<F: Unpin> Unpin for PollFn<F> {} #[stable(feature = "future_poll_fn", since = "1.64.0")] impl<F> fmt::Debug for PollFn<F> { @@ -57,7 +59,8 @@ where { type Output = T; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { - (&mut self.f)(cx) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { + // SAFETY: We are not moving out of the pinned field. + (unsafe { &mut self.get_unchecked_mut().f })(cx) } } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 5974562ac..aa13435e6 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -900,7 +900,7 @@ mod impls { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 81b6d5737..764e27962 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -31,7 +31,7 @@ use crate::intrinsics; /// /// `unreachable_unchecked()` can be used in situations where the compiler /// can't prove invariants that were previously established. Such situations -/// have a higher chance of occuring if those invariants are upheld by +/// have a higher chance of occurring if those invariants are upheld by /// external code that the compiler can't analyze. /// ``` /// fn prepare_inputs(divisors: &mut Vec<u32>) { @@ -160,19 +160,16 @@ pub const unsafe fn unreachable_unchecked() -> ! { #[inline] #[stable(feature = "renamed_spin_loop", since = "1.49.0")] pub fn spin_loop() { - #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] + #[cfg(target_arch = "x86")] { - #[cfg(target_arch = "x86")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. - unsafe { crate::arch::x86::_mm_pause() }; - } + // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. + unsafe { crate::arch::x86::_mm_pause() }; + } - #[cfg(target_arch = "x86_64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. - unsafe { crate::arch::x86_64::_mm_pause() }; - } + #[cfg(target_arch = "x86_64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. + unsafe { crate::arch::x86_64::_mm_pause() }; } // RISC-V platform spin loop hint implementation diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cabc5017f..11c75e2c9 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -54,7 +54,9 @@ )] #![allow(missing_docs)] -use crate::marker::{Destruct, DiscriminantKind}; +#[cfg(bootstrap)] +use crate::marker::Destruct; +use crate::marker::DiscriminantKind; use crate::mem; // These imports are used for simplifying intra-doc links @@ -63,7 +65,7 @@ use crate::mem; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { @@ -71,214 +73,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { unsafe { crate::ptr::drop_in_place(to_drop) } } -// These have been renamed. -#[cfg(bootstrap)] -extern "rust-intrinsic" { - pub fn atomic_cxchg<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_load<T: Copy>(src: *const T) -> T; - pub fn atomic_load_acq<T: Copy>(src: *const T) -> T; - pub fn atomic_load_relaxed<T: Copy>(src: *const T) -> T; - pub fn atomic_load_unordered<T: Copy>(src: *const T) -> T; - pub fn atomic_store<T: Copy>(dst: *mut T, val: T); - pub fn atomic_store_rel<T: Copy>(dst: *mut T, val: T); - pub fn atomic_store_relaxed<T: Copy>(dst: *mut T, val: T); - pub fn atomic_store_unordered<T: Copy>(dst: *mut T, val: T); - pub fn atomic_xchg<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_and<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_and_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_and_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_and_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_and_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_nand<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_nand_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_nand_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_nand_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_nand_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_or<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_or_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_or_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_or_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_or_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xor<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xor_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xor_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xor_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_xor_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_max<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_max_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_max_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_max_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_max_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_min<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_min_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_min_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_min_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_min_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umin<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umin_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umin_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umin_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umin_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umax<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umax_acq<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umax_rel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umax_acqrel<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_umax_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - pub fn atomic_fence(); - pub fn atomic_fence_acq(); - pub fn atomic_fence_rel(); - pub fn atomic_fence_acqrel(); - pub fn atomic_singlethreadfence(); - pub fn atomic_singlethreadfence_acq(); - pub fn atomic_singlethreadfence_rel(); - pub fn atomic_singlethreadfence_acqrel(); -} - -// These have been renamed. -#[cfg(bootstrap)] -mod atomics { - pub use super::atomic_cxchg as atomic_cxchg_seqcst_seqcst; - pub use super::atomic_cxchg_acq as atomic_cxchg_acquire_acquire; - pub use super::atomic_cxchg_acq_failrelaxed as atomic_cxchg_acquire_relaxed; - pub use super::atomic_cxchg_acqrel as atomic_cxchg_acqrel_acquire; - pub use super::atomic_cxchg_acqrel_failrelaxed as atomic_cxchg_acqrel_relaxed; - pub use super::atomic_cxchg_failacq as atomic_cxchg_seqcst_acquire; - pub use super::atomic_cxchg_failrelaxed as atomic_cxchg_seqcst_relaxed; - pub use super::atomic_cxchg_rel as atomic_cxchg_release_relaxed; - pub use super::atomic_cxchg_relaxed as atomic_cxchg_relaxed_relaxed; - - pub use super::atomic_cxchgweak as atomic_cxchgweak_seqcst_seqcst; - pub use super::atomic_cxchgweak_acq as atomic_cxchgweak_acquire_acquire; - pub use super::atomic_cxchgweak_acq_failrelaxed as atomic_cxchgweak_acquire_relaxed; - pub use super::atomic_cxchgweak_acqrel as atomic_cxchgweak_acqrel_acquire; - pub use super::atomic_cxchgweak_acqrel_failrelaxed as atomic_cxchgweak_acqrel_relaxed; - pub use super::atomic_cxchgweak_failacq as atomic_cxchgweak_seqcst_acquire; - pub use super::atomic_cxchgweak_failrelaxed as atomic_cxchgweak_seqcst_relaxed; - pub use super::atomic_cxchgweak_rel as atomic_cxchgweak_release_relaxed; - pub use super::atomic_cxchgweak_relaxed as atomic_cxchgweak_relaxed_relaxed; - - pub use super::atomic_load as atomic_load_seqcst; - pub use super::atomic_load_acq as atomic_load_acquire; - pub use super::atomic_load_relaxed; - pub use super::atomic_load_unordered; - - pub use super::atomic_store as atomic_store_seqcst; - pub use super::atomic_store_rel as atomic_store_release; - pub use super::atomic_store_relaxed; - pub use super::atomic_store_unordered; - - pub use super::atomic_xchg as atomic_xchg_seqcst; - pub use super::atomic_xchg_acq as atomic_xchg_acquire; - pub use super::atomic_xchg_acqrel; - pub use super::atomic_xchg_rel as atomic_xchg_release; - pub use super::atomic_xchg_relaxed; - - pub use super::atomic_xadd as atomic_xadd_seqcst; - pub use super::atomic_xadd_acq as atomic_xadd_acquire; - pub use super::atomic_xadd_acqrel; - pub use super::atomic_xadd_rel as atomic_xadd_release; - pub use super::atomic_xadd_relaxed; - - pub use super::atomic_xsub as atomic_xsub_seqcst; - pub use super::atomic_xsub_acq as atomic_xsub_acquire; - pub use super::atomic_xsub_acqrel; - pub use super::atomic_xsub_rel as atomic_xsub_release; - pub use super::atomic_xsub_relaxed; - - pub use super::atomic_and as atomic_and_seqcst; - pub use super::atomic_and_acq as atomic_and_acquire; - pub use super::atomic_and_acqrel; - pub use super::atomic_and_rel as atomic_and_release; - pub use super::atomic_and_relaxed; - - pub use super::atomic_nand as atomic_nand_seqcst; - pub use super::atomic_nand_acq as atomic_nand_acquire; - pub use super::atomic_nand_acqrel; - pub use super::atomic_nand_rel as atomic_nand_release; - pub use super::atomic_nand_relaxed; - - pub use super::atomic_or as atomic_or_seqcst; - pub use super::atomic_or_acq as atomic_or_acquire; - pub use super::atomic_or_acqrel; - pub use super::atomic_or_rel as atomic_or_release; - pub use super::atomic_or_relaxed; - - pub use super::atomic_xor as atomic_xor_seqcst; - pub use super::atomic_xor_acq as atomic_xor_acquire; - pub use super::atomic_xor_acqrel; - pub use super::atomic_xor_rel as atomic_xor_release; - pub use super::atomic_xor_relaxed; - - pub use super::atomic_max as atomic_max_seqcst; - pub use super::atomic_max_acq as atomic_max_acquire; - pub use super::atomic_max_acqrel; - pub use super::atomic_max_rel as atomic_max_release; - pub use super::atomic_max_relaxed; - - pub use super::atomic_min as atomic_min_seqcst; - pub use super::atomic_min_acq as atomic_min_acquire; - pub use super::atomic_min_acqrel; - pub use super::atomic_min_rel as atomic_min_release; - pub use super::atomic_min_relaxed; - - pub use super::atomic_umin as atomic_umin_seqcst; - pub use super::atomic_umin_acq as atomic_umin_acquire; - pub use super::atomic_umin_acqrel; - pub use super::atomic_umin_rel as atomic_umin_release; - pub use super::atomic_umin_relaxed; - - pub use super::atomic_umax as atomic_umax_seqcst; - pub use super::atomic_umax_acq as atomic_umax_acquire; - pub use super::atomic_umax_acqrel; - pub use super::atomic_umax_rel as atomic_umax_release; - pub use super::atomic_umax_relaxed; - - pub use super::atomic_fence as atomic_fence_seqcst; - pub use super::atomic_fence_acq as atomic_fence_acquire; - pub use super::atomic_fence_acqrel; - pub use super::atomic_fence_rel as atomic_fence_release; - - pub use super::atomic_singlethreadfence as atomic_singlethreadfence_seqcst; - pub use super::atomic_singlethreadfence_acq as atomic_singlethreadfence_acquire; - pub use super::atomic_singlethreadfence_acqrel; - pub use super::atomic_singlethreadfence_rel as atomic_singlethreadfence_release; -} - -#[cfg(bootstrap)] -pub use atomics::*; - -#[cfg(not(bootstrap))] extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -945,30 +739,7 @@ extern "rust-intrinsic" { /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. pub fn atomic_singlethreadfence_acqrel(); -} -// These have been renamed. -// -// These are the aliases for the old names. -// To be removed when stdarch and panic_unwind have been updated. -#[cfg(not(bootstrap))] -mod atomics { - pub use super::atomic_cxchg_acqrel_acquire as atomic_cxchg_acqrel; - pub use super::atomic_cxchg_acqrel_relaxed as atomic_cxchg_acqrel_failrelaxed; - pub use super::atomic_cxchg_acquire_acquire as atomic_cxchg_acq; - pub use super::atomic_cxchg_acquire_relaxed as atomic_cxchg_acq_failrelaxed; - pub use super::atomic_cxchg_relaxed_relaxed as atomic_cxchg_relaxed; - pub use super::atomic_cxchg_release_relaxed as atomic_cxchg_rel; - pub use super::atomic_cxchg_seqcst_acquire as atomic_cxchg_failacq; - pub use super::atomic_cxchg_seqcst_relaxed as atomic_cxchg_failrelaxed; - pub use super::atomic_cxchg_seqcst_seqcst as atomic_cxchg; - pub use super::atomic_store_seqcst as atomic_store; -} - -#[cfg(not(bootstrap))] -pub use atomics::*; - -extern "rust-intrinsic" { /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance @@ -1313,7 +1084,7 @@ extern "rust-intrinsic" { /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferrable to + /// Depending on what the code is doing, the following alternatives are preferable to /// pointer-to-integer transmutation: /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a /// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit]. @@ -1463,7 +1234,7 @@ extern "rust-intrinsic" { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] + #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] pub fn transmute<T, U>(e: T) -> U; @@ -1518,6 +1289,17 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T; + /// Masks out bits of the pointer according to a mask. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// Consider using [`pointer::mask`] instead. + #[cfg(not(bootstrap))] + pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; + /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::<T>()` and an alignment of /// `min_align_of::<T>()` @@ -2223,29 +2005,32 @@ extern "rust-intrinsic" { pub fn nontemporal_store<T>(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; /// See documentation of `<*const T>::sub_ptr` for details. - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize; /// See documentation of `<*const T>::guaranteed_eq` for details. + /// Returns `2` if the result is unknown. + /// Returns `1` if the pointers are guaranteed equal + /// Returns `0` if the pointers are guaranteed inequal /// /// Note that, unlike most intrinsics, this is safe to call; /// it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(not(bootstrap))] + pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8; + + #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(bootstrap)] pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool; - /// See documentation of `<*const T>::guaranteed_ne` for details. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] + #[cfg(bootstrap)] pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool; /// Allocates a block of memory at compile time. @@ -2282,7 +2067,8 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. + /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a + /// pointer value. /// Note that this is a stricter criterion than just the *values* being /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. /// @@ -2299,13 +2085,70 @@ extern "rust-intrinsic" { /// `ptr` must point to a vtable. /// The intrinsic will return the size stored in that vtable. - #[cfg(not(bootstrap))] pub fn vtable_size(ptr: *const ()) -> usize; /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. - #[cfg(not(bootstrap))] pub fn vtable_align(ptr: *const ()) -> usize; + + /// Selects which function to call depending on the context. + /// + /// If this function is evaluated at compile-time, then a call to this + /// intrinsic will be replaced with a call to `called_in_const`. It gets + /// replaced with a call to `called_at_rt` otherwise. + /// + /// # Type Requirements + /// + /// The two functions must be both function items. They cannot be function + /// pointers or closures. The first function must be a `const fn`. + /// + /// `arg` will be the tupled arguments that will be passed to either one of + /// the two functions, therefore, both functions must accept the same type of + /// arguments. Both functions must return RET. + /// + /// # Safety + /// + /// The two functions must behave observably equivalent. Safe code in other + /// crates may assume that calling a `const fn` at compile-time and at run-time + /// produces the same result. A function that produces a different result when + /// evaluated at run-time, or has any other observable side-effects, is + /// *unsound*. + /// + /// Here is an example of how this could cause a problem: + /// ```no_run + /// #![feature(const_eval_select)] + /// #![feature(core_intrinsics)] + /// use std::hint::unreachable_unchecked; + /// use std::intrinsics::const_eval_select; + /// + /// // Crate A + /// pub const fn inconsistent() -> i32 { + /// fn runtime() -> i32 { 1 } + /// const fn compiletime() -> i32 { 2 } + /// + /// unsafe { + // // ⚠ This code violates the required equivalence of `compiletime` + /// // and `runtime`. + /// const_eval_select((), compiletime, runtime) + /// } + /// } + /// + /// // Crate B + /// const X: i32 = inconsistent(); + /// let x = inconsistent(); + /// if x != X { unsafe { unreachable_unchecked(); }} + /// ``` + /// + /// This code causes Undefined Behavior when being run, since the + /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, + /// which violates the principle that a `const fn` must behave the same at + /// compile-time and at run-time. The unsafe code in crate B is fine. + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] + pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET + where + G: FnOnce<ARG, Output = RET>, + F: FnOnce<ARG, Output = RET>; } // Some functions are defined here because they accidentally got made @@ -2316,6 +2159,11 @@ extern "rust-intrinsic" { /// Check that the preconditions of an unsafe function are followed, if debug_assertions are on, /// and only at runtime. /// +/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)` +/// where the names specified will be moved into the macro as captured variables, and defines an item +/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics +/// for the function declaractions and can be omitted if there is no generics. +/// /// # Safety /// /// Invoking this macro is only sound if the following code is already UB when the passed @@ -2330,18 +2178,21 @@ extern "rust-intrinsic" { /// the occasional mistake, and this check should help them figure things out. #[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn macro_rules! assert_unsafe_precondition { - ($e:expr) => { + ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => { if cfg!(debug_assertions) { - // Use a closure so that we can capture arbitrary expressions from the invocation - let runtime = || { + // allow non_snake_case to allow capturing const generics + #[allow(non_snake_case)] + #[inline(always)] + fn runtime$(<$($tt)*>)?($($i:$ty),*) { if !$e { // abort instead of panicking to reduce impact on code size ::core::intrinsics::abort(); } - }; - const fn comptime() {} + } + #[allow(non_snake_case)] + const fn comptime$(<$($tt)*>)?($(_:$ty),*) {} - ::core::intrinsics::const_eval_select((), comptime, runtime); + ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime); } }; } @@ -2350,7 +2201,7 @@ pub(crate) use assert_unsafe_precondition; /// Checks whether `ptr` is properly aligned with respect to /// `align_of::<T>()`. pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool { - !ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0 + !ptr.is_null() && ptr.is_aligned() } /// Checks whether the regions of memory starting at `src` and `dst` of size @@ -2365,6 +2216,16 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - diff >= size } +#[cfg(bootstrap)] +pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 { + match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) { + (false, false) => 2, + (true, false) => 1, + (false, true) => 0, + (true, true) => unreachable!(), + } +} + /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source /// and destination must *not* overlap. /// @@ -2420,9 +2281,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - /// dst.reserve(src_len); /// /// unsafe { -/// // The call to offset is always safe because `Vec` will never +/// // The call to add is always safe because `Vec` will never /// // allocate more than `isize::MAX` bytes. -/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let dst_ptr = dst.as_mut_ptr().add(dst_len); /// let src_ptr = src.as_ptr(); /// /// // Truncate `src` without dropping its contents. We do this first, @@ -2451,7 +2312,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2464,7 +2325,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us // SAFETY: the safety contract for `copy_nonoverlapping` must be // upheld by the caller. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) => is_aligned_and_not_null(src) && is_aligned_and_not_null(dst) && is_nonoverlapping(src, dst, count) @@ -2538,7 +2399,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2550,7 +2411,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](src: *const T, dst: *mut T) => + is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); copy(src, dst, count) } } @@ -2606,7 +2468,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] +#[rustc_allowed_through_unstable_modules] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -2618,63 +2480,12 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); write_bytes(dst, val, count) } } -/// Selects which function to call depending on the context. -/// -/// If this function is evaluated at compile-time, then a call to this -/// intrinsic will be replaced with a call to `called_in_const`. It gets -/// replaced with a call to `called_at_rt` otherwise. -/// -/// # Type Requirements -/// -/// The two functions must be both function items. They cannot be function -/// pointers or closures. -/// -/// `arg` will be the arguments that will be passed to either one of the -/// two functions, therefore, both functions must accept the same type of -/// arguments. Both functions must return RET. -/// -/// # Safety -/// -/// The two functions must behave observably equivalent. Safe code in other -/// crates may assume that calling a `const fn` at compile-time and at run-time -/// produces the same result. A function that produces a different result when -/// evaluated at run-time, or has any other observable side-effects, is -/// *unsound*. -/// -/// Here is an example of how this could cause a problem: -/// ```no_run -/// #![feature(const_eval_select)] -/// #![feature(core_intrinsics)] -/// use std::hint::unreachable_unchecked; -/// use std::intrinsics::const_eval_select; -/// -/// // Crate A -/// pub const fn inconsistent() -> i32 { -/// fn runtime() -> i32 { 1 } -/// const fn compiletime() -> i32 { 2 } -/// -/// unsafe { -// // ⚠ This code violates the required equivalence of `compiletime` -/// // and `runtime`. -/// const_eval_select((), compiletime, runtime) -/// } -/// } -/// -/// // Crate B -/// const X: i32 = inconsistent(); -/// let x = inconsistent(); -/// if x != X { unsafe { unreachable_unchecked(); }} -/// ``` -/// -/// This code causes Undefined Behavior when being run, since the -/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, -/// which violates the principle that a `const fn` must behave the same at -/// compile-time and at run-time. The unsafe code in crate B is fine. +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", @@ -2696,6 +2507,7 @@ where called_at_rt.call_once(arg) } +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs new file mode 100644 index 000000000..9b479a9f8 --- /dev/null +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -0,0 +1,182 @@ +use crate::array; +use crate::iter::{ByRefSized, FusedIterator, Iterator}; +use crate::ops::{ControlFlow, NeverShortCircuit, Try}; + +/// An iterator over `N` elements of the iterator at a time. +/// +/// The chunks do not overlap. If `N` does not divide the length of the +/// iterator, then the last up to `N-1` elements will be omitted. +/// +/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks] +/// method on [`Iterator`]. See its documentation for more. +#[derive(Debug, Clone)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub struct ArrayChunks<I: Iterator, const N: usize> { + iter: I, + remainder: Option<array::IntoIter<I::Item, N>>, +} + +impl<I, const N: usize> ArrayChunks<I, N> +where + I: Iterator, +{ + #[track_caller] + pub(in crate::iter) fn new(iter: I) -> Self { + assert!(N != 0, "chunk size must be non-zero"); + Self { iter, remainder: None } + } + + /// Returns an iterator over the remaining elements of the original iterator + /// that are not going to be returned by this iterator. The returned + /// iterator will yield at most `N-1` elements. + #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + #[inline] + pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> { + self.remainder + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl<I, const N: usize> Iterator for ArrayChunks<I, N> +where + I: Iterator, +{ + type Item = [I::Item; N]; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.try_for_each(ControlFlow::Break).break_value() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (lower, upper) = self.iter.size_hint(); + + (lower / N, upper.map(|n| n / N)) + } + + #[inline] + fn count(self) -> usize { + self.iter.count() / N + } + + fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let mut acc = init; + loop { + match self.iter.next_chunk() { + Ok(chunk) => acc = f(acc, chunk)?, + Err(remainder) => { + // Make sure to not override `self.remainder` with an empty array + // when `next` is called after `ArrayChunks` exhaustion. + self.remainder.get_or_insert(remainder); + + break try { acc }; + } + } + } + } + + fn fold<B, F>(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N> +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<Self::Item> { + self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value() + } + + fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + // We are iterating from the back we need to first handle the remainder. + self.next_back_remainder(); + + let mut acc = init; + let mut iter = ByRefSized(&mut self.iter).rev(); + + // NB remainder is handled by `next_back_remainder`, so + // `next_chunk` can't return `Err` with non-empty remainder + // (assuming correct `I as ExactSizeIterator` impl). + while let Ok(mut chunk) = iter.next_chunk() { + // FIXME: do not do double reverse + // (we could instead add `next_chunk_back` for example) + chunk.reverse(); + acc = f(acc, chunk)? + } + + try { acc } + } + + fn rfold<B, F>(mut self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 + } +} + +impl<I, const N: usize> ArrayChunks<I, N> +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`. + fn next_back_remainder(&mut self) { + // Make sure to not override `self.remainder` with an empty array + // when `next_back` is called after `ArrayChunks` exhaustion. + if self.remainder.is_some() { + return; + } + + // We use the `ExactSizeIterator` implementation of the underlying + // iterator to know how many remaining elements there are. + let rem = self.iter.len() % N; + + // Take the last `rem` elements out of `self.iter`. + let mut remainder = + // SAFETY: `unwrap_err` always succeeds because x % N < N for all x. + unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() }; + + // We used `.rev()` above, so we need to re-reverse the reminder + remainder.as_mut_slice().reverse(); + self.remainder = Some(remainder); + } +} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {} + +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N> +where + I: ExactSizeIterator, +{ + #[inline] + fn len(&self) -> usize { + self.iter.len() / N + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.len() < N + } +} diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index cc1e8e8a2..477e7117c 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -1,4 +1,4 @@ -use crate::ops::Try; +use crate::ops::{NeverShortCircuit, Try}; /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics. /// @@ -8,28 +8,31 @@ use crate::ops::Try; #[derive(Debug)] pub struct ByRefSized<'a, I>(pub &'a mut I); +// The following implementations use UFCS-style, rather than trusting autoderef, +// to avoid accidentally calling the `&mut Iterator` implementations. + #[unstable(feature = "std_internals", issue = "none")] impl<I: Iterator> Iterator for ByRefSized<'_, I> { type Item = I::Item; #[inline] fn next(&mut self) -> Option<Self::Item> { - self.0.next() + I::next(self.0) } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - self.0.size_hint() + I::size_hint(self.0) } #[inline] fn advance_by(&mut self, n: usize) -> Result<(), usize> { - self.0.advance_by(n) + I::advance_by(self.0, n) } #[inline] fn nth(&mut self, n: usize) -> Option<Self::Item> { - self.0.nth(n) + I::nth(self.0, n) } #[inline] @@ -37,7 +40,8 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> { where F: FnMut(B, Self::Item) -> B, { - self.0.fold(init, f) + // `fold` needs ownership, so this can't forward directly. + I::try_fold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] @@ -46,7 +50,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> { F: FnMut(B, Self::Item) -> R, R: Try<Output = B>, { - self.0.try_fold(init, f) + I::try_fold(self.0, init, f) } } @@ -54,17 +58,17 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> { impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> { #[inline] fn next_back(&mut self) -> Option<Self::Item> { - self.0.next_back() + I::next_back(self.0) } #[inline] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - self.0.advance_back_by(n) + I::advance_back_by(self.0, n) } #[inline] fn nth_back(&mut self, n: usize) -> Option<Self::Item> { - self.0.nth_back(n) + I::nth_back(self.0, n) } #[inline] @@ -72,7 +76,8 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> { where F: FnMut(B, Self::Item) -> B, { - self.0.rfold(init, f) + // `rfold` needs ownership, so this can't forward directly. + I::try_rfold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] @@ -81,6 +86,6 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> { F: FnMut(B, Self::Item) -> R, R: Try<Output = B>, { - self.0.try_rfold(init, f) + I::try_rfold(self.0, init, f) } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 15a120e35..307016c26 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,6 +1,6 @@ use crate::fmt; use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. @@ -73,6 +73,21 @@ where { self.inner.fold(init, fold) } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_by(n) + } + + #[inline] + fn count(self) -> usize { + self.inner.count() + } + + #[inline] + fn last(self) -> Option<Self::Item> { + self.inner.last() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -103,6 +118,11 @@ where { self.inner.rfold(init, fold) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_back_by(n) + } } #[stable(feature = "fused", since = "1.26.0")] @@ -214,6 +234,21 @@ where { self.inner.fold(init, fold) } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_by(n) + } + + #[inline] + fn count(self) -> usize { + self.inner.count() + } + + #[inline] + fn last(self) -> Option<Self::Item> { + self.inner.last() + } } #[stable(feature = "iterator_flatten", since = "1.29.0")] @@ -244,6 +279,11 @@ where { self.inner.rfold(init, fold) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.inner.advance_back_by(n) + } } #[stable(feature = "iterator_flatten", since = "1.29.0")] @@ -280,6 +320,144 @@ where } } +impl<I, U> FlattenCompat<I, U> +where + I: Iterator<Item: IntoIterator<IntoIter = U>>, +{ + /// Folds the inner iterators into an accumulator by applying an operation. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `fold`, `count`, + /// and `last` methods. + #[inline] + fn iter_fold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, U) -> Acc, + { + #[inline] + fn flatten<T: IntoIterator, Acc>( + fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + '_ { + move |acc, iter| fold(acc, iter.into_iter()) + } + + if let Some(iter) = self.frontiter { + acc = fold(acc, iter); + } + + acc = self.iter.fold(acc, flatten(&mut fold)); + + if let Some(iter) = self.backiter { + acc = fold(acc, iter); + } + + acc + } + + /// Folds over the inner iterators as long as the given function returns successfully, + /// always storing the most recent inner iterator in `self.frontiter`. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `try_fold` and + /// `advance_by` methods. + #[inline] + fn iter_try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R + where + Fold: FnMut(Acc, &mut U) -> R, + R: Try<Output = Acc>, + { + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( + frontiter: &'a mut Option<T::IntoIter>, + fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, iter| fold(acc, frontiter.insert(iter.into_iter())) + } + + if let Some(iter) = &mut self.frontiter { + acc = fold(acc, iter)?; + } + self.frontiter = None; + + acc = self.iter.try_fold(acc, flatten(&mut self.frontiter, &mut fold))?; + self.frontiter = None; + + if let Some(iter) = &mut self.backiter { + acc = fold(acc, iter)?; + } + self.backiter = None; + + try { acc } + } +} + +impl<I, U> FlattenCompat<I, U> +where + I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U>>, +{ + /// Folds the inner iterators into an accumulator by applying an operation, starting form the + /// back. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `rfold` method. + #[inline] + fn iter_rfold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, U) -> Acc, + { + #[inline] + fn flatten<T: IntoIterator, Acc>( + fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + '_ { + move |acc, iter| fold(acc, iter.into_iter()) + } + + if let Some(iter) = self.backiter { + acc = fold(acc, iter); + } + + acc = self.iter.rfold(acc, flatten(&mut fold)); + + if let Some(iter) = self.frontiter { + acc = fold(acc, iter); + } + + acc + } + + /// Folds over the inner iterators in reverse order as long as the given function returns + /// successfully, always storing the most recent inner iterator in `self.backiter`. + /// + /// Folds over the inner iterators, not over their elements. Is used by the `try_rfold` and + /// `advance_back_by` methods. + #[inline] + fn iter_try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R + where + Fold: FnMut(Acc, &mut U) -> R, + R: Try<Output = Acc>, + { + #[inline] + fn flatten<'a, T: IntoIterator, Acc, R: Try>( + backiter: &'a mut Option<T::IntoIter>, + fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, + ) -> impl FnMut(Acc, T) -> R + 'a { + move |acc, iter| fold(acc, backiter.insert(iter.into_iter())) + } + + if let Some(iter) = &mut self.backiter { + acc = fold(acc, iter)?; + } + self.backiter = None; + + acc = self.iter.try_rfold(acc, flatten(&mut self.backiter, &mut fold))?; + self.backiter = None; + + if let Some(iter) = &mut self.frontiter { + acc = fold(acc, iter)?; + } + self.frontiter = None; + + try { acc } + } +} + impl<I, U> Iterator for FlattenCompat<I, U> where I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, @@ -323,99 +501,74 @@ where } #[inline] - fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R + fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( - frontiter: &'a mut Option<T::IntoIter>, - fold: &'a mut impl FnMut(Acc, T::Item) -> R, - ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_fold(acc, &mut *fold); - *frontiter = Some(mid); - r - } - } - - if let Some(ref mut front) = self.frontiter { - init = front.try_fold(init, &mut fold)?; + fn flatten<U: Iterator, Acc, R: Try<Output = Acc>>( + mut fold: impl FnMut(Acc, U::Item) -> R, + ) -> impl FnMut(Acc, &mut U) -> R { + move |acc, iter| iter.try_fold(acc, &mut fold) } - self.frontiter = None; - init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?; - self.frontiter = None; - - if let Some(ref mut back) = self.backiter { - init = back.try_fold(init, &mut fold)?; - } - self.backiter = None; - - try { init } + self.iter_try_fold(init, flatten(fold)) } #[inline] - fn fold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc + fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn flatten<T: IntoIterator, Acc>( - fold: &mut impl FnMut(Acc, T::Item) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ { - move |acc, x| x.into_iter().fold(acc, &mut *fold) - } - - if let Some(front) = self.frontiter { - init = front.fold(init, &mut fold); - } - - init = self.iter.fold(init, flatten(&mut fold)); - - if let Some(back) = self.backiter { - init = back.fold(init, &mut fold); + fn flatten<U: Iterator, Acc>( + mut fold: impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc { + move |acc, iter| iter.fold(acc, &mut fold) } - init + self.iter_fold(init, flatten(fold)) } #[inline] #[rustc_inherit_overflow_checks] fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - loop { - if let Some(ref mut front) = self.frontiter { - match front.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } - } - self.frontiter = match self.iter.next() { - Some(iterable) => Some(iterable.into_iter()), - _ => break, + #[inline] + #[rustc_inherit_overflow_checks] + fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> { + match iter.advance_by(n) { + Ok(()) => ControlFlow::BREAK, + Err(advanced) => ControlFlow::Continue(n - advanced), } } - self.frontiter = None; - - if let Some(ref mut back) = self.backiter { - match back.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } + match self.iter_try_fold(n, advance) { + ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), + _ => Ok(()), } + } - if rem > 0 { - return Err(n - rem); + #[inline] + fn count(self) -> usize { + #[inline] + #[rustc_inherit_overflow_checks] + fn count<U: Iterator>(acc: usize, iter: U) -> usize { + acc + iter.count() } - self.backiter = None; + self.iter_fold(0, count) + } + + #[inline] + fn last(self) -> Option<Self::Item> { + #[inline] + fn last<U: Iterator>(last: Option<U::Item>, iter: U) -> Option<U::Item> { + iter.last().or(last) + } - Ok(()) + self.iter_fold(None, last) } } @@ -438,105 +591,53 @@ where } #[inline] - fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R + fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( - backiter: &'a mut Option<T::IntoIter>, - fold: &'a mut impl FnMut(Acc, T::Item) -> R, - ) -> impl FnMut(Acc, T) -> R + 'a - where - T::IntoIter: DoubleEndedIterator, - { - move |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_rfold(acc, &mut *fold); - *backiter = Some(mid); - r - } + fn flatten<U: DoubleEndedIterator, Acc, R: Try<Output = Acc>>( + mut fold: impl FnMut(Acc, U::Item) -> R, + ) -> impl FnMut(Acc, &mut U) -> R { + move |acc, iter| iter.try_rfold(acc, &mut fold) } - if let Some(ref mut back) = self.backiter { - init = back.try_rfold(init, &mut fold)?; - } - self.backiter = None; - - init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?; - self.backiter = None; - - if let Some(ref mut front) = self.frontiter { - init = front.try_rfold(init, &mut fold)?; - } - self.frontiter = None; - - try { init } + self.iter_try_rfold(init, flatten(fold)) } #[inline] - fn rfold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc + fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn flatten<T: IntoIterator, Acc>( - fold: &mut impl FnMut(Acc, T::Item) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ - where - T::IntoIter: DoubleEndedIterator, - { - move |acc, x| x.into_iter().rfold(acc, &mut *fold) - } - - if let Some(back) = self.backiter { - init = back.rfold(init, &mut fold); + fn flatten<U: DoubleEndedIterator, Acc>( + mut fold: impl FnMut(Acc, U::Item) -> Acc, + ) -> impl FnMut(Acc, U) -> Acc { + move |acc, iter| iter.rfold(acc, &mut fold) } - init = self.iter.rfold(init, flatten(&mut fold)); - - if let Some(front) = self.frontiter { - init = front.rfold(init, &mut fold); - } - - init + self.iter_rfold(init, flatten(fold)) } #[inline] #[rustc_inherit_overflow_checks] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - loop { - if let Some(ref mut back) = self.backiter { - match back.advance_back_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, - } - } - match self.iter.next_back() { - Some(iterable) => self.backiter = Some(iterable.into_iter()), - _ => break, - } - } - - self.backiter = None; - - if let Some(ref mut front) = self.frontiter { - match front.advance_back_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, + #[inline] + #[rustc_inherit_overflow_checks] + fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> { + match iter.advance_back_by(n) { + Ok(()) => ControlFlow::BREAK, + Err(advanced) => ControlFlow::Continue(n - advanced), } } - if rem > 0 { - return Err(n - rem); + match self.iter_try_rfold(n, advance) { + ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), + _ => Ok(()), } - - self.frontiter = None; - - Ok(()) } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 916a26e24..bf4fabad3 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,6 +1,7 @@ use crate::iter::{InPlaceIterable, Iterator}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try}; +mod array_chunks; mod by_ref_sized; mod chain; mod cloned; @@ -32,6 +33,9 @@ pub use self::{ scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip, }; +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub use self::array_chunks::ArrayChunks; + #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index 2c283100f..dbf0ae9ec 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -33,21 +33,32 @@ where #[inline] fn next(&mut self) -> Option<I::Item> { if unlikely(self.n > 0) { - self.iter.nth(crate::mem::take(&mut self.n) - 1)?; + self.iter.nth(crate::mem::take(&mut self.n)) + } else { + self.iter.next() } - self.iter.next() } #[inline] fn nth(&mut self, n: usize) -> Option<I::Item> { - // Can't just add n + self.n due to overflow. if self.n > 0 { - let to_skip = self.n; - self.n = 0; - // nth(n) skips n+1 - self.iter.nth(to_skip - 1)?; + let skip: usize = crate::mem::take(&mut self.n); + // Checked add to handle overflow case. + let n = match skip.checked_add(n) { + Some(nth) => nth, + None => { + // In case of overflow, load skip value, before loading `n`. + // Because the amount of elements to iterate is beyond `usize::MAX`, this + // is split into two `nth` calls where the `skip` `nth` call is discarded. + self.iter.nth(skip - 1)?; + n + } + }; + // Load nth element including skip. + self.iter.nth(n) + } else { + self.iter.nth(n) } - self.iter.nth(n) } #[inline] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index d5c6aed5b..9514466bd 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -398,6 +398,8 @@ pub use self::traits::{ #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::adapters::zip; +#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] +pub use self::adapters::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::adapters::ByRefSized; #[stable(feature = "iter_cloned", since = "1.1.0")] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 275412b57..b2d08f4b0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; -use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ @@ -3316,6 +3316,49 @@ pub trait Iterator { Cycle::new(self) } + /// Returns an iterator over `N` elements of the iterator at a time. + /// + /// The chunks do not overlap. If `N` does not divide the length of the + /// iterator, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder] + /// function of the iterator. + /// + /// # Panics + /// + /// Panics if `N` is 0. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_array_chunks)] + /// + /// let mut iter = "lorem".chars().array_chunks(); + /// assert_eq!(iter.next(), Some(['l', 'o'])); + /// assert_eq!(iter.next(), Some(['r', 'e'])); + /// assert_eq!(iter.next(), None); + /// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']); + /// ``` + /// + /// ``` + /// #![feature(iter_array_chunks)] + /// + /// let data = [1, 1, 2, -2, 6, 0, 3, 1]; + /// // ^-----^ ^------^ + /// for [x, y, z] in data.iter().array_chunks() { + /// assert_eq!(x + y + z, 4); + /// } + /// ``` + #[track_caller] + #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] + fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N> + where + Self: Sized, + { + ArrayChunks::new(self) + } + /// Sums the elements of an iterator. /// /// Takes each element, adds them together, and returns the result. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49..5621d15c1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -93,6 +93,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] +#![allow(incomplete_features)] // // Library features: #![feature(const_align_offset)] @@ -130,7 +131,6 @@ #![feature(const_replace)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] -#![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] @@ -143,12 +143,14 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_default_impls)] +#![feature(const_unicode_case_lookup)] #![feature(const_unsafecell_get_mut)] #![feature(core_panic)] #![feature(duration_consts_float)] #![feature(maybe_uninit_uninit_array)] #![feature(ptr_metadata)] #![feature(slice_ptr_get)] +#![feature(slice_split_at_unchecked)] #![feature(str_internals)] #![feature(utf16_extra)] #![feature(utf16_extra_const)] @@ -157,9 +159,11 @@ #![feature(const_slice_from_ref)] #![feature(const_slice_index)] #![feature(const_is_char_boundary)] +#![feature(const_cstr_methods)] // // Language features: #![feature(abi_unadjusted)] +#![feature(adt_const_params)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] @@ -302,6 +306,8 @@ pub mod clone; pub mod cmp; pub mod convert; pub mod default; +#[cfg(not(bootstrap))] +pub mod error; pub mod marker; pub mod ops; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3a115a8b8..fd96e1ff7 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -350,10 +350,12 @@ macro_rules! matches { /// Unwraps a result or propagates its error. /// -/// The `?` operator was added to replace `try!` and should be used instead. -/// Furthermore, `try` is a reserved word in Rust 2018, so if you must use -/// it, you will need to use the [raw-identifier syntax][ris]: `r#try`. +/// The [`?` operator][propagating-errors] was added to replace `try!` +/// and should be used instead. Furthermore, `try` is a reserved word +/// in Rust 2018, so if you must use it, you will need to use the +/// [raw-identifier syntax][ris]: `r#try`. /// +/// [propagating-errors]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator /// [ris]: https://doc.rust-lang.org/nightly/rust-by-example/compatibility/raw_identifiers.html /// /// `try!` matches the given [`Result`]. In case of the `Ok` variant, the @@ -457,11 +459,12 @@ macro_rules! r#try { /// /// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects /// implementing either, as objects do not typically implement both. However, the module must -/// import the traits qualified so their names do not conflict: +/// avoid conflict between the trait names, such as by importing them as `_` or otherwise renaming +/// them: /// /// ``` -/// use std::fmt::Write as FmtWrite; -/// use std::io::Write as IoWrite; +/// use std::fmt::Write as _; +/// use std::io::Write as _; /// /// fn main() -> Result<(), Box<dyn std::error::Error>> { /// let mut s = String::new(); @@ -474,6 +477,23 @@ macro_rules! r#try { /// } /// ``` /// +/// If you also need the trait names themselves, such as to implement one or both on your types, +/// import the containing module and then name them with a prefix: +/// +/// ``` +/// # #![allow(unused_imports)] +/// use std::fmt::{self, Write as _}; +/// use std::io::{self, Write as _}; +/// +/// struct Example; +/// +/// impl fmt::Write for Example { +/// fn write_str(&mut self, _s: &str) -> core::fmt::Result { +/// unimplemented!(); +/// } +/// } +/// ``` +/// /// Note: This macro can be used in `no_std` setups as well. /// In a `no_std` setup you are responsible for the implementation details of the components. /// @@ -526,25 +546,6 @@ macro_rules! write { /// Ok(()) /// } /// ``` -/// -/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects -/// implementing either, as objects do not typically implement both. However, the module must -/// import the traits qualified so their names do not conflict: -/// -/// ``` -/// use std::fmt::Write as FmtWrite; -/// use std::io::Write as IoWrite; -/// -/// fn main() -> Result<(), Box<dyn std::error::Error>> { -/// let mut s = String::new(); -/// let mut v = Vec::new(); -/// -/// writeln!(&mut s, "{} {}", "abc", 123)?; // uses fmt::Write::write_fmt -/// writeln!(&mut v, "s = {:?}", s)?; // uses io::Write::write_fmt -/// assert_eq!(v, b"s = \"abc 123\\n\"\n"); -/// Ok(()) -/// } -/// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")] @@ -1015,7 +1016,7 @@ pub(crate) mod builtin { /// Concatenates literals into a byte slice. /// /// This macro takes any number of comma-separated literals, and concatenates them all into - /// one, yielding an expression of type `&[u8, _]`, which represents all of the literals + /// one, yielding an expression of type `&[u8; _]`, which represents all of the literals /// concatenated left-to-right. The literals passed can be any combination of: /// /// - byte literals (`b'r'`) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2c5789795..b8239ed88 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -343,7 +343,7 @@ pub trait StructuralEq { /// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get /// the error [E0204]. /// -/// [E0204]: ../../error-index.html#E0204 +/// [E0204]: ../../error_codes/E0204.html /// /// ## When *should* my type be `Copy`? /// @@ -800,6 +800,15 @@ impl<T: ?Sized> Unpin for *mut T {} #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] pub trait Destruct {} +/// A marker for tuple types. +/// +/// The implementation of this trait is built-in and cannot be implemented +/// for any user type. +#[unstable(feature = "tuple_trait", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "tuple_trait")] +#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +pub trait Tuple {} + /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4ea53608..2490c0767 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -54,9 +54,6 @@ use crate::slice; /// // The equivalent code with `MaybeUninit<i32>`: /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) -/// /// On top of that, remember that most types have additional invariants beyond merely /// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`] /// is considered initialized (under the current implementation; this does not constitute @@ -130,11 +127,8 @@ use crate::slice; /// MaybeUninit::uninit().assume_init() /// }; /// -/// // Dropping a `MaybeUninit` does nothing. Thus using raw pointer -/// // assignment instead of `ptr::write` does not cause the old -/// // uninitialized value to be dropped. Also if there is a panic during -/// // this loop, we have a memory leak, but there is no memory safety -/// // issue. +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. /// for elem in &mut data[..] { /// elem.write(vec![42]); /// } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 20b2d5e26..d2dd2941d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -665,14 +665,14 @@ pub unsafe fn zeroed<T>() -> T { /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit]. /// As the [`assume_init` documentation][assume_init] explains, /// [the Rust compiler assumes][inv] that values are properly initialized. -/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate -/// undefined behavior for returning a `bool` that is not definitely either `true` -/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// +/// Truly uninitialized memory like what gets returned here /// is special in that the compiler knows that it does not have a fixed value. /// This makes it undefined behavior to have uninitialized data in a variable even /// if that variable has an integer type. -/// (Notice that the rules around uninitialized integers are not finalized yet, but -/// until they are, it is advisable to avoid them.) +/// +/// Therefore, it is immediate undefined behavior to call this function on nearly all types, +/// including integer types and arrays of integer types, and even if the result is unused. /// /// [uninit]: MaybeUninit::uninit /// [assume_init]: MaybeUninit::assume_init diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index b59a5b89d..87a378631 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -9,20 +9,15 @@ message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." )] -pub unsafe trait BikeshedIntrinsicFrom< - Src, - Context, - const ASSUME_ALIGNMENT: bool, - const ASSUME_LIFETIMES: bool, - const ASSUME_VALIDITY: bool, - const ASSUME_VISIBILITY: bool, -> where +pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> +where Src: ?Sized, { } /// What transmutation safety conditions shall the compiler assume that *you* are checking? #[unstable(feature = "transmutability", issue = "99571")] +#[cfg_attr(not(bootstrap), lang = "transmute_opts")] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that @@ -33,11 +28,80 @@ pub struct Assume { /// that violates Rust's memory model. pub lifetimes: bool, + /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the + /// type and field privacy of the destination type (and sometimes of the source type, too). + pub safety: bool, + /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid /// instance of the destination type. pub validity: bool, +} - /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the - /// type and field privacy of the destination type (and sometimes of the source type, too). - pub visibility: bool, +impl Assume { + /// Do not assume that *you* have ensured any safety properties are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const NOTHING: Self = + Self { alignment: false, lifetimes: false, safety: false, validity: false }; + + /// Assume only that alignment conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING }; + + /// Assume only that lifetime conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING }; + + /// Assume only that safety conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING }; + + /// Assume only that dynamically-satisfiable validity conditions are met. + #[unstable(feature = "transmutability", issue = "99571")] + pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING }; + + /// Assume both `self` and `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn and(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment || other_assumptions.alignment, + lifetimes: self.lifetimes || other_assumptions.lifetimes, + safety: self.safety || other_assumptions.safety, + validity: self.validity || other_assumptions.validity, + } + } + + /// Assume `self`, excepting `other_assumptions`. + #[unstable(feature = "transmutability", issue = "99571")] + pub const fn but_not(self, other_assumptions: Self) -> Self { + Self { + alignment: self.alignment && !other_assumptions.alignment, + lifetimes: self.lifetimes && !other_assumptions.lifetimes, + safety: self.safety && !other_assumptions.safety, + validity: self.validity && !other_assumptions.validity, + } + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Add for Assume { + type Output = Assume; + + fn add(self, other_assumptions: Assume) -> Assume { + self.and(other_assumptions) + } +} + +// FIXME(jswrenn): This const op is not actually usable. Why? +// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926 +#[unstable(feature = "transmutability", issue = "99571")] +#[rustc_const_unstable(feature = "transmutability", issue = "99571")] +impl const core::ops::Sub for Assume { + type Output = Assume; + + fn sub(self, other_assumptions: Assume) -> Assume { + self.but_not(other_assumptions) + } } diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index fcfa95120..32b2afb72 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -26,7 +27,8 @@ impl ValidAlign { /// It must *not* be zero. #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - debug_assert!(align.is_power_of_two()); + // SAFETY: Precondition passed to the caller. + unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. @@ -34,9 +36,14 @@ impl ValidAlign { } #[inline] + pub(crate) const fn as_usize(self) -> usize { + self.0 as usize + } + + #[inline] pub(crate) const fn as_nonzero(self) -> NonZeroUsize { // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.0 as usize) } + unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } } /// Returns the base 2 logarithm of the alignment. @@ -46,6 +53,13 @@ impl ValidAlign { pub(crate) fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() } + + /// Returns the alignment for a type. + #[inline] + pub(crate) fn of<T>() -> Self { + // SAFETY: rustc ensures that type alignment is always a power of two. + unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) } + } } impl fmt::Debug for ValidAlign { diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index de85fdd6e..d2a21b6b3 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -137,7 +137,7 @@ macro_rules! define_bignum { // Find the most significant non-zero digit. let msd = digits.iter().rposition(|&x| x != 0); match msd { - Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1, + Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1, // There are no non-zero digits, i.e., the number is zero. _ => 0, } diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index f8edc3625..2019f71e6 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -32,7 +32,7 @@ impl Default for Decimal { impl Decimal { /// The maximum number of digits required to unambiguously round a float. /// - /// For a double-precision IEEE-754 float, this required 767 digits, + /// For a double-precision IEEE 754 float, this required 767 digits, /// so we store the max digits + 1. /// /// We can exactly represent a float in radix `b` from radix 2 if diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 1a223016d..1f6b40e5d 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,8 @@ //! Error types for conversion to integral types. use crate::convert::Infallible; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -144,3 +146,21 @@ impl fmt::Display for ParseIntError { self.__description().fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 6548ad2e5..2c6a0ba64 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f32` single-precision floating point type. +//! Constants for the `f32` single-precision floating point type. //! //! *[See also the `f32` primitive type][f32].* //! @@ -394,7 +394,7 @@ impl f32 { /// Not a Number (NaN). /// - /// Note that IEEE-745 doesn't define just a single NaN value; + /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, @@ -632,7 +632,7 @@ impl f32 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. @@ -654,7 +654,7 @@ impl f32 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. @@ -678,6 +678,106 @@ impl f32 { unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 } } + /// Returns the least number greater than `self`. + /// + /// Let `TINY` be the smallest representable positive `f32`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`]; + /// - if `self` is `-TINY`, this returns -0.0; + /// - if `self` is -0.0 or +0.0, this returns `TINY`; + /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`]; + /// - otherwise the unique least value greater than `self` is returned. + /// + /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_up().next_down()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// // f32::EPSILON is the difference between 1.0 and the next number up. + /// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON); + /// // But not for most numbers. + /// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON); + /// assert_eq!(16777216f32.next_up(), 16777218.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_up(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const TINY_BITS: u32 = 0x1; // Smallest positive f32. + const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + TINY_BITS + } else if bits == abs { + bits + 1 + } else { + bits - 1 + }; + Self::from_bits(next_bits) + } + + /// Returns the greatest number less than `self`. + /// + /// Let `TINY` be the smallest representable positive `f32`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`INFINITY`], this returns [`MAX`]; + /// - if `self` is `TINY`, this returns 0.0; + /// - if `self` is -0.0 or +0.0, this returns `-TINY`; + /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`]; + /// - otherwise the unique greatest value less than `self` is returned. + /// + /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_down().next_up()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// let x = 1.0f32; + /// // Clamp value into range [0, 1). + /// let clamped = x.clamp(0.0, 1.0f32.next_down()); + /// assert!(clamped < 1.0); + /// assert_eq!(clamped.next_up(), 1.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_down(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const NEG_TINY_BITS: u32 = 0x8000_0001; // Smallest (in magnitude) negative f32. + const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + NEG_TINY_BITS + } else if bits == abs { + bits - 1 + } else { + bits + 1 + }; + Self::from_bits(next_bits) + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` @@ -733,7 +833,7 @@ impl f32 { /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. /// This also matches the behavior of libm’s fmax. /// @@ -753,7 +853,7 @@ impl f32 { /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. /// This also matches the behavior of libm’s fmin. /// @@ -933,10 +1033,14 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f32_to_u32(x: f32) -> u32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } } @@ -947,9 +1051,9 @@ impl f32 { /// It turns out this is incredibly portable, for two reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. + /// * IEEE 754 very precisely specifies the bit layout of floats. /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most platforms /// (notably x86 and ARM) picked the interpretation that was ultimately /// standardized in 2008, but some didn't (notably MIPS). As a result, all @@ -1021,10 +1125,14 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u32_to_f32(x: u32) -> f32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) } } @@ -1282,15 +1390,14 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] - pub fn clamp(self, min: f32, max: f32) -> f32 { + pub fn clamp(mut self, min: f32, max: f32) -> f32 { assert!(min <= max); - let mut x = self; - if x < min { - x = min; + if self < min { + self = min; } - if x > max { - x = max; + if self > max { + self = max; } - x + self } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 75c92c2f8..fd3c18ce2 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1,4 +1,4 @@ -//! Constants specific to the `f64` double-precision floating point type. +//! Constants for the `f64` double-precision floating point type. //! //! *[See also the `f64` primitive type][f64].* //! @@ -393,7 +393,7 @@ impl f64 { /// Not a Number (NaN). /// - /// Note that IEEE-745 doesn't define just a single NaN value; + /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, @@ -624,7 +624,7 @@ impl f64 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. @@ -655,7 +655,7 @@ impl f64 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. @@ -688,6 +688,106 @@ impl f64 { self.is_sign_negative() } + /// Returns the least number greater than `self`. + /// + /// Let `TINY` be the smallest representable positive `f64`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`]; + /// - if `self` is `-TINY`, this returns -0.0; + /// - if `self` is -0.0 or +0.0, this returns `TINY`; + /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`]; + /// - otherwise the unique least value greater than `self` is returned. + /// + /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_up().next_down()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// // f64::EPSILON is the difference between 1.0 and the next number up. + /// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON); + /// // But not for most numbers. + /// assert!(0.1f64.next_up() < 0.1 + f64::EPSILON); + /// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_up(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const TINY_BITS: u64 = 0x1; // Smallest positive f64. + const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + TINY_BITS + } else if bits == abs { + bits + 1 + } else { + bits - 1 + }; + Self::from_bits(next_bits) + } + + /// Returns the greatest number less than `self`. + /// + /// Let `TINY` be the smallest representable positive `f64`. Then, + /// - if `self.is_nan()`, this returns `self`; + /// - if `self` is [`INFINITY`], this returns [`MAX`]; + /// - if `self` is `TINY`, this returns 0.0; + /// - if `self` is -0.0 or +0.0, this returns `-TINY`; + /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`]; + /// - otherwise the unique greatest value less than `self` is returned. + /// + /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x` + /// is finite `x == x.next_down().next_up()` also holds. + /// + /// ```rust + /// #![feature(float_next_up_down)] + /// let x = 1.0f64; + /// // Clamp value into range [0, 1). + /// let clamped = x.clamp(0.0, 1.0f64.next_down()); + /// assert!(clamped < 1.0); + /// assert_eq!(clamped.next_up(), 1.0); + /// ``` + /// + /// [`NEG_INFINITY`]: Self::NEG_INFINITY + /// [`INFINITY`]: Self::INFINITY + /// [`MIN`]: Self::MIN + /// [`MAX`]: Self::MAX + #[unstable(feature = "float_next_up_down", issue = "91399")] + #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")] + pub const fn next_down(self) -> Self { + // We must use strictly integer arithmetic to prevent denormals from + // flushing to zero after an arithmetic operation on some platforms. + const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64. + const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff; + + let bits = self.to_bits(); + if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() { + return self; + } + + let abs = bits & CLEAR_SIGN_MASK; + let next_bits = if abs == 0 { + NEG_TINY_BITS + } else if bits == abs { + bits - 1 + } else { + bits + 1 + }; + Self::from_bits(next_bits) + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` @@ -744,7 +844,7 @@ impl f64 { /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. /// This also matches the behavior of libm’s fmax. /// @@ -764,7 +864,7 @@ impl f64 { /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. - /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. /// This also matches the behavior of libm’s fmin. /// @@ -926,10 +1026,14 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_f64_to_u64(rt: f64) -> u64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::<f64, u64>(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } } @@ -940,9 +1044,9 @@ impl f64 { /// It turns out this is incredibly portable, for two reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. + /// * IEEE 754 very precisely specifies the bit layout of floats. /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most platforms /// (notably x86 and ARM) picked the interpretation that was ultimately /// standardized in 2008, but some didn't (notably MIPS). As a result, all @@ -1019,10 +1123,14 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) }; + + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 + fn rt_u64_to_f64(rt: u64) -> f64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::<u64, f64>(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) } } @@ -1280,15 +1388,14 @@ impl f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] #[inline] - pub fn clamp(self, min: f64, max: f64) -> f64 { + pub fn clamp(mut self, min: f64, max: f64) -> f64 { assert!(min <= max); - let mut x = self; - if x < min { - x = min; + if self < min { + self = min; } - if x > max { - x = max; + if self > max { + self = max; } - x + self } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a66de19ba..e7deb728d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1518,6 +1518,51 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self + rhs + carry` without the ability to overflow. + /// + /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")] + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ", + "(-1, true));" + )] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + /// + /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add): + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as $SelfT); + (c, b != d) + } + /// Calculates `self` + `rhs` with an unsigned `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -1569,6 +1614,39 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self - rhs - borrow` without the ability to overflow. + /// + /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as $SelfT); + (c, b != d) + } + /// Calculates `self` - `rhs` with an unsigned `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating @@ -2204,7 +2282,7 @@ macro_rules! int_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics @@ -2217,7 +2295,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2226,8 +2304,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2250,7 +2328,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2259,8 +2337,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2283,7 +2361,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2292,8 +2370,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2311,20 +2389,20 @@ macro_rules! int_impl { /// Returns `None` if the number is negative or zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option<u32> { + pub const fn checked_ilog(self, base: Self) -> Option<u32> { if self <= 0 || base <= 1 { None } else { @@ -2333,7 +2411,7 @@ macro_rules! int_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -2354,13 +2432,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option<u32> { + pub const fn checked_ilog2(self) -> Option<u32> { if self <= 0 { None } else { @@ -2378,13 +2456,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option<u32> { + pub const fn checked_ilog10(self) -> Option<u32> { if self > 0 { Some(int_log10::$ActualT(self as $ActualT)) } else { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f481399fd..ab17aa0c8 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,6 +3,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -57,6 +59,16 @@ pub use wrapping::Wrapping; #[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; +#[cfg(not(bootstrap))] +#[cfg(not(no_fp_fmt_parse))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; @@ -623,7 +635,7 @@ impl u8 { /// /// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or /// - U+003A ..= U+0040 `: ; < = > ? @`, or - /// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+005B ..= U+0060 `` [ \ ] ^ _ ` ``, or /// - U+007B ..= U+007E `{ | } ~` /// /// # Examples diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 4de0a0cf5..532a09736 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -56,7 +56,7 @@ macro_rules! nonzero_integers { pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. unsafe { - core::intrinsics::assert_unsafe_precondition!(n != 0); + core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0); Self(n) } } @@ -309,8 +309,8 @@ macro_rules! nonzero_unsigned_operations { ( $( $Ty: ident($Int: ident); )+ ) => { $( impl $Ty { - /// Add an unsigned integer to a non-zero value. - /// Check for overflow and return [`None`] on overflow + /// Adds an unsigned integer to a non-zero value. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// @@ -346,7 +346,7 @@ macro_rules! nonzero_unsigned_operations { } } - /// Add an unsigned integer to a non-zero value. + /// Adds an unsigned integer to a non-zero value. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -377,7 +377,7 @@ macro_rules! nonzero_unsigned_operations { unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } } - /// Add an unsigned integer to a non-zero value, + /// Adds an unsigned integer to a non-zero value, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -409,7 +409,7 @@ macro_rules! nonzero_unsigned_operations { } /// Returns the smallest power of two greater than or equal to n. - /// Check for overflow and return [`None`] + /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. /// @@ -450,7 +450,7 @@ macro_rules! nonzero_unsigned_operations { /// Returns the base 2 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log2`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog2`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -460,22 +460,22 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log2(self) -> u32 { + pub const fn ilog2(self) -> u32 { Self::BITS - 1 - self.leading_zeros() } /// Returns the base 10 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log10`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog10`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -485,15 +485,15 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log10(self) -> u32 { + pub const fn ilog10(self) -> u32 { super::int_log10::$Int(self.0) } } @@ -545,7 +545,7 @@ macro_rules! nonzero_signed_operations { } /// Checked absolute value. - /// Check for overflow and returns [`None`] if + /// Checks for overflow and returns [`None`] if #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] /// The result cannot be zero. /// @@ -740,8 +740,8 @@ macro_rules! nonzero_unsigned_signed_operations { ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { $( impl $Ty { - /// Multiply two non-zero integers together. - /// Check for overflow and return [`None`] on overflow. + /// Multiplies two non-zero integers together. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples @@ -777,7 +777,7 @@ macro_rules! nonzero_unsigned_signed_operations { } } - /// Multiply two non-zero integers together. + /// Multiplies two non-zero integers together. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -809,7 +809,7 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } } - /// Multiply two non-zero integers together, + /// Multiplies two non-zero integers together, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -849,8 +849,8 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } } - /// Raise non-zero value to an integer power. - /// Check for overflow and return [`None`] on overflow. + /// Raises non-zero value to an integer power. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 733655442..46fd7f2d0 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -688,7 +688,7 @@ macro_rules! uint_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics @@ -700,7 +700,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -709,8 +709,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -733,7 +733,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -742,8 +742,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -766,7 +766,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -775,8 +775,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -794,20 +794,20 @@ macro_rules! uint_impl { /// Returns `None` if the number is zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option<u32> { + pub const fn checked_ilog(self, base: Self) -> Option<u32> { if self <= 0 || base <= 1 { None } else { @@ -816,7 +816,7 @@ macro_rules! uint_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -837,15 +837,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option<u32> { + pub const fn checked_ilog2(self) -> Option<u32> { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log2()) + Some(x.ilog2()) } else { None } @@ -859,15 +859,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option<u32> { + pub const fn checked_ilog10(self) -> Option<u32> { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log10()) + Some(x.ilog10()) } else { None } diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index aa654aa55..de9ddb852 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -156,7 +156,7 @@ pub trait Drop { /// handled by the compiler, but when using unsafe code, can sometimes occur /// unintentionally, particularly when using [`ptr::drop_in_place`]. /// - /// [E0040]: ../../error-index.html#E0040 + /// [E0040]: ../../error_codes/E0040.html /// [`panic!`]: crate::panic! /// [`mem::drop`]: drop /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index c5a194b7d..8fdf22cf6 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -250,9 +250,10 @@ pub trait FnOnce<Args> { mod impls { #[stable(feature = "rust1", since = "1.0.0")] - impl<A, F: ?Sized> Fn<A> for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl<A, F: ?Sized> const Fn<A> for &F where - F: Fn<A>, + F: ~const Fn<A>, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -260,9 +261,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<A, F: ?Sized> FnMut<A> for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl<A, F: ?Sized> const FnMut<A> for &F where - F: Fn<A>, + F: ~const Fn<A>, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -270,9 +272,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<A, F: ?Sized> FnOnce<A> for &F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl<A, F: ?Sized> const FnOnce<A> for &F where - F: Fn<A>, + F: ~const Fn<A>, { type Output = F::Output; @@ -282,9 +285,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<A, F: ?Sized> FnMut<A> for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl<A, F: ?Sized> const FnMut<A> for &mut F where - F: FnMut<A>, + F: ~const FnMut<A>, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -292,9 +296,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<A, F: ?Sized> FnOnce<A> for &mut F + #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] + impl<A, F: ?Sized> const FnOnce<A> for &mut F where - F: FnMut<A>, + F: ~const FnMut<A>, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs index b651b7b23..3ebd6f8cd 100644 --- a/library/core/src/ops/generator.rs +++ b/library/core/src/ops/generator.rs @@ -83,7 +83,7 @@ pub trait Generator<R = ()> { /// `return` statement or implicitly as the last expression of a generator /// literal. For example futures would use this as `Result<T, E>` as it /// represents a completed future. - #[lang = "generator_return"] + #[cfg_attr(bootstrap, lang = "generator_return")] type Return; /// Resumes the execution of this generator. diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index a3b148473..d29ae3561 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -677,7 +677,7 @@ pub enum Bound<T> { impl<T> Bound<T> { /// Converts from `&Bound<T>` to `Bound<&T>`. #[inline] - #[unstable(feature = "bound_as_ref", issue = "80996")] + #[stable(feature = "bound_as_ref_shared", since = "1.65.0")] pub fn as_ref(&self) -> Bound<&T> { match *self { Included(ref x) => Included(x), diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 02f7f62bf..10f041344 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -222,7 +222,87 @@ pub trait Try: FromResidual { /// 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. -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result<T, E>", + R = "std::option::Option<std::convert::Infallible>" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result<T, E>", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option<T>", + R = "std::result::Result<T, E>", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option<T>", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow<B, C>", + R = "std::ops::ControlFlow<B, C>", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \ + can only be used on other `ControlFlow<B, _>`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow<B, C>", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + parent_label = "this function should return `Result` or `Option` to accept `?`" + ), +))] +#[cfg_attr(bootstrap, rustc_on_unimplemented( on( all( from_desugaring = "QuestionMark", @@ -301,7 +381,7 @@ pub trait Try: FromResidual { label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), -)] +))] #[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual<R = <Self as Try>::Residual> { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index bca73cb77..934175863 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1189,6 +1189,12 @@ impl<T> Option<T> { /// Returns [`None`] if the option is [`None`], otherwise returns `optb`. /// + /// Arguments passed to `and` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`and_then`], which is + /// lazily evaluated. + /// + /// [`and_then`]: Option::and_then + /// /// # Examples /// /// ``` diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 7a575a88e..d4afe0f53 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -190,11 +190,11 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>( right: &str, args: Option<fmt::Arguments<'_>>, ) -> ! { - // Use the Display implementation to display the pattern. + // The pattern is a string so it can be displayed directly. struct Pattern<'a>(&'a str); impl fmt::Debug for Pattern<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.0, f) + f.write_str(self.0) } } assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args); diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index b8e546164..242f44ade 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -801,11 +801,53 @@ mod prim_array {} /// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>()); /// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>()); /// ``` +/// +/// ## Trait Implementations +/// +/// Some traits are implemented for slices if the element type implements +/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`]. +/// +/// ## Iteration +/// +/// The slices implement `IntoIterator`. The iterator yields references to the +/// slice elements. +/// +/// ``` +/// let numbers: &[i32] = &[0, 1, 2]; +/// for n in numbers { +/// println!("{n} is a number!"); +/// } +/// ``` +/// +/// The mutable slice yields mutable references to the elements: +/// +/// ``` +/// let mut scores: &mut [i32] = &mut [7, 8, 9]; +/// for score in scores { +/// *score += 1; +/// } +/// ``` +/// +/// This iterator yields mutable references to the slice's elements, so while +/// the element type of the slice is `i32`, the element type of the iterator is +/// `&mut i32`. +/// +/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default +/// iterators. +/// * Further methods that return iterators are [`.split`], [`.splitn`], +/// [`.chunks`], [`.windows`] and more. +/// +/// [`Hash`]: core::hash::Hash +/// [`.iter`]: slice::iter +/// [`.iter_mut`]: slice::iter_mut +/// [`.split`]: slice::split +/// [`.splitn`]: slice::splitn +/// [`.chunks`]: slice::chunks +/// [`.windows`]: slice::windows #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice {} #[doc(primitive = "str")] -// /// String slices. /// /// *[See also the `std::str` module](crate::str).* @@ -816,19 +858,22 @@ mod prim_slice {} /// /// String slices are always valid UTF-8. /// -/// # Examples +/// # Basic Usage /// /// String literals are string slices: /// /// ``` -/// let hello = "Hello, world!"; -/// -/// // with an explicit type annotation -/// let hello: &'static str = "Hello, world!"; +/// let hello_world = "Hello, World!"; /// ``` /// -/// They are `'static` because they're stored directly in the final binary, and -/// so will be valid for the `'static` duration. +/// Here we have declared a string slice initialized with a string literal. +/// String literals have a static lifetime, which means the string `hello_world` +/// is guaranteed to be valid for the duration of the entire program. +/// We can explicitly specify `hello_world`'s lifetime as well: +/// +/// ``` +/// let hello_world: &'static str = "Hello, world!"; +/// ``` /// /// # Representation /// @@ -996,7 +1041,7 @@ impl<T> (T,) {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Clone> Clone for (T,) { fn clone(&self) -> Self { @@ -1007,7 +1052,7 @@ impl<T: Clone> Clone for (T,) { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Copy> Copy for (T,) { // empty @@ -1178,7 +1223,7 @@ mod prim_usize {} #[doc(alias = "&")] #[doc(alias = "&mut")] // -/// References, both shared and mutable. +/// References, `&T` and `&mut T`. /// /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` /// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or @@ -1484,13 +1529,12 @@ mod prim_fn {} // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls #[doc(hidden)] -#[cfg(not(bootstrap))] impl<Ret, T> fn(T) -> Ret {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl<Ret, T> Clone for fn(T) -> Ret { fn clone(&self) -> Self { @@ -1501,7 +1545,7 @@ impl<Ret, T> Clone for fn(T) -> Ret { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(fake_variadic))] +#[doc(fake_variadic)] /// This trait is implemented on function pointers with any number of arguments. impl<Ret, T> Copy for fn(T) -> Ret { // empty diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e0655d68d..43e883b8b 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -36,7 +36,10 @@ impl<T: ?Sized> *const T { pub const fn is_null(self) -> bool { // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. - (self as *const u8).guaranteed_eq(null()) + match (self as *const u8).guaranteed_eq(null()) { + None => false, + Some(res) => res, + } } /// Casts to a pointer of another type. @@ -95,8 +98,8 @@ impl<T: ?Sized> *const T { /// /// This is a bit safer than `as` because it wouldn't silently change the type if the code is /// refactored. - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_mut(self) -> *mut T { self as _ } @@ -154,7 +157,7 @@ impl<T: ?Sized> *const T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the @@ -249,7 +252,7 @@ impl<T: ?Sized> *const T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::<u8>().wrapping_offset(offset).cast::<T>() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. @@ -559,6 +562,21 @@ impl<T: ?Sized> *const T { from_raw_parts::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self)) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "98290")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *const T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask); + from_raw_parts::<T>(this, metadata(self)) + } + /// Calculates the distance between two pointers. The returned value is in /// units of T: the distance in bytes divided by `mem::size_of::<T>()`. /// @@ -641,7 +659,7 @@ impl<T: ?Sized> *const T { /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -740,9 +758,12 @@ impl<T: ?Sized> *const T { where T: Sized, { + let this = self; // SAFETY: The comparison has no side-effects, and the intrinsic // does this check internally in the CTFE implementation. - unsafe { assert_unsafe_precondition!(self >= origin) }; + unsafe { + assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin) + }; let pointee_size = mem::size_of::<T>(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); @@ -752,20 +773,16 @@ impl<T: ?Sized> *const T { /// Returns whether two pointers are guaranteed to be equal. /// - /// At runtime this function behaves like `self == other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), /// it is not always possible to determine equality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be equal. - /// But when it returns `true`, the pointers are guaranteed to be equal. + /// spuriously return `None` for pointers that later actually turn out to have its equality known. + /// But when it returns `Some`, the pointers' equality is guaranteed to be known. /// - /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_ne`]: #method.guaranteed_ne - /// - /// The return value may change depending on the compiler version and unsafe code must not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -774,29 +791,28 @@ impl<T: ?Sized> *const T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_eq(self, other: *const T) -> bool + pub const fn guaranteed_eq(self, other: *const T) -> Option<bool> where T: Sized, { - intrinsics::ptr_guaranteed_eq(self, other) + match intrinsics::ptr_guaranteed_cmp(self as _, other as _) { + 2 => None, + other => Some(other == 1), + } } - /// Returns whether two pointers are guaranteed to be unequal. + /// Returns whether two pointers are guaranteed to be inequal. /// - /// At runtime this function behaves like `self != other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), - /// it is not always possible to determine the inequality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be unequal. - /// But when it returns `true`, the pointers are guaranteed to be unequal. - /// - /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_eq`]: #method.guaranteed_eq + /// it is not always possible to determine inequality of two pointers, so this function may + /// spuriously return `None` for pointers that later actually turn out to have its inequality known. + /// But when it returns `Some`, the pointers' inequality is guaranteed to be known. /// - /// The return value may change depending on the compiler version and unsafe code must not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -805,11 +821,14 @@ impl<T: ?Sized> *const T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_ne(self, other: *const T) -> bool + pub const fn guaranteed_ne(self, other: *const T) -> Option<bool> where T: Sized, { - intrinsics::ptr_guaranteed_ne(self, other) + match self.guaranteed_eq(other) { + None => None, + Some(eq) => Some(!eq), + } } /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). @@ -1267,20 +1286,21 @@ impl<T: ?Sized> *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr(); /// let offset = ptr.align_offset(align_of::<u16>()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::<u16>(); + /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7])); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] @@ -1336,11 +1356,8 @@ impl<T: ?Sized> *const T { panic!("is_aligned_to: align is not a power-of-two"); } - // SAFETY: `is_power_of_two()` will return `false` for zero. - unsafe { core::intrinsics::assume(align != 0) }; - // Cast is needed for `T: !Sized` - self.cast::<u8>().addr() % align == 0 + self.cast::<u8>().addr() & align - 1 == 0 } } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index cd5edee04..8865c834c 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -180,7 +180,6 @@ pub struct DynMetadata<Dyn: ?Sized> { phantom: crate::marker::PhantomData<Dyn>, } -#[cfg(not(bootstrap))] extern "C" { /// Opaque type for accessing vtables. /// @@ -189,17 +188,6 @@ extern "C" { type VTable; } -/// The common prefix of all vtables. It is followed by function pointers for trait methods. -/// -/// Private implementation detail of `DynMetadata::size_of` etc. -#[repr(C)] -#[cfg(bootstrap)] -struct VTable { - drop_in_place: fn(*mut ()), - size_of: usize, - align_of: usize, -} - impl<Dyn: ?Sized> DynMetadata<Dyn> { /// Returns the size of the type associated with this vtable. #[inline] @@ -207,9 +195,6 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> { // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw". // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the // `Send` part! - #[cfg(bootstrap)] - return self.vtable_ptr.size_of; - #[cfg(not(bootstrap))] // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) @@ -219,9 +204,6 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> { /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { - #[cfg(bootstrap)] - return self.vtable_ptr.align_of; - #[cfg(not(bootstrap))] // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 40e28e636..e976abed7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -90,7 +90,7 @@ //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue //! to conflate these notions). This would potentially make it possible to more efficiently //! target platforms where pointers are larger than offsets, such as CHERI and maybe some -//! segmented architecures. +//! segmented architectures. //! //! ## Provenance //! @@ -172,7 +172,7 @@ //! a pointer to a usize is generally an operation which *only* extracts the address. It is //! therefore *impossible* to construct a valid pointer from a usize because there is no way //! to restore the address-space and provenance. In other words, pointer-integer-pointer -//! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable). +//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable). //! //! The key insight to making this model *at all* viable is the [`with_addr`][] method: //! @@ -272,7 +272,7 @@ //! //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can //! be used for sentinel values like `null` *or* to represent a tagged pointer that will -//! never be dereferencable. In general, it is always sound for an integer to pretend +//! never be dereferenceable. In general, it is always sound for an integer to pretend //! to be a pointer "for fun" as long as you don't use operations on it which require //! it to be valid (offset, read, write, etc). //! @@ -603,6 +603,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T { #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn from_exposed_addr<T>(addr: usize) -> *const T where T: Sized, @@ -639,6 +640,7 @@ where #[must_use] #[inline] #[unstable(feature = "strict_provenance", issue = "95228")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T where T: Sized, @@ -884,7 +886,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { // SAFETY: the caller must guarantee that `x` and `y` are // valid for writes and properly aligned. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) => is_aligned_and_not_null(x) && is_aligned_and_not_null(y) && is_nonoverlapping(x, y, count) @@ -981,7 +983,7 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T { // and cannot overlap `src` since `dst` must point to a distinct // allocated object. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); mem::swap(&mut *dst, &mut src); // cannot overlap } src @@ -1468,7 +1470,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { pub unsafe fn read_volatile<T>(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src)); + assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src)); intrinsics::volatile_load(src) } } @@ -1539,7 +1541,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); intrinsics::volatile_store(dst, src); } } @@ -1834,7 +1836,7 @@ macro_rules! maybe_fnptr_doc { $item }; ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for function pointers with up to twelve arguments."] #[$meta] $item diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index fc3dd2a9b..e277b8181 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -35,7 +35,10 @@ impl<T: ?Sized> *mut T { pub const fn is_null(self) -> bool { // Compare via a cast to a thin pointer, so fat pointers are only // considering their "data" part for null-ness. - (self as *mut u8).guaranteed_eq(null_mut()) + match (self as *mut u8).guaranteed_eq(null_mut()) { + None => false, + Some(res) => res, + } } /// Casts to a pointer of another type. @@ -100,8 +103,8 @@ impl<T: ?Sized> *mut T { /// coercion. /// /// [`cast_mut`]: #method.cast_mut - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_const(self) -> *const T { self as _ } @@ -160,7 +163,7 @@ impl<T: ?Sized> *mut T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the @@ -255,7 +258,7 @@ impl<T: ?Sized> *mut T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::<u8>().wrapping_offset(offset).cast::<T>() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. @@ -575,6 +578,21 @@ impl<T: ?Sized> *mut T { ) } + /// Masks out bits of the pointer according to a mask. + /// + /// This is convenience for `ptr.map_addr(|a| a & mask)`. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[cfg(not(bootstrap))] + #[unstable(feature = "ptr_mask", issue = "98290")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + pub fn mask(self, mask: usize) -> *mut T { + let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut (); + from_raw_parts_mut::<T>(this, metadata(self)) + } + /// Returns `None` if the pointer is null, or else returns a unique reference to /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`] /// must be used instead. @@ -682,20 +700,16 @@ impl<T: ?Sized> *mut T { /// Returns whether two pointers are guaranteed to be equal. /// - /// At runtime this function behaves like `self == other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), /// it is not always possible to determine equality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be equal. - /// But when it returns `true`, the pointers are guaranteed to be equal. + /// spuriously return `None` for pointers that later actually turn out to have its equality known. + /// But when it returns `Some`, the pointers' equality is guaranteed to be known. /// - /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. - /// - /// [`guaranteed_ne`]: #method.guaranteed_ne - /// - /// The return value may change depending on the compiler version and unsafe code might not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -704,29 +718,25 @@ impl<T: ?Sized> *mut T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const fn guaranteed_eq(self, other: *mut T) -> bool + pub const fn guaranteed_eq(self, other: *mut T) -> Option<bool> where T: Sized, { - intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _) + (self as *const T).guaranteed_eq(other as _) } - /// Returns whether two pointers are guaranteed to be unequal. + /// Returns whether two pointers are guaranteed to be inequal. /// - /// At runtime this function behaves like `self != other`. + /// At runtime this function behaves like `Some(self == other)`. /// However, in some contexts (e.g., compile-time evaluation), - /// it is not always possible to determine the inequality of two pointers, so this function may - /// spuriously return `false` for pointers that later actually turn out to be unequal. - /// But when it returns `true`, the pointers are guaranteed to be unequal. - /// - /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer - /// comparisons for which both functions return `false`. + /// it is not always possible to determine inequality of two pointers, so this function may + /// spuriously return `None` for pointers that later actually turn out to have its inequality known. + /// But when it returns `Some`, the pointers' inequality is guaranteed to be known. /// - /// [`guaranteed_eq`]: #method.guaranteed_eq - /// - /// The return value may change depending on the compiler version and unsafe code might not + /// The return value may change from `Some` to `None` and vice versa depending on the compiler + /// version and unsafe code must not /// rely on the result of this function for soundness. It is suggested to only use this function - /// for performance optimizations where spurious `false` return values by this function do not + /// for performance optimizations where spurious `None` return values by this function do not /// affect the outcome, but just the performance. /// The consequences of using this method to make runtime and compile-time code behave /// differently have not been explored. This method should not be used to introduce such @@ -735,11 +745,11 @@ impl<T: ?Sized> *mut T { #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] - pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool + pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool> where T: Sized, { - intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _) + (self as *const T).guaranteed_ne(other as _) } /// Calculates the distance between two pointers. The returned value is in @@ -824,7 +834,7 @@ impl<T: ?Sized> *mut T { /// } /// ``` #[stable(feature = "ptr_offset_from", since = "1.47.0")] - #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")] + #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn offset_from(self, origin: *const T) -> isize @@ -1545,20 +1555,23 @@ impl<T: ?Sized> *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let mut x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr(); /// let offset = ptr.align_offset(align_of::<u16>()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::<u16>(); + /// *u16_ptr = 0; + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] @@ -1614,11 +1627,8 @@ impl<T: ?Sized> *mut T { panic!("is_aligned_to: align is not a power-of-two"); } - // SAFETY: `is_power_of_two()` will return `false` for zero. - unsafe { core::intrinsics::assume(align != 0) }; - // Cast is needed for `T: !Sized` - self.cast::<u8>().addr() % align == 0 + self.cast::<u8>().addr() & align - 1 == 0 } } diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 45b052c82..76eaa191f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1285,6 +1285,11 @@ impl<T, E> Result<T, E> { /// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`. /// + /// Arguments passed to `and` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`and_then`], which is + /// lazily evaluated. + /// + /// [`and_then`]: Result::and_then /// /// # Examples /// @@ -1771,40 +1776,6 @@ impl<T, E> Result<Result<T, E>, E> { } } -impl<T> Result<T, T> { - /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if - /// `self` is `Err`. - /// - /// In other words, this function returns the value (the `T`) of a - /// `Result<T, T>`, regardless of whether or not that result is `Ok` or - /// `Err`. - /// - /// This can be useful in conjunction with APIs such as - /// [`Atomic*::compare_exchange`], or [`slice::binary_search`], but only in - /// cases where you don't care if the result was `Ok` or not. - /// - /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange - /// - /// # Examples - /// - /// ``` - /// #![feature(result_into_ok_or_err)] - /// let ok: Result<u32, u32> = Ok(3); - /// let err: Result<u32, u32> = Err(4); - /// - /// assert_eq!(ok.into_ok_or_err(), 3); - /// assert_eq!(err.into_ok_or_err(), 4); - /// ``` - #[inline] - #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")] - pub const fn into_ok_or_err(self) -> T { - match self { - Ok(v) => v, - Err(v) => v, - } - } -} - // This is a separate function to reduce the code size of the methods #[cfg(not(feature = "panic_immediate_abort"))] #[inline(never)] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 63715a6b8..5e5399acc 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -215,8 +215,6 @@ impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> { } } #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] -impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {} -#[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> iter::FusedIterator for EscapeAscii<'a> {} #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] impl<'a> fmt::Display for EscapeAscii<'a> { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index fd7ecf3da..3403a5a86 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -48,10 +48,12 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range start index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice start index is out of range for slice"); } @@ -69,10 +71,12 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range end index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice end index is out of range for slice"); } @@ -88,10 +92,12 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { panic!("slice index starts at {index} but ends at {end}"); } +#[track_caller] const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { panic!("slice index start is larger than end"); } @@ -217,21 +223,23 @@ unsafe impl<T> const SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + let this = self; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len()); slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + let this = self; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len()); slice.as_mut_ptr().add(self) } } @@ -276,22 +284,26 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *const [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *mut [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index f1e659309..395c56784 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::<T>() == 0 { - (ptr as *const u8).wrapping_add(slice.len()) as *const T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::<T>() == 0 { - (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -2754,10 +2754,10 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { None => 0, }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (head, tail) = unsafe { self.v.split_at_mut(start) }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (nth, _) = unsafe { tail.split_at_mut(end - start) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c05242222..6c9e7574e 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -64,7 +64,7 @@ macro_rules! iterator { // backwards by `n`. `n` must not exceed `self.len()`. macro_rules! zst_shrink { ($self: ident, $n: ident) => { - $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + $self.end = $self.end.wrapping_byte_sub($n); } } @@ -82,7 +82,7 @@ macro_rules! iterator { // returning the old start. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::<T>() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -90,7 +90,7 @@ macro_rules! iterator { let old = self.ptr.as_ptr(); // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) }; old } } @@ -99,7 +99,7 @@ macro_rules! iterator { // returning the new end. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::<T>() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -107,7 +107,7 @@ macro_rules! iterator { // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // which is guaranteed to not overflow an `isize`. Also, the resulting pointer // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; + self.end = unsafe { self.end.sub(offset) }; self.end } } @@ -180,7 +180,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { - self.post_inc_start(n as isize); + self.post_inc_start(n); Some(next_unchecked!(self)) } } @@ -189,7 +189,7 @@ macro_rules! iterator { fn advance_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.post_inc_start(advance as isize) }; + unsafe { self.post_inc_start(advance) }; if advance == n { Ok(()) } else { Err(advance) } } @@ -375,7 +375,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. unsafe { - self.pre_dec_end(n as isize); + self.pre_dec_end(n); Some(next_back_unchecked!(self)) } } @@ -384,7 +384,7 @@ macro_rules! iterator { fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.pre_dec_end(advance as isize) }; + unsafe { self.pre_dec_end(advance) }; if advance == n { Ok(()) } else { Err(advance) } } } diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index dffeaf6a8..7de1f48e6 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -16,35 +16,51 @@ const USIZE_BYTES: usize = mem::size_of::<usize>(); /// bytes where the borrow propagated all the way to the most significant /// bit." #[inline] -fn contains_zero_byte(x: usize) -> bool { +const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } #[cfg(target_pointer_width = "16")] #[inline] -fn repeat_byte(b: u8) -> usize { +const fn repeat_byte(b: u8) -> usize { (b as usize) << 8 | b as usize } #[cfg(not(target_pointer_width = "16"))] #[inline] -fn repeat_byte(b: u8) -> usize { +const fn repeat_byte(b: u8) -> usize { (b as usize) * (usize::MAX / 255) } /// Returns the first index matching the byte `x` in `text`. #[must_use] #[inline] -pub fn memchr(x: u8, text: &[u8]) -> Option<usize> { - // Fast path for small slices +pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> { + // Fast path for small slices. if text.len() < 2 * USIZE_BYTES { - return text.iter().position(|elt| *elt == x); + return memchr_naive(x, text); } - memchr_general_case(x, text) + memchr_aligned(x, text) } -fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> { +#[inline] +const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> { + let mut i = 0; + + // FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`. + while i < text.len() { + if text[i] == x { + return Some(i); + } + + i += 1; + } + + None +} + +const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> { // Scan for a single byte value by reading two `usize` words at a time. // // Split `text` in three parts @@ -59,7 +75,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> { if offset > 0 { offset = cmp::min(offset, len); - if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { + if let Some(index) = memchr_naive(x, &text[..offset]) { return Some(index); } } @@ -84,7 +100,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> { } // Find the byte after the point the body loop stopped. - text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) + // FIXME(const-hack): Use `?` instead. + if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None } } /// Returns the last index matching the byte `x` in `text`. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e6ca6ef82..6a7150d29 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -656,10 +656,11 @@ impl<T> [T] { #[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { - let ptr = self.as_mut_ptr(); + let this = self; + let ptr = this.as_mut_ptr(); // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - assert_unsafe_precondition!(a < self.len() && b < self.len()); + assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len()); ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -674,8 +675,9 @@ impl<T> [T] { /// assert!(v == [3, 2, 1]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_reverse", issue = "100784")] #[inline] - pub fn reverse(&mut self) { + pub const fn reverse(&mut self) { let half_len = self.len() / 2; let Range { start, end } = self.as_mut_ptr_range(); @@ -698,9 +700,9 @@ impl<T> [T] { revswap(front_half, back_half, half_len); #[inline] - fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) { - debug_assert_eq!(a.len(), n); - debug_assert_eq!(b.len(), n); + const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) { + debug_assert!(a.len() == n); + debug_assert!(b.len() == n); // Because this function is first compiled in isolation, // this check tells LLVM that the indexing below is @@ -708,8 +710,10 @@ impl<T> [T] { // lengths of the slices are known -- it's removed. let (a, b) = (&mut a[..n], &mut b[..n]); - for i in 0..n { + let mut i = 0; + while i < n { mem::swap(&mut a[i], &mut b[n - 1 - i]); + i += 1; } } } @@ -969,9 +973,10 @@ impl<T> [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { + let this = self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into @@ -1108,10 +1113,11 @@ impl<T> [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { + let this = &*self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); - exact_div(self.len(), N) + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); + exact_div(this.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. @@ -1538,13 +1544,14 @@ impl<T> [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")] #[inline] #[track_caller] #[must_use] - pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { + pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. + // fulfills the requirements of `split_at_unchecked`. unsafe { self.split_at_unchecked(mid) } } @@ -1623,11 +1630,19 @@ impl<T> [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] #[inline] #[must_use] - pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + // HACK: the const function `from_raw_parts` is used to make this + // function const; previously the implementation used + // `(self.get_unchecked(..mid), self.get_unchecked(mid..))` + + let len = self.len(); + let ptr = self.as_ptr(); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } } /// Divides one mutable slice into two at an index, without doing bounds checking. @@ -1675,7 +1690,7 @@ impl<T> [T] { // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. unsafe { - assert_unsafe_precondition!(mid <= len); + assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len); (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } @@ -2309,7 +2324,7 @@ impl<T> [T] { } /// Binary searches this slice for a given element. - /// This behaves similary to [`contains`] if this slice is sorted. + /// This behaves similarly to [`contains`] if this slice is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2921,7 +2936,7 @@ impl<T> [T] { let prev_ptr_write = ptr.add(next_write - 1); if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) { if next_read != next_write { - let ptr_write = prev_ptr_write.offset(1); + let ptr_write = prev_ptr_write.add(1); mem::swap(&mut *ptr_read, &mut *ptr_write); } next_write += 1; @@ -3518,7 +3533,7 @@ impl<T> [T] { // alignment targeted for U. // `crate::ptr::align_offset` is called with a correctly aligned and // valid pointer `ptr` (it comes from a reference to `self`) and with - // a size that is a power of two (since it comes from the alignement for U), + // a size that is a power of two (since it comes from the alignment for U), // satisfying its safety constraints. let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::<U>()) }; if offset > self.len() { @@ -4101,7 +4116,6 @@ impl<T, const N: usize> [[T; N]] { } } -#[cfg(not(bootstrap))] #[cfg(not(test))] impl [f32] { /// Sorts the slice of floats. @@ -4131,7 +4145,6 @@ impl [f32] { } } -#[cfg(not(bootstrap))] #[cfg(not(test))] impl [f64] { /// Sorts the slice of floats. diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 107e71ab6..f1e8bc79b 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -90,7 +90,7 @@ use crate::ptr; pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *const T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize ); @@ -134,7 +134,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *mut T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize ); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 6a201834b..c6c03c0b0 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -326,8 +326,8 @@ where unsafe { // Branchless comparison. *end_l = i as u8; - end_l = end_l.offset(!is_less(&*elem, pivot) as isize); - elem = elem.offset(1); + end_l = end_l.add(!is_less(&*elem, pivot) as usize); + elem = elem.add(1); } } } @@ -352,9 +352,9 @@ where // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice. unsafe { // Branchless comparison. - elem = elem.offset(-1); + elem = elem.sub(1); *end_r = i as u8; - end_r = end_r.offset(is_less(&*elem, pivot) as isize); + end_r = end_r.add(is_less(&*elem, pivot) as usize); } } } @@ -365,12 +365,12 @@ where if count > 0 { macro_rules! left { () => { - l.offset(*start_l as isize) + l.add(usize::from(*start_l)) }; } macro_rules! right { () => { - r.offset(-(*start_r as isize) - 1) + r.sub(usize::from(*start_r) + 1) }; } @@ -398,16 +398,16 @@ where ptr::copy_nonoverlapping(right!(), left!(), 1); for _ in 1..count { - start_l = start_l.offset(1); + start_l = start_l.add(1); ptr::copy_nonoverlapping(left!(), right!(), 1); - start_r = start_r.offset(1); + start_r = start_r.add(1); ptr::copy_nonoverlapping(right!(), left!(), 1); } ptr::copy_nonoverlapping(&tmp, right!(), 1); mem::forget(tmp); - start_l = start_l.offset(1); - start_r = start_r.offset(1); + start_l = start_l.add(1); + start_r = start_r.add(1); } } @@ -420,7 +420,7 @@ where // safe. Otherwise, the debug assertions in the `is_done` case guarantee that // `width(l, r) == block_l + block_r`, namely, that the block sizes have been adjusted to account // for the smaller number of remaining elements. - l = unsafe { l.offset(block_l as isize) }; + l = unsafe { l.add(block_l) }; } if start_r == end_r { @@ -428,7 +428,7 @@ where // SAFETY: Same argument as [block-width-guarantee]. Either this is a full block `2*BLOCK`-wide, // or `block_r` has been adjusted for the last handful of elements. - r = unsafe { r.offset(-(block_r as isize)) }; + r = unsafe { r.sub(block_r) }; } if is_done { @@ -457,9 +457,9 @@ where // - `offsets_l` contains valid offsets into `v` collected during the partitioning of // the last block, so the `l.offset` calls are valid. unsafe { - end_l = end_l.offset(-1); - ptr::swap(l.offset(*end_l as isize), r.offset(-1)); - r = r.offset(-1); + end_l = end_l.sub(1); + ptr::swap(l.add(usize::from(*end_l)), r.sub(1)); + r = r.sub(1); } } width(v.as_mut_ptr(), r) @@ -470,9 +470,9 @@ where while start_r < end_r { // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { - end_r = end_r.offset(-1); - ptr::swap(l, r.offset(-(*end_r as isize) - 1)); - l = l.offset(1); + end_r = end_r.sub(1); + ptr::swap(l, r.sub(usize::from(*end_r) + 1)); + l = l.add(1); } } width(v.as_mut_ptr(), l) diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4e569fcc8..343889b69 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -1,5 +1,7 @@ //! Defines utf8 error type. +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// Errors which can occur when attempting to interpret a sequence of [`u8`] @@ -122,6 +124,15 @@ impl fmt::Display for Utf8Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for Utf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8: corrupt contents" + } +} + /// An error returned when parsing a `bool` using [`from_str`] fails /// /// [`from_str`]: super::FromStr::from_str @@ -136,3 +147,12 @@ impl fmt::Display for ParseBoolError { "provided string was not `true` or `false`".fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseBoolError { + #[allow(deprecated)] + fn description(&self) -> &str { + "failed to parse bool" + } +} diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 6ec1c9390..59f873d12 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,51 +1,170 @@ -use crate::char; -use crate::fmt::{self, Write}; -use crate::mem; +use crate::fmt; +use crate::fmt::Formatter; +use crate::fmt::Write; +use crate::iter::FusedIterator; use super::from_utf8_unchecked; use super::validations::utf8_char_width; -/// Lossy UTF-8 string. -#[unstable(feature = "str_internals", issue = "none")] -pub struct Utf8Lossy { - bytes: [u8], +/// An item returned by the [`Utf8Chunks`] iterator. +/// +/// A `Utf8Chunk` stores a sequence of [`u8`] up to the first broken character +/// when decoding a UTF-8 string. +/// +/// # Examples +/// +/// ``` +/// #![feature(utf8_chunks)] +/// +/// use std::str::Utf8Chunks; +/// +/// // An invalid UTF-8 string +/// let bytes = b"foo\xF1\x80bar"; +/// +/// // Decode the first `Utf8Chunk` +/// let chunk = Utf8Chunks::new(bytes).next().unwrap(); +/// +/// // The first three characters are valid UTF-8 +/// assert_eq!("foo", chunk.valid()); +/// +/// // The fourth character is broken +/// assert_eq!(b"\xF1\x80", chunk.invalid()); +/// ``` +#[unstable(feature = "utf8_chunks", issue = "99543")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Utf8Chunk<'a> { + valid: &'a str, + invalid: &'a [u8], } -impl Utf8Lossy { +impl<'a> Utf8Chunk<'a> { + /// Returns the next validated UTF-8 substring. + /// + /// This substring can be empty at the start of the string or between + /// broken UTF-8 characters. #[must_use] - pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { - // SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required. - unsafe { mem::transmute(bytes) } + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn valid(&self) -> &'a str { + self.valid } - pub fn chunks(&self) -> Utf8LossyChunksIter<'_> { - Utf8LossyChunksIter { source: &self.bytes } + /// Returns the invalid sequence that caused a failure. + /// + /// The returned slice will have a maximum length of 3 and starts after the + /// substring given by [`valid`]. Decoding will resume after this sequence. + /// + /// If empty, this is the last chunk in the string. If non-empty, an + /// unexpected byte was encountered or the end of the input was reached + /// unexpectedly. + /// + /// Lossy decoding would replace this sequence with [`U+FFFD REPLACEMENT + /// CHARACTER`]. + /// + /// [`valid`]: Self::valid + /// [`U+FFFD REPLACEMENT CHARACTER`]: crate::char::REPLACEMENT_CHARACTER + #[must_use] + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn invalid(&self) -> &'a [u8] { + self.invalid } } -/// Iterator over lossy UTF-8 string -#[must_use = "iterators are lazy and do nothing unless consumed"] +#[must_use] +#[unstable(feature = "str_internals", issue = "none")] +pub struct Debug<'a>(&'a [u8]); + #[unstable(feature = "str_internals", issue = "none")] -#[allow(missing_debug_implementations)] -pub struct Utf8LossyChunksIter<'a> { +impl fmt::Debug for Debug<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_char('"')?; + + for chunk in Utf8Chunks::new(self.0) { + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let valid = chunk.valid(); + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in chunk.invalid() { + write!(f, "\\x{:02X}", b)?; + } + } + + f.write_char('"') + } +} + +/// An iterator used to decode a slice of mostly UTF-8 bytes to string slices +/// ([`&str`]) and byte slices ([`&[u8]`][byteslice]). +/// +/// If you want a simple conversion from UTF-8 byte slices to string slices, +/// [`from_utf8`] is easier to use. +/// +/// [byteslice]: slice +/// [`from_utf8`]: super::from_utf8 +/// +/// # Examples +/// +/// This can be used to create functionality similar to +/// [`String::from_utf8_lossy`] without allocating heap memory: +/// +/// ``` +/// #![feature(utf8_chunks)] +/// +/// use std::str::Utf8Chunks; +/// +/// fn from_utf8_lossy<F>(input: &[u8], mut push: F) where F: FnMut(&str) { +/// for chunk in Utf8Chunks::new(input) { +/// push(chunk.valid()); +/// +/// if !chunk.invalid().is_empty() { +/// push("\u{FFFD}"); +/// } +/// } +/// } +/// ``` +/// +/// [`String::from_utf8_lossy`]: ../../std/string/struct.String.html#method.from_utf8_lossy +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[unstable(feature = "utf8_chunks", issue = "99543")] +#[derive(Clone)] +pub struct Utf8Chunks<'a> { source: &'a [u8], } -#[unstable(feature = "str_internals", issue = "none")] -#[derive(PartialEq, Eq, Debug)] -pub struct Utf8LossyChunk<'a> { - /// Sequence of valid chars. - /// Can be empty between broken UTF-8 chars. - pub valid: &'a str, - /// Single broken char, empty if none. - /// Empty iff iterator item is last. - pub broken: &'a [u8], +impl<'a> Utf8Chunks<'a> { + /// Creates a new iterator to decode the bytes. + #[unstable(feature = "utf8_chunks", issue = "99543")] + pub fn new(bytes: &'a [u8]) -> Self { + Self { source: bytes } + } + + #[doc(hidden)] + #[unstable(feature = "str_internals", issue = "none")] + pub fn debug(&self) -> Debug<'_> { + Debug(self.source) + } } -impl<'a> Iterator for Utf8LossyChunksIter<'a> { - type Item = Utf8LossyChunk<'a>; +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl<'a> Iterator for Utf8Chunks<'a> { + type Item = Utf8Chunk<'a>; - fn next(&mut self) -> Option<Utf8LossyChunk<'a>> { + fn next(&mut self) -> Option<Utf8Chunk<'a>> { if self.source.is_empty() { return None; } @@ -130,71 +249,22 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { // SAFETY: `valid_up_to <= i` because it is only ever assigned via // `valid_up_to = i` and `i` only increases. - let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) }; + let (valid, invalid) = unsafe { inspected.split_at_unchecked(valid_up_to) }; - Some(Utf8LossyChunk { + Some(Utf8Chunk { // SAFETY: All bytes up to `valid_up_to` are valid UTF-8. valid: unsafe { from_utf8_unchecked(valid) }, - broken, + invalid, }) } } -impl fmt::Display for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // If we're the empty string then our iterator won't actually yield - // anything, so perform the formatting manually - if self.bytes.is_empty() { - return "".fmt(f); - } - - for Utf8LossyChunk { valid, broken } in self.chunks() { - // If we successfully decoded the whole chunk as a valid string then - // we can return a direct formatting of the string which will also - // respect various formatting flags if possible. - if valid.len() == self.bytes.len() { - assert!(broken.is_empty()); - return valid.fmt(f); - } - - f.write_str(valid)?; - if !broken.is_empty() { - f.write_char(char::REPLACEMENT_CHARACTER)?; - } - } - Ok(()) - } -} - -impl fmt::Debug for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_char('"')?; +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl FusedIterator for Utf8Chunks<'_> {} - for Utf8LossyChunk { valid, broken } in self.chunks() { - // Valid part. - // Here we partially parse UTF-8 again which is suboptimal. - { - let mut from = 0; - for (i, c) in valid.char_indices() { - let esc = c.escape_debug(); - // If char needs escaping, flush backlog so far and write, else skip - if esc.len() != 1 { - f.write_str(&valid[from..i])?; - for c in esc { - f.write_char(c)?; - } - from = i + c.len_utf8(); - } - } - f.write_str(&valid[from..])?; - } - - // Broken parts of string as hex escape. - for &b in broken { - write!(f, "\\x{:02x}", b)?; - } - } - - f.write_char('"') +#[unstable(feature = "utf8_chunks", issue = "99543")] +impl fmt::Debug for Utf8Chunks<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish() } } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c4f2e283e..f673aa2a4 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -22,9 +22,9 @@ use crate::slice::{self, SliceIndex}; pub mod pattern; -#[unstable(feature = "str_internals", issue = "none")] -#[allow(missing_docs)] -pub mod lossy; +mod lossy; +#[unstable(feature = "utf8_chunks", issue = "99543")] +pub use lossy::{Utf8Chunk, Utf8Chunks}; #[stable(feature = "rust1", since = "1.0.0")] pub use converts::{from_utf8, from_utf8_unchecked}; @@ -91,10 +91,12 @@ const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { } } +#[track_caller] const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! { panic!("failed to slice string"); } +#[track_caller] fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { const MAX_DISPLAY_LENGTH: usize = 256; let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH); @@ -2353,7 +2355,7 @@ impl str { #[inline] pub fn is_ascii(&self) -> bool { // We can treat each byte as character here: all multibyte characters - // start with a byte that is not in the ascii range, so we will stop + // start with a byte that is not in the ASCII range, so we will stop // there already. self.as_bytes().is_ascii() } @@ -2638,3 +2640,7 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +impl !crate::error::Error for &str {} diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 04bc66523..2acef432f 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -216,12 +216,12 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // SAFETY: since `align - index` and `ascii_block_size` are // multiples of `usize_bytes`, `block = ptr.add(index)` is // always aligned with a `usize` so it's safe to dereference - // both `block` and `block.offset(1)`. + // both `block` and `block.add(1)`. unsafe { let block = ptr.add(index) as *const usize; // break if there is a nonascii byte let zu = contains_nonascii(*block); - let zv = contains_nonascii(*block.offset(1)); + let zv = contains_nonascii(*block.add(1)); if zu || zv { break; } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 5e2e0c4d8..3c96290fc 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1554,8 +1554,8 @@ impl<T> AtomicPtr<T> { /// Offsets the pointer's address by adding `val` *bytes*, returning the /// previous pointer. /// - /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically - /// perform `ptr = ptr.cast::<u8>().wrapping_add(val).cast::<T>()`. + /// This is equivalent to using [`wrapping_byte_add`] to atomically + /// perform `ptr = ptr.wrapping_byte_add(val)`. /// /// `fetch_byte_add` takes an [`Ordering`] argument which describes the /// memory ordering of this operation. All ordering modes are possible. Note @@ -1565,8 +1565,7 @@ impl<T> AtomicPtr<T> { /// **Note**: This method is only available on platforms that support atomic /// operations on [`AtomicPtr`]. /// - /// [`wrapping_add`]: pointer::wrapping_add - /// [`cast`]: pointer::cast + /// [`wrapping_byte_add`]: pointer::wrapping_byte_add /// /// # Examples /// @@ -1584,23 +1583,15 @@ impl<T> AtomicPtr<T> { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_add(self.p.get().cast::<usize>(), val, order) as *mut T - } + unsafe { atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Offsets the pointer's address by subtracting `val` *bytes*, returning the /// previous pointer. /// - /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically - /// perform `ptr = ptr.cast::<u8>().wrapping_sub(val).cast::<T>()`. + /// This is equivalent to using [`wrapping_byte_sub`] to atomically + /// perform `ptr = ptr.wrapping_byte_sub(val)`. /// /// `fetch_byte_sub` takes an [`Ordering`] argument which describes the /// memory ordering of this operation. All ordering modes are possible. Note @@ -1610,8 +1601,7 @@ impl<T> AtomicPtr<T> { /// **Note**: This method is only available on platforms that support atomic /// operations on [`AtomicPtr`]. /// - /// [`wrapping_sub`]: pointer::wrapping_sub - /// [`cast`]: pointer::cast + /// [`wrapping_byte_sub`]: pointer::wrapping_byte_sub /// /// # Examples /// @@ -1628,16 +1618,8 @@ impl<T> AtomicPtr<T> { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_sub(self.p.get().cast::<usize>(), val, order) as *mut T - } + unsafe { atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "or" operation on the address of the current pointer, @@ -1687,16 +1669,8 @@ impl<T> AtomicPtr<T> { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_or(self.p.get().cast::<usize>(), val, order) as *mut T - } + unsafe { atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "and" operation on the address of the current @@ -1745,16 +1719,8 @@ impl<T> AtomicPtr<T> { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_and(self.p.get().cast::<usize>(), val, order) as *mut T - } + unsafe { atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } /// Performs a bitwise "xor" operation on the address of the current @@ -1801,16 +1767,8 @@ impl<T> AtomicPtr<T> { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { - #[cfg(not(bootstrap))] - // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() - } - #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { - atomic_xor(self.p.get().cast::<usize>(), val, order) as *mut T - } + unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } } @@ -3073,30 +3031,22 @@ unsafe fn atomic_compare_exchange<T: Copy>( let (val, ok) = unsafe { match (success, failure) { (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), - #[cfg(not(bootstrap))] (AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), - #[cfg(bootstrap)] - _ => panic!("a failure ordering can't be stronger than a success ordering"), } }; if ok { Ok(val) } else { Err(val) } @@ -3116,30 +3066,22 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( let (val, ok) = unsafe { match (success, failure) { (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new), (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new), - #[cfg(not(bootstrap))] (Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new), - #[cfg(not(bootstrap))] (Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new), (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new), (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new), - #[cfg(not(bootstrap))] (AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new), (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new), (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), - #[cfg(bootstrap)] - _ => panic!("a failure ordering can't be stronger than a success ordering"), } }; if ok { Ok(val) } else { Err(val) } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 87d4a25af..60ecc9c0b 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -71,6 +71,12 @@ impl RawWaker { /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. +/// +/// These functions must all be thread-safe (even though [`RawWaker`] is +/// <code>\![Send] + \![Sync]</code>) +/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to +/// arbitrary threads or invoked by `&` reference. For example, this means that if the +/// `clone` and `drop` functions manage a reference count, they must do so atomically. #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -110,6 +116,12 @@ impl RawWakerVTable { /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, /// `wake_by_ref`, and `drop` functions. /// + /// These functions must all be thread-safe (even though [`RawWaker`] is + /// <code>\![Send] + \![Sync]</code>) + /// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to + /// arbitrary threads or invoked by `&` reference. For example, this means that if the + /// `clone` and `drop` functions manage a reference count, they must do so atomically. + /// /// # `clone` /// /// This function will be called when the [`RawWaker`] gets cloned, e.g. when @@ -157,9 +169,9 @@ impl RawWakerVTable { } } -/// The `Context` of an asynchronous task. +/// The context of an asynchronous task. /// -/// Currently, `Context` only serves to provide access to a `&Waker` +/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) /// which can be used to wake the current task. #[stable(feature = "futures_api", since = "1.36.0")] pub struct Context<'a> { @@ -172,7 +184,7 @@ pub struct Context<'a> { } impl<'a> Context<'a> { - /// Create a new `Context` from a `&Waker`. + /// Create a new `Context` from a [`&Waker`](Waker). #[stable(feature = "futures_api", since = "1.36.0")] #[must_use] #[inline] @@ -180,7 +192,7 @@ impl<'a> Context<'a> { Context { waker, _marker: PhantomData } } - /// Returns a reference to the `Waker` for the current task. + /// Returns a reference to the [`Waker`] for the current task. #[stable(feature = "futures_api", since = "1.36.0")] #[must_use] #[inline] @@ -202,7 +214,18 @@ impl fmt::Debug for Context<'_> { /// This handle encapsulates a [`RawWaker`] instance, which defines the /// executor-specific wakeup behavior. /// -/// Implements [`Clone`], [`Send`], and [`Sync`]. +/// The typical life of a `Waker` is that it is constructed by an executor, wrapped in a +/// [`Context`], then passed to [`Future::poll()`]. Then, if the future chooses to return +/// [`Poll::Pending`], it must also store the waker somehow and call [`Waker::wake()`] when +/// the future should be polled again. +/// +/// Implements [`Clone`], [`Send`], and [`Sync`]; therefore, a waker may be invoked +/// from any thread, including ones not in any way managed by the executor. For example, +/// this might be done to wake a future when a blocking function call completes on another +/// thread. +/// +/// [`Future::poll()`]: core::future::Future::poll +/// [`Poll::Pending`]: core::task::Poll::Pending #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -219,18 +242,21 @@ unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. /// - /// As long as the runtime keeps running and the task is not finished, it is - /// guaranteed that each invocation of `wake` (or `wake_by_ref`) will be followed - /// by at least one `poll` of the task to which this `Waker` belongs. This makes + /// As long as the executor keeps running and the task is not finished, it is + /// guaranteed that each invocation of [`wake()`](Self::wake) (or + /// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one + /// [`poll()`] of the task to which this `Waker` belongs. This makes /// it possible to temporarily yield to other tasks while running potentially /// unbounded processing loops. /// /// Note that the above implies that multiple wake-ups may be coalesced into a - /// single `poll` invocation by the runtime. + /// single [`poll()`] invocation by the runtime. /// /// Also note that yielding to competing tasks is not guaranteed: it is the /// executor’s choice which task to run and the executor may choose to run the /// current task again. + /// + /// [`poll()`]: crate::future::Future::poll #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub fn wake(self) { @@ -250,8 +276,8 @@ impl Waker { /// Wake up the task associated with this `Waker` without consuming the `Waker`. /// - /// This is similar to `wake`, but may be slightly less efficient in the case - /// where an owned `Waker` is available. This method should be preferred to + /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in + /// the case where an owned `Waker` is available. This method should be preferred to /// calling `waker.clone().wake()`. #[inline] #[stable(feature = "futures_api", since = "1.36.0")] @@ -263,7 +289,7 @@ impl Waker { unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } } - /// Returns `true` if this `Waker` and another `Waker` have awoken the same task. + /// Returns `true` if this `Waker` and another `Waker` would awake the same task. /// /// This function works on a best-effort basis, and may return false even /// when the `Waker`s would awaken the same task. However, if this function diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 756f1a166..4f29ecc0f 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -318,19 +318,11 @@ impl Duration { /// assert_eq!(duration.as_secs(), 5); /// ``` /// - /// To determine the total number of seconds represented by the `Duration`, - /// use `as_secs` in combination with [`subsec_nanos`]: - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// - /// assert_eq!(5.730023852, - /// duration.as_secs() as f64 - /// + duration.subsec_nanos() as f64 * 1e-9); - /// ``` + /// To determine the total number of seconds represented by the `Duration` + /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`] /// + /// [`as_secs_f64`]: Duration::as_secs_f64 + /// [`as_secs_f32`]: Duration::as_secs_f32 /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] @@ -1143,7 +1135,7 @@ impl fmt::Debug for Duration { // 2. The postfix: can be "µs" so we have to count UTF8 characters. let mut actual_w = prefix.len() + postfix.chars().count(); // 3. The integer part: - if let Some(log) = integer_part.checked_log10() { + if let Some(log) = integer_part.checked_ilog10() { // integer_part is > 0, so has length log10(x)+1 actual_w += 1 + log as usize; } else { @@ -1288,7 +1280,7 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch + // f32 does not have enough precision to trigger the second branch // since it can not represent numbers between 0.999_999_940_395 and 1.0. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) } @@ -1307,9 +1299,9 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch. + // f32 does not have enough precision to trigger the second branch. // For example, it can not represent numbers between 1.999_999_880... - // and 2.0. Bigger values result in even smaller presicion of the + // and 2.0. Bigger values result in even smaller precision of the // fractional part. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index d189e6400..aa8a2425b 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -107,7 +107,7 @@ macro_rules! tuple_impls { // Otherwise, it hides the docs entirely. macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(fake_variadic))] + #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index d2073f86c..7301da2af 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -1,7 +1,8 @@ ///! This file is generated by src/tools/unicode-table-generator; do not edit manually! +#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline(always)] -fn bitset_search< +const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, const N1: usize, @@ -17,14 +18,18 @@ fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; - let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) { - v + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. + let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { + chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; - let word = if let Some(word) = bitset_canonical.get(idx) { - *word + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. + let word = if idx < bitset_canonical.len() { + bitset_canonical[idx] } else { let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()]; let mut word = bitset_canonical[real_idx as usize]; @@ -318,14 +323,14 @@ pub mod grapheme_extend { #[rustfmt::skip] pub mod lowercase { - static BITSET_CHUNKS_MAP: [u8; 123] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[ 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 3, 0, 0, 7, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 19] = &[ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], @@ -346,7 +351,7 @@ pub mod lowercase { [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44], ]; - static BITSET_CANONICAL: [u64; 55] = [ + const BITSET_CANONICAL: &'static [u64; 55] = &[ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -403,13 +408,14 @@ pub mod lowercase { 0b1110011111111111111111111111111111111111111111110000000000000000, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - static BITSET_MAPPING: [(u8, u8); 20] = [ + const BITSET_MAPPING: &'static [(u8, u8); 20] = &[ (0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187), (6, 132), (7, 93), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, @@ -454,14 +460,14 @@ pub mod n { #[rustfmt::skip] pub mod uppercase { - static BITSET_CHUNKS_MAP: [u8; 125] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[ 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, 6, 6, 9, 6, 3, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[ [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], @@ -480,7 +486,7 @@ pub mod uppercase { [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], ]; - static BITSET_CANONICAL: [u64; 43] = [ + const BITSET_CANONICAL: &'static [u64; 43] = &[ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, @@ -525,13 +531,14 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - static BITSET_MAPPING: [(u8, u8); 25] = [ + const BITSET_MAPPING: &'static [(u8, u8); 25] = &[ (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, @@ -544,18 +551,26 @@ pub mod uppercase { #[rustfmt::skip] pub mod white_space { - static SHORT_OFFSET_RUNS: [u32; 4] = [ - 5760, 18882560, 23080960, 40972289, - ]; - static OFFSETS: [u8; 21] = [ - 9, 5, 18, 1, 100, 1, 26, 1, 0, 1, 0, 11, 29, 2, 5, 1, 47, 1, 0, 1, 0, + static WHITESPACE_MAP: [u8; 256] = [ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; + #[inline] pub fn lookup(c: char) -> bool { - super::skip_search( - c as u32, - &SHORT_OFFSET_RUNS, - &OFFSETS, - ) + match c as u32 >> 8 { + 0 => WHITESPACE_MAP[c as usize & 0xff] & 1 != 0, + 22 => c as u32 == 0x1680, + 32 => WHITESPACE_MAP[c as usize & 0xff] & 2 != 0, + 48 => c as u32 == 0x3000, + _ => false, + } } } diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs index 8a5a06b34..3ceaeadce 100644 --- a/library/core/tests/alloc.rs +++ b/library/core/tests/alloc.rs @@ -1,4 +1,5 @@ use core::alloc::Layout; +use core::mem::size_of; use core::ptr::{self, NonNull}; #[test] @@ -13,6 +14,49 @@ fn const_unchecked_layout() { } #[test] +fn layout_round_up_to_align_edge_cases() { + const MAX_SIZE: usize = isize::MAX as usize; + + for shift in 0..usize::BITS { + let align = 1_usize << shift; + let edge = (MAX_SIZE + 1) - align; + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::from_size_align(low, align).is_ok()); + assert!(Layout::from_size_align(high, align).is_err()); + for size in low..=high { + assert_eq!( + Layout::from_size_align(size, align).is_ok(), + size.next_multiple_of(align) <= MAX_SIZE, + ); + } + } +} + +#[test] +fn layout_array_edge_cases() { + for_type::<i64>(); + for_type::<[i32; 0b10101]>(); + for_type::<[u8; 0b1010101]>(); + + // Make sure ZSTs don't lead to divide-by-zero + assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap()); + + fn for_type<T>() { + const MAX_SIZE: usize = isize::MAX as usize; + + let edge = (MAX_SIZE + 1) / size_of::<T>(); + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::array::<T>(low).is_ok()); + assert!(Layout::array::<T>(high).is_err()); + for n in low..=high { + assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= MAX_SIZE); + } + } +} + +#[test] fn layout_debug_shows_log2_of_alignment() { // `Debug` is not stable, but here's what it does right now let layout = Layout::from_size_align(24576, 8192).unwrap(); diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs index 8ed0c8880..9538b8139 100644 --- a/library/core/tests/any.rs +++ b/library/core/tests/any.rs @@ -142,7 +142,7 @@ impl Provider for SomeConcreteType { demand .provide_ref::<String>(&self.some_string) .provide_ref::<str>(&self.some_string) - .provide_value::<String>(|| "bye".to_owned()); + .provide_value_with::<String>(|| "bye".to_owned()); } } diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 13b12db20..94b031060 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -155,7 +155,7 @@ fn ptr_add_data() { assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); assert_eq!(atom.load(SeqCst), n); - let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>(); + let bytes_from_n = |b| n.wrapping_byte_add(b); assert_eq!(atom.fetch_byte_add(1, SeqCst), n); assert_eq!(atom.load(SeqCst), bytes_from_n(1)); diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803..d874f0831 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x const fn unaligned_ptr() -> *const u16 { // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } + unsafe { DATA.as_ptr().byte_add(1) } } #[test] @@ -67,7 +67,7 @@ fn write() { 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; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); } two_aligned @@ -91,7 +91,7 @@ fn mut_ptr_write() { 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; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); } two_aligned diff --git a/library/core/tests/iter/adapters/array_chunks.rs b/library/core/tests/iter/adapters/array_chunks.rs new file mode 100644 index 000000000..4e9d89e1e --- /dev/null +++ b/library/core/tests/iter/adapters/array_chunks.rs @@ -0,0 +1,179 @@ +use core::cell::Cell; +use core::iter::{self, Iterator}; + +use super::*; + +#[test] +fn test_iterator_array_chunks_infer() { + let xs = [1, 1, 2, -2, 6, 0, 3, 1]; + for [a, b, c] in xs.iter().copied().array_chunks() { + assert_eq!(a + b + c, 4); + } +} + +#[test] +fn test_iterator_array_chunks_clone_and_drop() { + let count = Cell::new(0); + let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + assert_eq!(it.by_ref().count(), 1); + assert_eq!(count.get(), 3); + let mut it2 = it.clone(); + assert_eq!(count.get(), 3); + assert_eq!(it.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 5); + assert!(it2.next().is_none()); + assert_eq!(it2.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 7); +} + +#[test] +fn test_iterator_array_chunks_remainder() { + let mut it = (0..11).array_chunks::<4>(); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_size_hint() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.size_hint(), (6, Some(6))); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.size_hint(), (2, Some(2))); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.size_hint(), (1, Some(1))); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.size_hint(), (0, Some(0))); + + let it = (1..).array_chunks::<2>(); + assert_eq!(it.size_hint(), (usize::MAX / 2, None)); + + let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>(); + assert_eq!(it.size_hint(), (0, None)); +} + +#[test] +fn test_iterator_array_chunks_count() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.count(), 6); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.count(), 2); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.count(), 1); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.count(), 0); + + let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>(); + assert_eq!(it.count(), 1); + + let it = iter::empty::<i32>().array_chunks::<2>(); + assert_eq!(it.count(), 0); + + let it = [(); usize::MAX].iter().array_chunks::<2>(); + assert_eq!(it.count(), usize::MAX / 2); +} + +#[test] +fn test_iterator_array_chunks_next_and_next_back() { + let mut it = (0..11).array_chunks::<3>(); + assert_eq!(it.next(), Some([0, 1, 2])); + assert_eq!(it.next_back(), Some([6, 7, 8])); + assert_eq!(it.next(), Some([3, 4, 5])); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]); +} + +#[test] +fn test_iterator_array_chunks_rev_remainder() { + let mut it = (0..11).array_chunks::<4>(); + { + let mut it = it.by_ref().rev(); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + } + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_try_fold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 9); +} + +#[test] +fn test_iterator_array_chunks_fold() { + let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| { + assert_eq!(acc + 1, a); + assert_eq!(acc + 2, b); + assert_eq!(acc + 3, c); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + assert_eq!(count.get(), 10); +} + +#[test] +fn test_iterator_array_chunks_try_rfold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); +} + +#[test] +fn test_iterator_array_chunks_rfold() { + let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| { + assert_eq!(10 - (acc + 1), c); + assert_eq!(10 - (acc + 2), b); + assert_eq!(10 - (acc + 3), a); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + assert_eq!(count.get(), 10); +} diff --git a/library/core/tests/iter/adapters/by_ref_sized.rs b/library/core/tests/iter/adapters/by_ref_sized.rs new file mode 100644 index 000000000..a9c066f0e --- /dev/null +++ b/library/core/tests/iter/adapters/by_ref_sized.rs @@ -0,0 +1,20 @@ +use core::iter::*; + +#[test] +fn test_iterator_by_ref_sized() { + let a = ['a', 'b', 'c', 'd']; + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zab"); + ByRefSized(&mut it).fold((), |(), x| s.push(x)); + assert_eq!(s, "Zabcd"); + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).rev().take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zdc"); + ByRefSized(&mut it).rfold((), |(), x| s.push(x)); + assert_eq!(s, "Zdcba"); +} diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index f8ab8c9d4..690fd0c21 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -168,3 +168,45 @@ fn test_trusted_len_flatten() { assert_trusted_len(&iter); assert_eq!(iter.size_hint(), (20, Some(20))); } + +#[test] +fn test_flatten_count() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().count(), 40); + it.advance_by(5).unwrap(); + assert_eq!(it.clone().count(), 35); + it.advance_back_by(5).unwrap(); + assert_eq!(it.clone().count(), 30); + it.advance_by(10).unwrap(); + assert_eq!(it.clone().count(), 20); + it.advance_back_by(8).unwrap(); + assert_eq!(it.clone().count(), 12); + it.advance_by(4).unwrap(); + assert_eq!(it.clone().count(), 8); + it.advance_back_by(5).unwrap(); + assert_eq!(it.clone().count(), 3); + it.advance_by(3).unwrap(); + assert_eq!(it.clone().count(), 0); +} + +#[test] +fn test_flatten_last() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().last(), Some(39)); + it.advance_by(5).unwrap(); // 5..40 + assert_eq!(it.clone().last(), Some(39)); + it.advance_back_by(5).unwrap(); // 5..35 + assert_eq!(it.clone().last(), Some(34)); + it.advance_by(10).unwrap(); // 15..35 + assert_eq!(it.clone().last(), Some(34)); + it.advance_back_by(8).unwrap(); // 15..27 + assert_eq!(it.clone().last(), Some(26)); + it.advance_by(4).unwrap(); // 19..27 + assert_eq!(it.clone().last(), Some(26)); + it.advance_back_by(5).unwrap(); // 19..22 + assert_eq!(it.clone().last(), Some(21)); + it.advance_by(3).unwrap(); // 22..22 + assert_eq!(it.clone().last(), None); +} diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs index 567d9fe49..ffd5f3857 100644 --- a/library/core/tests/iter/adapters/mod.rs +++ b/library/core/tests/iter/adapters/mod.rs @@ -1,3 +1,5 @@ +mod array_chunks; +mod by_ref_sized; mod chain; mod cloned; mod copied; @@ -183,3 +185,25 @@ impl Clone for CountClone { ret } } + +#[derive(Debug, Clone)] +struct CountDrop<'a> { + dropped: bool, + count: &'a Cell<usize>, +} + +impl<'a> CountDrop<'a> { + pub fn new(count: &'a Cell<usize>) -> Self { + Self { dropped: false, count } + } +} + +impl Drop for CountDrop<'_> { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + self.count.set(self.count.get() + 1); + } +} diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs index 65f235e86..754641834 100644 --- a/library/core/tests/iter/adapters/skip.rs +++ b/library/core/tests/iter/adapters/skip.rs @@ -201,3 +201,34 @@ fn test_skip_non_fused() { // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario. let _ = non_fused.skip(20).next(); } + +#[test] +fn test_skip_non_fused_nth_overflow() { + let non_fused = Unfuse::new(0..10); + + // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused + // iterators. + let _ = non_fused.skip(20).nth(usize::MAX); +} + +#[test] +fn test_skip_overflow_wrapping() { + // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded. + struct WrappingIterator(usize); + + impl Iterator for WrappingIterator { + type Item = usize; + + fn next(&mut self) -> core::option::Option<Self::Item> { + <Self as Iterator>::nth(self, 0) + } + + fn nth(&mut self, nth: usize) -> core::option::Option<Self::Item> { + self.0 = self.0.wrapping_add(nth.wrapping_add(1)); + Some(self.0) + } + } + + let wrap = WrappingIterator(0); + assert_eq!(wrap.skip(20).nth(usize::MAX), Some(20)); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db94368f6..4a0e162bc 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(array_methods)] #![feature(array_windows)] #![feature(bench_black_box)] +#![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_assume)] #![feature(const_black_box)] @@ -14,6 +15,7 @@ #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_pointer_byte_offsets)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] @@ -61,6 +63,7 @@ #![feature(slice_partition_dedup)] #![feature(int_log)] #![feature(iter_advance_by)] +#![feature(iter_array_chunks)] #![feature(iter_collect_into)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] @@ -73,7 +76,7 @@ #![feature(const_pin)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(result_into_ok_or_err)] +#![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] @@ -96,6 +99,7 @@ #![feature(waker_getters)] #![feature(slice_flatten)] #![feature(provide_any)] +#![feature(utf8_chunks)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs index dc3092e14..be203fb5c 100644 --- a/library/core/tests/num/int_log.rs +++ b/library/core/tests/num/int_log.rs @@ -1,166 +1,166 @@ -//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a +//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a //! separate file because there's both a large number of them, and not all tests -//! can be run on Android. This is because in Android `log2` uses an imprecise +//! can be run on Android. This is because in Android `ilog2` uses an imprecise //! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53 #[test] -fn checked_log() { - assert_eq!(999u32.checked_log(10), Some(2)); - assert_eq!(1000u32.checked_log(10), Some(3)); - assert_eq!(555u32.checked_log(13), Some(2)); - assert_eq!(63u32.checked_log(4), Some(2)); - assert_eq!(64u32.checked_log(4), Some(3)); - assert_eq!(10460353203u64.checked_log(3), Some(21)); - assert_eq!(10460353202u64.checked_log(3), Some(20)); - assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80)); - assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79)); - assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8)); - assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7)); - - assert_eq!(0u8.checked_log(4), None); - assert_eq!(0u16.checked_log(4), None); - assert_eq!(0i8.checked_log(4), None); - assert_eq!(0i16.checked_log(4), None); +fn checked_ilog() { + assert_eq!(999u32.checked_ilog(10), Some(2)); + assert_eq!(1000u32.checked_ilog(10), Some(3)); + assert_eq!(555u32.checked_ilog(13), Some(2)); + assert_eq!(63u32.checked_ilog(4), Some(2)); + assert_eq!(64u32.checked_ilog(4), Some(3)); + assert_eq!(10460353203u64.checked_ilog(3), Some(21)); + assert_eq!(10460353202u64.checked_ilog(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7)); + + assert_eq!(0u8.checked_ilog(4), None); + assert_eq!(0u16.checked_ilog(4), None); + assert_eq!(0i8.checked_ilog(4), None); + assert_eq!(0i16.checked_ilog(4), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log(4), None); + assert_eq!(i.checked_ilog(4), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } } #[test] -fn checked_log2() { - assert_eq!(5u32.checked_log2(), Some(2)); - assert_eq!(0u64.checked_log2(), None); - assert_eq!(128i32.checked_log2(), Some(7)); - assert_eq!((-55i16).checked_log2(), None); +fn checked_ilog2() { + assert_eq!(5u32.checked_ilog2(), Some(2)); + assert_eq!(0u64.checked_ilog2(), None); + assert_eq!(128i32.checked_ilog2(), Some(7)); + assert_eq!((-55i16).checked_ilog2(), None); - assert_eq!(0u8.checked_log2(), None); - assert_eq!(0u16.checked_log2(), None); - assert_eq!(0i8.checked_log2(), None); - assert_eq!(0i16.checked_log2(), None); + assert_eq!(0u8.checked_ilog2(), None); + assert_eq!(0u16.checked_ilog2(), None); + assert_eq!(0i8.checked_ilog2(), None); + assert_eq!(0i16.checked_ilog2(), None); for i in 1..=u8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 && i != 32768 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } for i in i8::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } for i in 1..=i8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } } -// Validate cases that fail on Android's imprecise float log2 implementation. +// Validate cases that fail on Android's imprecise float ilog2 implementation. #[test] #[cfg(not(target_os = "android"))] -fn checked_log2_not_android() { - assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32)); - assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32)); - assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32)); +fn checked_ilog2_not_android() { + assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); + assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); + assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); } #[test] -fn checked_log10() { - assert_eq!(0u8.checked_log10(), None); - assert_eq!(0u16.checked_log10(), None); - assert_eq!(0i8.checked_log10(), None); - assert_eq!(0i16.checked_log10(), None); +fn checked_ilog10() { + assert_eq!(0u8.checked_ilog10(), None); + assert_eq!(0u16.checked_ilog10(), None); + assert_eq!(0i8.checked_ilog10(), None); + assert_eq!(0i16.checked_ilog10(), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log10(), None); + assert_eq!(i.checked_ilog10(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=100_000u32 { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } } -macro_rules! log10_loop { - ($T:ty, $log10_max:expr) => { - assert_eq!(<$T>::MAX.log10(), $log10_max); - for i in 0..=$log10_max { +macro_rules! ilog10_loop { + ($T:ty, $ilog10_max:expr) => { + assert_eq!(<$T>::MAX.ilog10(), $ilog10_max); + for i in 0..=$ilog10_max { let p = (10 as $T).pow(i as u32); if p >= 10 { - assert_eq!((p - 9).log10(), i - 1); - assert_eq!((p - 1).log10(), i - 1); + assert_eq!((p - 9).ilog10(), i - 1); + assert_eq!((p - 1).ilog10(), i - 1); } - assert_eq!(p.log10(), i); - assert_eq!((p + 1).log10(), i); + assert_eq!(p.ilog10(), i); + assert_eq!((p + 1).ilog10(), i); if p >= 10 { - assert_eq!((p + 9).log10(), i); + assert_eq!((p + 9).ilog10(), i); } - // also check `x.log(10)` + // also check `x.ilog(10)` if p >= 10 { - assert_eq!((p - 9).log(10), i - 1); - assert_eq!((p - 1).log(10), i - 1); + assert_eq!((p - 9).ilog(10), i - 1); + assert_eq!((p - 1).ilog(10), i - 1); } - assert_eq!(p.log(10), i); - assert_eq!((p + 1).log(10), i); + assert_eq!(p.ilog(10), i); + assert_eq!((p + 1).ilog(10), i); if p >= 10 { - assert_eq!((p + 9).log(10), i); + assert_eq!((p + 9).ilog(10), i); } } }; } #[test] -fn log10_u8() { - log10_loop! { u8, 2 } +fn ilog10_u8() { + ilog10_loop! { u8, 2 } } #[test] -fn log10_u16() { - log10_loop! { u16, 4 } +fn ilog10_u16() { + ilog10_loop! { u16, 4 } } #[test] -fn log10_u32() { - log10_loop! { u32, 9 } +fn ilog10_u32() { + ilog10_loop! { u32, 9 } } #[test] -fn log10_u64() { - log10_loop! { u64, 19 } +fn ilog10_u64() { + ilog10_loop! { u64, 19 } } #[test] -fn log10_u128() { - log10_loop! { u128, 38 } +fn ilog10_u128() { + ilog10_loop! { u128, 38 } } diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 8b84a78e6..18c55e43a 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -338,6 +338,32 @@ macro_rules! int_module { assert_eq!(MIN.checked_next_multiple_of(-3), None); assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true)); + assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false)); + assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true)); + assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true)); + assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false)); + assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true)); + assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); + assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); + } } }; } diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 93ae620c2..15ae9f232 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -230,6 +230,28 @@ macro_rules! uint_module { assert_eq!((1 as $T).checked_next_multiple_of(0), None); assert_eq!(MAX.checked_next_multiple_of(2), None); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq!($T::MAX.carrying_add(1, true), (1, true)); + + assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + + assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } } }; } diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 12861794c..97a369810 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -650,7 +650,7 @@ fn thin_box() { .unwrap_or_else(|| handle_alloc_error(layout)) .cast::<DynMetadata<T>>(); ptr.as_ptr().write(meta); - ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value); + ptr.as_ptr().byte_add(offset).cast::<Value>().write(value); Self { ptr, phantom: PhantomData } } } diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 103e8cc3a..50926da3c 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -96,15 +96,6 @@ fn test_unwrap_or() { } #[test] -fn test_ok_or_err() { - let ok: Result<isize, isize> = Ok(100); - let err: Result<isize, isize> = Err(200); - - assert_eq!(ok.into_ok_or_err(), 100); - assert_eq!(err.into_ok_or_err(), 200); -} - -#[test] fn test_unwrap_or_else() { fn handler(msg: &'static str) -> isize { if msg == "I got this." { 50 } else { panic!("BadBad") } diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 0656109e9..b8f6fe696 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1197,7 +1197,6 @@ fn chunks_mut_are_send_and_sync() { use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut}; use std::sync::MutexGuard; - #[allow(unused)] fn assert_send_and_sync() where ChunksMut<'static, Cell<i32>>: Send, @@ -1210,6 +1209,8 @@ fn chunks_mut_are_send_and_sync() { RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, { } + + assert_send_and_sync(); } #[test] diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs index d4b47a470..9d3f0b65f 100644 --- a/library/core/tests/str_lossy.rs +++ b/library/core/tests/str_lossy.rs @@ -1,85 +1,85 @@ -use core::str::lossy::*; +use core::str::Utf8Chunks; #[test] fn chunks() { - let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); + macro_rules! assert_chunks { + ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{ + let mut iter = Utf8Chunks::new($string); + $( + let chunk = iter.next().expect("missing chunk"); + assert_eq!($valid, chunk.valid()); + assert_eq!($invalid, chunk.invalid()); + )* + assert_eq!(None, iter.next()); + }}; + } - let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); + assert_chunks!(b"hello", ("hello", b"")); + assert_chunks!("ศไทย中华Việt Nam".as_bytes(), ("ศไทย中华Việt Nam", b"")); + assert_chunks!( + b"Hello\xC2 There\xFF Goodbye", + ("Hello", b"\xC2"), + (" There", b"\xFF"), + (" Goodbye", b""), + ); + assert_chunks!( + b"Hello\xC0\x80 There\xE6\x83 Goodbye", + ("Hello", b"\xC0"), + ("", b"\x80"), + (" There", b"\xE6\x83"), + (" Goodbye", b""), + ); + assert_chunks!( + b"\xF5foo\xF5\x80bar", + ("", b"\xF5"), + ("foo", b"\xF5"), + ("", b"\x80"), + ("bar", b""), + ); + assert_chunks!( + b"\xF1foo\xF1\x80bar\xF1\x80\x80baz", + ("", b"\xF1"), + ("foo", b"\xF1\x80"), + ("bar", b"\xF1\x80\x80"), + ("baz", b""), + ); + assert_chunks!( + b"\xF4foo\xF4\x80bar\xF4\xBFbaz", + ("", b"\xF4"), + ("foo", b"\xF4\x80"), + ("bar", b"\xF4"), + ("", b"\xBF"), + ("baz", b""), + ); + assert_chunks!( + b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar", + ("", b"\xF0"), + ("", b"\x80"), + ("", b"\x80"), + ("", b"\x80"), + ("foo\u{10000}bar", b""), + ); // surrogates - let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + assert_chunks!( + b"\xED\xA0\x80foo\xED\xBF\xBFbar", + ("", b"\xED"), + ("", b"\xA0"), + ("", b"\x80"), + ("foo", b"\xED"), + ("", b"\xBF"), + ("", b"\xBF"), + ("bar", b""), ); } #[test] fn debug() { assert_eq!( - "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", + "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"", &format!( "{:?}", - Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa") - ) + Utf8Chunks::new(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa").debug(), + ), ); } |