diff options
Diffstat (limited to 'library/core/src')
45 files changed, 863 insertions, 309 deletions
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index d6ae2b821..78091c017 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -94,8 +94,9 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// * Memory blocks returned from an allocator must point to valid memory and retain their validity -/// until the instance and all of its copies and clones are dropped, +/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to +/// valid memory and retain their validity while they are [*currently allocated*] and at +/// least one of the instance and all of its clones has not been dropped. /// /// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this /// allocator. A copied or cloned allocator must behave like the same allocator, and diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 7969f4055..09f52d692 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -153,6 +153,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; +use crate::hash; use crate::intrinsics; /////////////////////////////////////////////////////////////////////////////// @@ -662,10 +663,10 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! -#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { - t: u64, + t: u128, } #[stable(feature = "rust1", since = "1.0.0")] @@ -696,7 +697,31 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of<T: ?Sized + 'static>() -> TypeId { - TypeId { t: intrinsics::type_id::<T>() } + #[cfg(bootstrap)] + let t = intrinsics::type_id::<T>() as u128; + #[cfg(not(bootstrap))] + let t: u128 = intrinsics::type_id::<T>(); + TypeId { t } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for TypeId { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + // We only hash the lower 64 bits of our (128 bit) internal numeric ID, + // because: + // - The hashing algorithm which backs `TypeId` is expected to be + // unbiased and high quality, meaning further mixing would be somewhat + // redundant compared to choosing (the lower) 64 bits arbitrarily. + // - `Hasher::finish` returns a u64 anyway, so the extra entropy we'd + // get from hashing the full value would probably not be useful + // (especially given the previous point about the lower 64 bits being + // high quality on their own). + // - It is correct to do so -- only hashing a subset of `self` is still + // with an `Eq` implementation that considers the entire value, as + // ours does. + (self.t as u64).hash(state); } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index fec92320a..76b3589b9 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -538,29 +538,6 @@ impl<T, const N: usize> [T; N] { drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f))) } - /// 'Zips up' two arrays into a single array of pairs. - /// - /// `zip()` returns a new array where every element is a tuple where the - /// first element comes from the first array, and the second element comes - /// from the second array. In other words, it zips two arrays together, - /// into a single one. - /// - /// # Examples - /// - /// ``` - /// #![feature(array_zip)] - /// let x = [1, 2, 3]; - /// let y = [4, 5, 6]; - /// let z = x.zip(y); - /// assert_eq!(z, [(1, 4), (2, 5), (3, 6)]); - /// ``` - #[unstable(feature = "array_zip", issue = "80094")] - pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] { - drain_array_with(self, |lhs| { - drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs))) - }) - } - /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")] diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 744767aae..909b32547 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -59,7 +59,7 @@ //! [`borrow`](`RefCell::borrow`), and a mutable borrow (`&mut T`) can be obtained with //! [`borrow_mut`](`RefCell::borrow_mut`). When these functions are called, they first verify that //! Rust's borrow rules will be satisfied: any number of immutable borrows are allowed or a -//! single immutable borrow is allowed, but never both. If a borrow is attempted that would violate +//! single mutable borrow is allowed, but never both. If a borrow is attempted that would violate //! these rules, the thread will panic. //! //! The corresponding [`Sync`] version of `RefCell<T>` is [`RwLock<T>`]. @@ -1374,7 +1374,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::MAX); + assert!(borrow != BorrowFlag::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1756,7 +1756,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::MIN); + assert!(borrow != BorrowFlag::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 38a6d1ccd..ff5a4c913 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -495,8 +495,7 @@ pub trait Into<T>: Sized { /// By converting underlying error types to our own custom error type that encapsulates the /// underlying error type, we can return a single error type without losing information on the /// underlying cause. The '?' operator automatically converts the underlying error type to our -/// custom error type by calling `Into<CliError>::into` which is automatically provided when -/// implementing `From`. The compiler then infers which implementation of `Into` should be used. +/// custom error type with `From::from`. /// /// ``` /// use std::fs; @@ -533,7 +532,7 @@ pub trait Into<T>: Sized { #[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( - all(_Self = "&str", T = "std::string::String"), + all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")), note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] pub trait From<T>: Sized { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 09dbc9581..1f7be85d3 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -190,7 +190,7 @@ macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] impl Default for $t { - #[inline] + #[inline(always)] #[doc = $doc] fn default() -> $t { $v diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index e1e1a9b40..39f795c1f 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -81,7 +81,7 @@ use crate::str; #[derive(Hash)] #[stable(feature = "core_c_str", since = "1.64.0")] #[rustc_has_incoherent_inherent_impls] -#[cfg_attr(not(bootstrap), lang = "CStr")] +#[lang = "CStr"] // FIXME: // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies // on `CStr` being layout-compatible with `[u8]`. @@ -241,7 +241,7 @@ impl CStr { /// ``` /// /// ``` - /// #![feature(const_cstr_methods)] + /// #![feature(const_cstr_from_ptr)] /// /// use std::ffi::{c_char, CStr}; /// @@ -256,7 +256,7 @@ impl CStr { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "101719")] pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { // SAFETY: The caller has provided a pointer that points to a valid C // string with a NUL terminator of size less than `isize::MAX`, whose @@ -377,7 +377,7 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { @@ -561,10 +561,12 @@ 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_stable(feature = "const_cstr_methods", since = "1.72.0")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); + // FIXME(const-hack) replace with range index // SAFETY: to_bytes_with_nul returns slice with length at least 1 - unsafe { bytes.get_unchecked(..bytes.len() - 1) } + unsafe { slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1) } } /// Converts this C string to a byte slice containing the trailing 0 byte. @@ -588,7 +590,7 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] 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. @@ -612,7 +614,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_stable(feature = "const_cstr_methods", since = "1.72.0")] + 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/ffi/mod.rs b/library/core/src/ffi/mod.rs index b73abbbac..0488c8076 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -132,7 +132,12 @@ mod c_char_definition { ), all( target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "riscv64" + ) ), all( target_os = "vxworks", @@ -202,7 +207,7 @@ mod c_long_definition { // would be uninhabited and at least dereferencing such pointers would // be UB. #[doc = include_str!("c_void.md")] -#[cfg_attr(not(bootstrap), lang = "c_void")] +#[lang = "c_void"] #[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435 #[stable(feature = "core_c_void", since = "1.30.0")] pub enum c_void { @@ -238,7 +243,7 @@ impl fmt::Debug for c_void { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -267,7 +272,7 @@ pub struct VaListImpl<'f> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -292,7 +297,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf #[cfg(all( target_arch = "aarch64", - not(any(target_os = "macos", target_os = "ios")), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")), not(target_os = "uefi"), not(windows), ))] @@ -389,7 +394,10 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all( + target_arch = "aarch64", + any(target_os = "macos", target_os = "ios", target_os = "tvos") + ), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -404,7 +412,10 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), @@ -422,7 +433,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), - all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), + all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios", target_os = "tvos")), target_family = "wasm", target_arch = "asmjs", target_os = "uefi", @@ -449,7 +460,10 @@ impl<'f> VaListImpl<'f> { target_arch = "s390x", target_arch = "x86_64" ), - any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), + any( + not(target_arch = "aarch64"), + not(any(target_os = "macos", target_os = "ios", target_os = "tvos")) + ), not(target_family = "wasm"), not(target_arch = "asmjs"), not(target_os = "uefi"), diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 90cb79739..d27a9dfc1 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -24,6 +24,93 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` +/// +/// ## Capturing a pinned state +/// +/// Example of a closure wrapping inner futures: +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select<T>( +/// a: impl Future<Output = T>, +/// b: impl Future<Output = T>, +/// ) -> impl Future<Output = T> +/// { +/// let (mut a, mut b) = (Box::pin(a), Box::pin(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }) +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// +/// let a = future::pending(); +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 27); +/// +/// let a = async { 42 }; +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); // biased towards `a` in case of tie! +/// # } +/// ``` +/// +/// This time without [`Box::pin`]ning: +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::pin::pin; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select<T>( +/// a: impl Future<Output = T>, +/// b: impl Future<Output = T>, +/// ) -> impl Future<Output = T> +/// { +/// async { +/// let (mut a, mut b) = (pin!(a), pin!(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }).await +/// } +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// # } +/// ``` +/// +/// - Notice how, by virtue of being in an `async` context, we have been able to make the [`pin!`] +/// macro work, thereby avoiding any need for the `unsafe` +/// <code>[Pin::new_unchecked](&mut fut)</code> constructor. +/// +/// [`pin!`]: crate::pin::pin! #[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn<T, F>(f: F) -> PollFn<F> where diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f5c5dd29f..5a9a7013a 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1057,8 +1057,25 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] #[rustc_safe_intrinsic] #[rustc_nounwind] + #[cfg(bootstrap)] pub fn type_id<T: ?Sized + 'static>() -> u64; + /// Gets an identifier which is globally unique to the specified type. This + /// function will return the same value for a type regardless of whichever + /// crate it is invoked in. + /// + /// 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. + /// + /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. + #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] + #[rustc_safe_intrinsic] + #[rustc_nounwind] + #[cfg(not(bootstrap))] + pub fn type_id<T: ?Sized + 'static>() -> u128; + /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: /// This will statically either panic, or do nothing. /// @@ -1385,7 +1402,6 @@ extern "rust-intrinsic" { /// /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. - #[cfg(not(bootstrap))] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_nounwind] pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst; @@ -1425,19 +1441,11 @@ extern "rust-intrinsic" { /// returned value will result in undefined behavior. /// /// The stabilized version of this intrinsic is [`pointer::offset`]. - #[cfg(not(bootstrap))] #[must_use = "returns a new pointer rather than modifying its argument"] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_nounwind] pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr; - /// The bootstrap version of this is more restricted. - #[cfg(bootstrap)] - #[must_use = "returns a new pointer rather than modifying its argument"] - #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] - #[rustc_nounwind] - pub fn offset<T>(dst: *const T, offset: isize) -> *const T; - /// Calculates the offset from a pointer, potentially wrapping. /// /// This is implemented as an intrinsic to avoid converting to and from an @@ -2270,7 +2278,6 @@ extern "rust-intrinsic" { /// This intrinsic can *only* be called where the pointer is a local without /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[cfg(not(bootstrap))] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[rustc_nounwind] pub fn write_via_move<T>(ptr: *mut T, value: T); @@ -2650,7 +2657,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { @@ -2741,7 +2748,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { @@ -2814,7 +2821,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_allowed_through_unstable_modules] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] -#[inline] +#[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { @@ -2832,24 +2839,3 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { write_bytes(dst, val, count) } } - -/// Polyfill for bootstrap -#[cfg(bootstrap)] -pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst { - use crate::mem::*; - // SAFETY: It's a transmute -- the caller promised it's fine. - unsafe { transmute_copy(&ManuallyDrop::new(src)) } -} - -/// Polyfill for bootstrap -#[cfg(bootstrap)] -pub const unsafe fn write_via_move<T>(ptr: *mut T, value: T) { - use crate::mem::*; - // SAFETY: the caller must guarantee that `dst` is valid for writes. - // `dst` cannot overlap `src` because the caller has mutable access - // to `dst` while `src` is owned by this function. - unsafe { - copy_nonoverlapping::<T>(&value, ptr, 1); - forget(value); - } -} diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 2568aaf34..d3e454563 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -310,7 +310,7 @@ where /// Real logic of both `Flatten` and `FlatMap` which simply delegate to /// this type. #[derive(Clone, Debug)] -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] struct FlattenCompat<I, U> { iter: Fuse<I>, frontiter: Option<U>, @@ -464,7 +464,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] impl<I, U> Iterator for FlattenCompat<I, U> where I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, @@ -579,7 +579,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] impl<I, U> DoubleEndedIterator for FlattenCompat<I, U> where I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, @@ -649,7 +649,7 @@ where } } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl<const N: usize, I, T> TrustedLen for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter> where @@ -657,7 +657,7 @@ where { } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter> where @@ -665,7 +665,7 @@ where { } -#[unstable(feature = "trusted_len", issue = "37572")] +#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter> where diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 4252c34a0..7f58f7d17 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,4 +1,9 @@ -use crate::{intrinsics, iter::from_fn, ops::Try}; +use crate::convert::TryFrom; +use crate::{ + intrinsics, + iter::{from_fn, TrustedLen}, + ops::{Range, Try}, +}; /// An iterator for stepping iterators by a custom amount. /// @@ -11,14 +16,22 @@ use crate::{intrinsics, iter::from_fn, ops::Try}; #[stable(feature = "iterator_step_by", since = "1.28.0")] #[derive(Clone, Debug)] pub struct StepBy<I> { + /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup` + /// in the constructor. + /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy + /// which means the inner iterator cannot be returned to user code. + /// Additionally this type-dependent preprocessing means specialized implementations + /// cannot be used interchangeably. iter: I, step: usize, first_take: bool, } impl<I> StepBy<I> { + #[inline] pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> { assert!(step != 0); + let iter = <I as SpecRangeSetup<I>>::setup(iter, step); StepBy { iter, step: step - 1, first_take: true } } } @@ -32,16 +45,174 @@ where #[inline] fn next(&mut self) -> Option<Self::Item> { + self.spec_next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.spec_size_hint() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.spec_nth(n) + } + + fn try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc>, + { + self.spec_try_fold(acc, f) + } + + #[inline] + fn fold<Acc, F>(self, acc: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + self.spec_fold(acc, f) + } +} + +impl<I> StepBy<I> +where + I: ExactSizeIterator, +{ + // The zero-based index starting from the end of the iterator of the + // last element. Used in the `DoubleEndedIterator` implementation. + fn next_back_index(&self) -> usize { + let rem = self.iter.len() % (self.step + 1); if self.first_take { - self.first_take = false; - self.iter.next() + if rem == 0 { self.step } else { rem - 1 } } else { - self.iter.nth(self.step) + rem } } +} +#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] +impl<I> DoubleEndedIterator for StepBy<I> +where + I: DoubleEndedIterator + ExactSizeIterator, +{ #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { + fn next_back(&mut self) -> Option<Self::Item> { + self.spec_next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + self.spec_nth_back(n) + } + + fn try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc>, + { + self.spec_try_rfold(init, f) + } + + #[inline] + fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc + where + Self: Sized, + F: FnMut(Acc, Self::Item) -> Acc, + { + self.spec_rfold(init, f) + } +} + +// StepBy can only make the iterator shorter, so the len will still fit. +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {} + +trait SpecRangeSetup<T> { + fn setup(inner: T, step: usize) -> T; +} + +impl<T> SpecRangeSetup<T> for T { + #[inline] + default fn setup(inner: T, _step: usize) -> T { + inner + } +} + +/// Specialization trait to optimize `StepBy<Range<{integer}>>` iteration. +/// +/// # Safety +/// +/// Technically this is safe to implement (look ma, no unsafe!), but in reality +/// a lot of unsafe code relies on ranges over integers being correct. +/// +/// For correctness *all* public StepBy methods must be specialized +/// because `setup` drastically alters the meaning of the struct fields so that mixing +/// different implementations would lead to incorrect results. +unsafe trait StepByImpl<I> { + type Item; + + fn spec_next(&mut self) -> Option<Self::Item>; + + fn spec_size_hint(&self) -> (usize, Option<usize>); + + fn spec_nth(&mut self, n: usize) -> Option<Self::Item>; + + fn spec_try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc>; + + fn spec_fold<Acc, F>(self, acc: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc; +} + +/// Specialization trait for double-ended iteration. +/// +/// See also: `StepByImpl` +/// +/// # Safety +/// +/// The specializations must be implemented together with `StepByImpl` +/// where applicable. I.e. if `StepBy` does support backwards iteration +/// for a given iterator and that is specialized for forward iteration then +/// it must also be specialized for backwards iteration. +unsafe trait StepByBackImpl<I> { + type Item; + + fn spec_next_back(&mut self) -> Option<Self::Item> + where + I: DoubleEndedIterator + ExactSizeIterator; + + fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> + where + I: DoubleEndedIterator + ExactSizeIterator; + + fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R + where + I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc>; + + fn spec_rfold<Acc, F>(self, init: Acc, f: F) -> Acc + where + I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(Acc, Self::Item) -> Acc; +} + +unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { + type Item = I::Item; + + #[inline] + default fn spec_next(&mut self) -> Option<I::Item> { + let step_size = if self.first_take { 0 } else { self.step }; + self.first_take = false; + self.iter.nth(step_size) + } + + #[inline] + default fn spec_size_hint(&self) -> (usize, Option<usize>) { #[inline] fn first_size(step: usize) -> impl Fn(usize) -> usize { move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } @@ -64,7 +235,7 @@ where } #[inline] - fn nth(&mut self, mut n: usize) -> Option<Self::Item> { + default fn spec_nth(&mut self, mut n: usize) -> Option<I::Item> { if self.first_take { self.first_take = false; let first = self.iter.next(); @@ -108,7 +279,7 @@ where } } - fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R + default fn spec_try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, @@ -128,7 +299,7 @@ where from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) } - fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc + default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { @@ -148,34 +319,16 @@ where } } -impl<I> StepBy<I> -where - I: ExactSizeIterator, -{ - // The zero-based index starting from the end of the iterator of the - // last element. Used in the `DoubleEndedIterator` implementation. - fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { - if rem == 0 { self.step } else { rem - 1 } - } else { - rem - } - } -} +unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I> { + type Item = I::Item; -#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")] -impl<I> DoubleEndedIterator for StepBy<I> -where - I: DoubleEndedIterator + ExactSizeIterator, -{ #[inline] - fn next_back(&mut self) -> Option<Self::Item> { + default fn spec_next_back(&mut self) -> Option<Self::Item> { self.iter.nth_back(self.next_back_index()) } #[inline] - fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + default fn spec_nth_back(&mut self, n: usize) -> Option<I::Item> { // `self.iter.nth_back(usize::MAX)` does the right thing here when `n` // is out of bounds because the length of `self.iter` does not exceed // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is @@ -184,7 +337,7 @@ where self.iter.nth_back(n) } - fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R + default fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, @@ -207,10 +360,10 @@ where } #[inline] - fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc + default fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc where Self: Sized, - F: FnMut(Acc, Self::Item) -> Acc, + F: FnMut(Acc, I::Item) -> Acc, { #[inline] fn nth_back<I: DoubleEndedIterator>( @@ -230,6 +383,192 @@ where } } -// StepBy can only make the iterator shorter, so the len will still fit. -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {} +/// For these implementations, `SpecRangeSetup` calculates the number +/// of iterations that will be needed and stores that in `iter.end`. +/// +/// The various iterator implementations then rely on that to not need +/// overflow checking, letting loops just be counted instead. +/// +/// These only work for unsigned types, and will need to be reworked +/// if you want to use it to specialize on signed types. +/// +/// Currently these are only implemented for integers up to usize due to +/// correctness issues around ExactSizeIterator impls on 16bit platforms. +/// And since ExactSizeIterator is a prerequisite for backwards iteration +/// and we must consistently specialize backwards and forwards iteration +/// that makes the situation complicated enough that it's not covered +/// for now. +macro_rules! spec_int_ranges { + ($($t:ty)*) => ($( + + const _: () = assert!(usize::BITS >= <$t>::BITS); + + impl SpecRangeSetup<Range<$t>> for Range<$t> { + #[inline] + fn setup(mut r: Range<$t>, step: usize) -> Range<$t> { + let inner_len = r.size_hint().0; + // If step exceeds $t::MAX, then the count will be at most 1 and + // thus always fit into $t. + let yield_count = inner_len.div_ceil(step); + // Turn the range end into an iteration counter + r.end = yield_count as $t; + r + } + } + + unsafe impl StepByImpl<Range<$t>> for StepBy<Range<$t>> { + #[inline] + fn spec_next(&mut self) -> Option<$t> { + // if a step size larger than the type has been specified fall back to + // t::MAX, in which case remaining will be at most 1. + // The `+ 1` can't overflow since the constructor substracted 1 from the original value. + let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let remaining = self.iter.end; + if remaining > 0 { + let val = self.iter.start; + // this can only overflow during the last step, after which the value + // will not be used + self.iter.start = val.wrapping_add(step); + self.iter.end = remaining - 1; + Some(val) + } else { + None + } + } + + #[inline] + fn spec_size_hint(&self) -> (usize, Option<usize>) { + let remaining = self.iter.end as usize; + (remaining, Some(remaining)) + } + + // The methods below are all copied from the Iterator trait default impls. + // We have to repeat them here so that the specialization overrides the StepByImpl defaults + + #[inline] + fn spec_nth(&mut self, n: usize) -> Option<Self::Item> { + self.advance_by(n).ok()?; + self.next() + } + + #[inline] + fn spec_try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R + where + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc> + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x)?; + } + try { accum } + } + + #[inline] + fn spec_fold<Acc, F>(self, init: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc + { + // if a step size larger than the type has been specified fall back to + // t::MAX, in which case remaining will be at most 1. + let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let remaining = self.iter.end; + let mut acc = init; + let mut val = self.iter.start; + for _ in 0..remaining { + acc = f(acc, val); + // this can only overflow during the last step, after which the value + // will no longer be used + val = val.wrapping_add(step); + } + acc + } + } + + /// Safety: This macro is only applied to ranges over types <= usize + /// which means the inner length is guaranteed to fit into a usize and so + /// the outer length calculation won't encounter clamped values + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for StepBy<Range<$t>> {} + )*) +} + +macro_rules! spec_int_ranges_r { + ($($t:ty)*) => ($( + const _: () = assert!(usize::BITS >= <$t>::BITS); + + unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> { + + #[inline] + fn spec_next_back(&mut self) -> Option<Self::Item> + where Range<$t>: DoubleEndedIterator + ExactSizeIterator, + { + let step = (self.step + 1) as $t; + let remaining = self.iter.end; + if remaining > 0 { + let start = self.iter.start; + self.iter.end = remaining - 1; + Some(start + step * (remaining - 1)) + } else { + None + } + } + + // The methods below are all copied from the Iterator trait default impls. + // We have to repeat them here so that the specialization overrides the StepByImplBack defaults + + #[inline] + fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> + where Self: DoubleEndedIterator, + { + if self.advance_back_by(n).is_err() { + return None; + } + self.next_back() + } + + #[inline] + fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R + where + Self: DoubleEndedIterator, + F: FnMut(Acc, Self::Item) -> R, + R: Try<Output = Acc> + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x)?; + } + try { accum } + } + + #[inline] + fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc + where + Self: DoubleEndedIterator, + F: FnMut(Acc, Self::Item) -> Acc + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } + } + )*) +} + +#[cfg(target_pointer_width = "64")] +spec_int_ranges!(u8 u16 u32 u64 usize); +// DoubleEndedIterator requires ExactSizeIterator, which isn't implemented for Range<u64> +#[cfg(target_pointer_width = "64")] +spec_int_ranges_r!(u8 u16 u32 usize); + +#[cfg(target_pointer_width = "32")] +spec_int_ranges!(u8 u16 u32 usize); +#[cfg(target_pointer_width = "32")] +spec_int_ranges_r!(u8 u16 u32 usize); + +#[cfg(target_pointer_width = "16")] +spec_int_ranges!(u8 u16 usize); +#[cfg(target_pointer_width = "16")] +spec_int_ranges_r!(u8 u16 usize); diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0171d8981..462f7170a 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -619,9 +619,10 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_next(&mut self) -> Option<T> { if self.start < self.end { + let old = self.start; // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; - Some(mem::replace(&mut self.start, n)) + self.start = unsafe { Step::forward_unchecked(old, 1) }; + Some(old) } else { None } @@ -629,15 +630,15 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_nth(&mut self, n: usize) -> Option<T> { - if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if let Some(plus_n) = Step::forward_checked(self.start, n) { if plus_n < self.end { // SAFETY: just checked precondition - self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) }; + self.start = unsafe { Step::forward_unchecked(plus_n, 1) }; return Some(plus_n); } } - self.start = self.end.clone(); + self.start = self.end; None } @@ -655,7 +656,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { // then steps_between either returns a bound to which we clamp or returns None which // together with the initial inequality implies more than usize::MAX steps. // Otherwise 0 is returned which always safe to use. - self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + self.start = unsafe { Step::forward_unchecked(self.start, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } @@ -664,8 +665,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { fn spec_next_back(&mut self) -> Option<T> { if self.start < self.end { // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - Some(self.end.clone()) + self.end = unsafe { Step::backward_unchecked(self.end, 1) }; + Some(self.end) } else { None } @@ -673,15 +674,15 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { #[inline] fn spec_nth_back(&mut self, n: usize) -> Option<T> { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if let Some(minus_n) = Step::backward_checked(self.end, n) { if minus_n > self.start { // SAFETY: just checked precondition self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; - return Some(self.end.clone()); + return Some(self.end); } } - self.end = self.start.clone(); + self.end = self.start; None } @@ -696,7 +697,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { let taken = available.min(n); // SAFETY: same as the spec_advance_by() implementation - self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + self.end = unsafe { Step::backward_unchecked(self.end, taken) }; NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs index 99f058a90..6a6cbe905 100644 --- a/library/core/src/iter/sources/successors.rs +++ b/library/core/src/iter/sources/successors.rs @@ -22,7 +22,7 @@ where Successors { next: first, succ } } -/// An new iterator where each successive item is computed based on the preceding one. +/// A new iterator where each successive item is computed based on the preceding one. /// /// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index dabfce144..988352283 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -26,13 +26,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - _Self = "std::ops::RangeTo<Idx>", + any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"), label = "if you meant to iterate until a value, add a starting value", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ bounded `Range`: `0..end`" ), on( - _Self = "std::ops::RangeToInclusive<Idx>", + any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"), label = "if you meant to iterate until a value (including it), add a starting value", note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ to have a bounded `RangeInclusive`: `0..=end`" @@ -43,7 +43,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} ), on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), on( - _Self = "std::vec::Vec<T, A>", + any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"), label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" ), on( @@ -51,7 +51,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( - _Self = "std::string::String", + any(_Self = "alloc::string::String", _Self = "std::string::String"), label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index af0284823..c21a2aac1 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,4 +86,4 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +pub unsafe trait TrustedStep: Step + Copy {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6c419eb16..05876f5fc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -113,7 +113,6 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_from_u32_unchecked)] -#![feature(const_cstr_methods)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_exact_div)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c4134dbcd..45e5b7627 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -960,6 +960,8 @@ pub(crate) mod builtin { /// /// A compile time error is never emitted when using this macro regardless /// of whether the environment variable is present or not. + /// To emit a compile error if the environment variable is not present, + /// use the [`env!`] macro instead. /// /// # Examples /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 8dab8d1a6..e251015dd 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -140,7 +140,8 @@ unsafe impl<T: Sync + ?Sized> Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[rustc_coinductive] pub trait Sized { // Empty. @@ -173,7 +174,8 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "18598")] #[lang = "unsize"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Unsize<T: ?Sized> { // Empty. } @@ -205,6 +207,20 @@ pub trait StructuralPartialEq { // Empty. } +marker_impls! { + #[unstable(feature = "structural_match", issue = "31434")] + StructuralPartialEq for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + bool, + char, + str /* Technically requires `[u8]: StructuralEq` */, + (), + {T, const N: usize} [T; N], + {T} [T], + {T: ?Sized} &T, +} + /// Required trait for constants used in pattern matches. /// /// Any type that derives `Eq` automatically implements this trait, *regardless* @@ -267,6 +283,7 @@ marker_impls! { bool, char, str /* Technically requires `[u8]: StructuralEq` */, + (), {T, const N: usize} [T; N], {T} [T], {T: ?Sized} &T, @@ -558,59 +575,59 @@ impl<T: ?Sized> Copy for &T {} #[lang = "sync"] #[rustc_on_unimplemented( on( - _Self = "std::cell::OnceCell<T>", + any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" ), on( - _Self = "std::cell::Cell<u8>", + any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", ), on( - _Self = "std::cell::Cell<u16>", + any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", ), on( - _Self = "std::cell::Cell<u32>", + any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", ), on( - _Self = "std::cell::Cell<u64>", + any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", ), on( - _Self = "std::cell::Cell<usize>", + any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", ), on( - _Self = "std::cell::Cell<i8>", + any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", ), on( - _Self = "std::cell::Cell<i16>", + any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", ), on( - _Self = "std::cell::Cell<i32>", + any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", ), on( - _Self = "std::cell::Cell<i64>", + any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", ), on( - _Self = "std::cell::Cell<isize>", + any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", ), on( - _Self = "std::cell::Cell<bool>", + any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", ), on( - _Self = "std::cell::Cell<T>", + any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", ), on( - _Self = "std::cell::RefCell<T>", + any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", ), message = "`{Self}` cannot be shared between threads safely", @@ -839,7 +856,8 @@ impl<T: ?Sized> StructuralEq for PhantomData<T> {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -944,7 +962,8 @@ marker_impls! { #[unstable(feature = "const_trait_impl", issue = "67792")] #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] #[const_trait] pub trait Destruct {} @@ -955,7 +974,8 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Tuple {} /// A marker for pointer-like types. @@ -971,21 +991,20 @@ pub trait Tuple {} pub trait PointerLike {} /// A marker for types which can be used as types of `const` generic parameters. -#[cfg_attr(not(bootstrap), lang = "const_param_ty")] +#[lang = "const_param_ty"] #[unstable(feature = "adt_const_params", issue = "95174")] #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] -pub trait ConstParamTy: StructuralEq {} +#[allow(multiple_supertrait_upcastable)] +pub trait ConstParamTy: StructuralEq + StructuralPartialEq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] #[unstable(feature = "adt_const_params", issue = "95174")] -#[cfg(not(bootstrap))] pub macro ConstParamTy($item:item) { /* compiler built-in */ } -// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure` -// FIXME(generic_const_parameter_types): handle `ty::Tuple` +// FIXME(adt_const_params): handle `ty::FnDef`/`ty::Closure` marker_impls! { #[unstable(feature = "adt_const_params", issue = "95174")] ConstParamTy for @@ -999,6 +1018,11 @@ marker_impls! { {T: ?Sized + ConstParamTy} &T, } +// FIXME(adt_const_params): Add to marker_impls call above once not in bootstrap +#[unstable(feature = "adt_const_params", issue = "95174")] +#[cfg(not(bootstrap))] +impl ConstParamTy for () {} + /// A common trait implemented by all function pointers. #[unstable( feature = "fn_ptr_trait", @@ -1006,7 +1030,8 @@ marker_impls! { reason = "internal trait for implementing various traits for all function pointers" )] #[lang = "fn_ptr_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait FnPtr: Copy + Clone { /// Returns the address of the function pointer. #[lang = "fn_ptr_addr"] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index afbfd6d36..2fff3f0ef 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -968,7 +968,7 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T { /// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` -/// # #![cfg_attr(not(bootstrap), allow(dropping_copy_types))] +/// # #![allow(dropping_copy_types)] /// #[derive(Copy, Clone)] /// struct Foo(u8); /// @@ -1316,9 +1316,9 @@ impl<T> SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` -#[cfg(not(bootstrap))] #[unstable(feature = "offset_of", issue = "106655")] -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(builtin_syntax, hint_must_use)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - builtin # offset_of($Container, $($fields).+) + // The `{}` is for better error messages + crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) } diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 87ae30619..3805d149b 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -1,3 +1,5 @@ +use crate::marker::ConstParamTy; + /// Are values of a type transmutable into values of another type? /// /// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of @@ -5,6 +7,8 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> where Src: ?Sized, @@ -33,6 +37,9 @@ pub struct Assume { pub validity: bool, } +#[unstable(feature = "transmutability", issue = "99571")] +impl ConstParamTy for Assume {} + impl Assume { /// Do not assume that *you* have ensured any safety properties are met. #[unstable(feature = "transmutability", issue = "99571")] diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 954d88d54..c51913fa8 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1770,14 +1770,8 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } + } else if let Some(ipv4) = self.to_ipv4_mapped() { + write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] struct Span { diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4a035ad61..d050d21c8 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -403,6 +403,7 @@ impl f32 { /// and the stability of its representation over Rust versions /// and target platforms isn't guaranteed. #[stable(feature = "assoc_int_consts", since = "1.43.0")] + #[rustc_diagnostic_item = "f32_nan"] pub const NAN: f32 = 0.0_f32 / 0.0_f32; /// Infinity (∞). #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 3aafc435f..d9a738191 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -401,6 +401,7 @@ impl f64 { /// This constant isn't guaranteed to equal to any specific NaN bitpattern, /// and the stability of its representation over Rust versions /// and target platforms isn't guaranteed. + #[rustc_diagnostic_item = "f64_nan"] #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NAN: f64 = 0.0_f64 / 0.0_f64; /// Infinity (∞). diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c9baa09f4..95dcaf5dd 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,7 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; -use crate::convert::TryInto; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -278,18 +277,12 @@ macro_rules! widening_impl { macro_rules! conv_rhs_for_unchecked_shift { ($SelfT:ty, $x:expr) => {{ - #[inline] - fn conv(x: u32) -> $SelfT { - // FIXME(const-hack) replace with `.try_into().ok().unwrap_unchecked()`. - // SAFETY: Any legal shift amount must be losslessly representable in the self type. - unsafe { x.try_into().ok().unwrap_unchecked() } - } - #[inline] - const fn const_conv(x: u32) -> $SelfT { - x as _ + // If the `as` cast will truncate, ensure we still tell the backend + // that the pre-truncation value was also small. + if <$SelfT>::BITS < 32 { + intrinsics::assume($x <= (<$SelfT>::MAX as u32)); } - - intrinsics::const_eval_select(($x,), const_conv, conv) + $x as $SelfT }}; } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7f06e170a..5939dedbd 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -348,7 +348,7 @@ macro_rules! nonzero_unsigned_operations { } /// Adds an unsigned integer to a non-zero value. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -579,7 +579,7 @@ macro_rules! nonzero_signed_operations { /// Checked absolute value. /// Checks for overflow and returns [`None`] if - #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] + #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] /// The result cannot be zero. /// /// # Example @@ -800,7 +800,8 @@ macro_rules! nonzero_signed_operations { self.get().is_negative() } - /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`. + /// Checked negation. Computes `-self`, + #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] /// /// # Example /// @@ -859,8 +860,10 @@ macro_rules! nonzero_signed_operations { ((unsafe { $Ty::new_unchecked(result) }), overflow) } - /// Saturating negation. Computes `-self`, returning `MAX` if - /// `self == i32::MIN` instead of overflowing. + /// Saturating negation. Computes `-self`, + #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] + #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] + /// instead of overflowing. /// /// # Example /// @@ -993,7 +996,7 @@ macro_rules! nonzero_unsigned_signed_operations { } /// Multiplies two non-zero integers together. - #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] /// /// # Examples /// @@ -1102,11 +1105,11 @@ macro_rules! nonzero_unsigned_signed_operations { #[doc = sign_dependent_expr!{ $signedness ? if signed { - concat!("Return [`", stringify!($Int), "::MIN`] ", - "or [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MIN`] ", + "or [`", stringify!($Ty), "::MAX`] on overflow.") } if unsigned { - concat!("Return [`", stringify!($Int), "::MAX`] on overflow.") + concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") } }] /// diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 1f1784ec9..f4649be54 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -153,7 +153,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" ), on( - _Self = "std::string::String", + any(_Self = "alloc::string::String", _Self = "std::string::String"), note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" ), diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index b4f69d0b2..17625dacc 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -226,8 +226,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::result::Result<T, E>", - R = "std::option::Option<std::convert::Infallible>" + any( + _Self = "core::result::Result<T, E>", + _Self = "std::result::Result<T, E>", + ), + any( + R = "core::option::Option<core::convert::Infallible>", + 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`", @@ -237,7 +243,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::result::Result<T, E>", + any( + _Self = "core::result::Result<T, E>", + _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, @@ -250,8 +259,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::option::Option<T>", - R = "std::result::Result<T, E>", + any( + _Self = "core::option::Option<T>", + _Self = "std::option::Option<T>", + ), + any( + R = "core::result::Result<T, E>", + R = "std::result::Result<T, E>", + ) ), message = "the `?` operator can only be used on `Option`s, not `Result`s, \ in {ItemContext} that returns `Option`", @@ -261,7 +276,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::option::Option<T>", + any( + _Self = "core::option::Option<T>", + _Self = "std::option::Option<T>", + ) ), // `Option`-in-`Option` always works, as there's only one possible // residual, so this can also be phrased strongly. @@ -273,8 +291,14 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::ops::ControlFlow<B, C>", - R = "std::ops::ControlFlow<B, C>", + any( + _Self = "core::ops::ControlFlow<B, C>", + _Self = "std::ops::ControlFlow<B, C>", + ), + any( + R = "core::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)", @@ -285,7 +309,10 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - _Self = "std::ops::ControlFlow<B, C>", + any( + _Self = "core::ops::ControlFlow<B, C>", + _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 \ diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ec1ef3cf4..9b6ff76b2 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1138,7 +1138,7 @@ impl<T> Option<T> { /// Computes a default function result (if none), or /// applies a different function to the contained value (if any). /// - /// # Examples + /// # Basic examples /// /// ``` /// let k = 21; @@ -1149,6 +1149,25 @@ impl<T> Option<T> { /// let x: Option<&str> = None; /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); /// ``` + /// + /// # Handling a Result-based fallback + /// + /// A somewhat common occurrence when dealing with optional values + /// in combination with [`Result<T, E>`] is the case where one wants to invoke + /// a fallible fallback if the option is not present. This example + /// parses a command line argument (if present), or the contents of a file to + /// an integer. However, unlike accessing the command line argument, reading + /// the file is fallible, so it must be wrapped with `Ok`. + /// + /// ```no_run + /// # fn main() -> Result<(), Box<dyn std::error::Error>> { + /// let v: u64 = std::env::args() + /// .nth(1) + /// .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)? + /// .parse()?; + /// # Ok(()) + /// # } + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U @@ -1383,6 +1402,7 @@ impl<T> Option<T> { /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0)); /// assert_eq!(item_2_0, None); /// ``` + #[doc(alias = "flatmap")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn and_then<U, F>(self, f: F) -> Option<U> diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 81be3fb22..f0fcdab00 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -166,14 +166,15 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref +#[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } - panic!( + panic_nounwind_fmt(format_args!( "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" - ) + )) } /// Panic because we cannot unwind out of a function. diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 8266e8990..80289ca08 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -308,7 +308,7 @@ mod prim_never {} /// /// ```no_run /// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }; +/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// /// USVs are also the exact set of values that may be encoded in UTF-8. Because diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 6e1e862d3..926189a17 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -104,6 +104,7 @@ impl<T: ?Sized> *const T { /// refactored. #[stable(feature = "ptr_const_cast", since = "1.65.0")] #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_diagnostic_item = "ptr_cast_mut"] #[inline(always)] pub const fn cast_mut(self) -> *mut T { self as _ @@ -916,16 +917,8 @@ impl<T: ?Sized> *const T { where T: Sized, { - #[cfg(bootstrap)] // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - self.offset(count as isize) - } - #[cfg(not(bootstrap))] - // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 2ea032d4a..daaa44b1d 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -50,7 +50,8 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] -#[rustc_deny_explicit_impl] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))] +#[cfg_attr(bootstrap, rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d0cb2f715..acc9ca29d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -698,6 +698,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] +#[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { r } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2fe5164c3..c6f438578 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -473,20 +473,10 @@ impl<T: ?Sized> *mut T { where T: Sized, { - #[cfg(bootstrap)] // SAFETY: the caller must uphold the safety contract for `offset`. // The obtained pointer is valid for writes since the caller must // guarantee that it points to the same allocated object as `self`. - unsafe { - intrinsics::offset(self, count) as *mut T - } - #[cfg(not(bootstrap))] - // SAFETY: the caller must uphold the safety contract for `offset`. - // The obtained pointer is valid for writes since the caller must - // guarantee that it points to the same allocated object as `self`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes. @@ -1026,16 +1016,8 @@ impl<T: ?Sized> *mut T { where T: Sized, { - #[cfg(bootstrap)] - // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - self.offset(count as isize) - } - #[cfg(not(bootstrap))] // SAFETY: the caller must uphold the safety contract for `offset`. - unsafe { - intrinsics::offset(self, count) - } + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index a853f15ed..ff7e91d3e 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -32,6 +32,8 @@ use crate::ptr::NonNull; )] #[doc(hidden)] #[repr(transparent)] +// Lang item used experimentally by Miri to define the semantics of `Unique`. +#[cfg_attr(not(bootstrap), lang = "ptr_unique")] pub struct Unique<T: ?Sized> { pointer: NonNull<T>, // NOTE: this marker has no consequences for variance, but is necessary diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 6ef9f9c95..e1e3bcc05 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -152,7 +152,10 @@ mod private_slice_index { #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), on( - all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), + all( + any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"), + _Self = "{integer}" + ), note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ for more information, see chapter 8 in The Book: \ <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 3462c0e02..96a145e22 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -191,6 +191,39 @@ macro_rules! iterator { self.next_back() } + #[inline] + fn fold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + // this implementation consists of the following optimizations compared to the + // default implementation: + // - do-while loop, as is llvm's preferred loop shape, + // see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops + // - bumps an index instead of a pointer since the latter case inhibits + // some optimizations, see #111603 + // - avoids Option wrapping/matching + if is_empty!(self) { + return init; + } + let mut acc = init; + let mut i = 0; + let len = len!(self); + loop { + // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of + // the slice allocation + acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() }); + // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the + // slice had that length, in which case we'll break out of the loop + // after the increment + i = unsafe { i.unchecked_add(1) }; + if i == len { + break; + } + } + acc + } + // We override the default implementation, which uses `try_fold`, // because this simple implementation generates less LLVM IR and is // faster to compile. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ea0181e35..e2a2428fb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -851,6 +851,8 @@ impl<T> [T] { /// Swaps two elements in the slice. /// + /// If `a` equals to `b`, it's guaranteed that elements won't change value. + /// /// # Arguments /// /// * a - The index of the first element @@ -2995,7 +2997,7 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is /// unstable (i.e. any number of equal elements may end up at position `index`), in-place - /// (i.e. does not allocate), and *O*(*n*) on average. The worst-case performance is *O*(*n* log *n*). + /// (i.e. does not allocate), and runs in *O*(*n*) time. /// This function is also known as "kth element" in other libraries. /// /// It returns a triplet of the following from the reordered slice: @@ -3045,9 +3047,8 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the comparator function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) on average. - /// The worst-case performance is *O*(*n* log *n*). This function is also known as - /// "kth element" in other libraries. + /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. + /// This function is also known as "kth element" in other libraries. /// /// It returns a triplet of the following from /// the slice reordered according to the provided comparator function: the subslice prior to @@ -3101,8 +3102,7 @@ impl<T> [T] { /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index` using the key extraction function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) on average. - /// The worst-case performance is *O*(*n* log *n*). + /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. /// This function is also known as "kth element" in other libraries. /// /// It returns a triplet of the following from @@ -3113,8 +3113,9 @@ impl<T> [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 052fd34d0..48a6eb03b 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -32,7 +32,8 @@ use crate::ptr; /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// # Caveat @@ -125,7 +126,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`. +/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// [valid]: ptr#safety @@ -179,15 +181,16 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements. @@ -247,16 +250,17 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { /// the last element, such that the offset from the end to the start pointer is /// the length of the slice. /// -/// * The range must contain `N` consecutive properly initialized values of type `T`: +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. /// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// * The range must contain `N` consecutive properly initialized values of type `T`. /// /// * The memory referenced by the returned slice must not be accessed through any other pointer /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total length of the range must be no larger than `isize::MAX`. +/// * The total length of the range must be no larger than `isize::MAX`, +/// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// /// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 5f8748206..0f23cf7ae 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -84,6 +84,7 @@ use super::Utf8Error; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_shared", since = "1.63.0")] #[rustc_allow_const_fn_unstable(str_internals)] +#[rustc_diagnostic_item = "str_from_utf8"] pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { // FIXME: This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -127,6 +128,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // This should use `?` again, once it's `const` match run_utf8_validation(v) { @@ -167,6 +169,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked"] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. @@ -194,6 +197,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` // are valid UTF-8, thus the cast to `*mut str` is safe. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index ef05b25fd..9a93bb729 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -144,8 +144,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let len = "foo".len(); /// assert_eq!(3, len); @@ -165,8 +163,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = ""; /// assert!(s.is_empty()); @@ -311,8 +307,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bytes = "bors".as_bytes(); /// assert_eq!(b"bors", bytes); @@ -387,8 +381,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Hello"; /// let ptr = s.as_ptr(); @@ -570,8 +562,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Löwe 老虎 Léopard"; /// @@ -649,8 +639,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "Per Martin-Löf"; /// @@ -691,8 +679,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = "Per Martin-Löf".to_string(); /// { @@ -840,8 +826,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut bytes = "bors".bytes(); /// @@ -1020,8 +1004,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let text = "Zażółć gęślą jaźń"; /// @@ -1050,8 +1032,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1077,8 +1057,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1103,8 +1081,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let bananas = "bananas"; /// @@ -1463,8 +1439,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); /// assert_eq!(v, ["A", "B"]); @@ -1696,8 +1670,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); /// assert_eq!(v, ["abc", "abc", "abc"]); @@ -1732,8 +1704,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); /// assert_eq!(v, ["abc", "abc", "abc"]); @@ -1775,8 +1745,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); @@ -1817,8 +1785,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); @@ -1845,8 +1811,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "\n Hello\tworld\t\n"; /// @@ -2085,8 +2049,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11"); /// assert_eq!("123foo1bar123".trim_start_matches(char::is_numeric), "foo1bar123"); @@ -2232,8 +2194,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 7043ab5ff..b63fd5c90 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -2,6 +2,7 @@ use crate::fmt; use crate::marker::{PhantomData, Unpin}; +use crate::ptr; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] /// which provides customized wakeup behavior. @@ -322,6 +323,45 @@ impl Waker { Waker { waker } } + /// Creates a new `Waker` that does nothing when `wake` is called. + /// + /// This is mostly useful for writing tests that need a [`Context`] to poll + /// some futures, but are not expecting those futures to wake the waker or + /// do not need to do anything specific if it happens. + /// + /// # Examples + /// + /// ``` + /// #![feature(noop_waker)] + /// + /// use std::future::Future; + /// use std::task; + /// + /// let waker = task::Waker::noop(); + /// let mut cx = task::Context::from_waker(&waker); + /// + /// let mut future = Box::pin(async { 10 }); + /// assert_eq!(future.as_mut().poll(&mut cx), task::Poll::Ready(10)); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "noop_waker", issue = "98286")] + pub const fn noop() -> Waker { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RAW, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); + + Waker { waker: RAW } + } + /// Get a reference to the underlying [`RawWaker`]. #[inline] #[must_use] diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index a1388dfee..ac8d04a82 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,6 +1,9 @@ // See src/libstd/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; +#[cfg(not(bootstrap))] +use crate::marker::ConstParamTy; +use crate::marker::{StructuralEq, StructuralPartialEq}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -47,6 +50,28 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + #[cfg(not(bootstrap))] + impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + impl<$($T),+> StructuralPartialEq for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "structural_match", issue = "31434")] + impl<$($T),+> StructuralEq for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+) where diff --git a/library/core/src/unicode/printable.py b/library/core/src/unicode/printable.py index 7c37f5f09..4d39ace06 100755 --- a/library/core/src/unicode/printable.py +++ b/library/core/src/unicode/printable.py @@ -119,7 +119,7 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) print("];") def print_normal(normal, normalname): |