diff options
| author | bors <bors@rust-lang.org> | 2024-09-25 06:41:56 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-09-25 06:41:56 +0000 |
| commit | 34aff74fb06e78fb9cd1a66acafb6d150638de35 (patch) | |
| tree | 14533de260c2f1834994e58af1d210a6884625a9 /library/alloc/src | |
| parent | 938c7b1162a38dca257c7004ef7ecf86397a8634 (diff) | |
| parent | 8be19465ec14880160d294f2909202451a547740 (diff) | |
| download | rust-34aff74fb06e78fb9cd1a66acafb6d150638de35.tar.gz rust-34aff74fb06e78fb9cd1a66acafb6d150638de35.zip | |
Auto merge of #18183 - lnicola:sync-from-rust, r=lnicola
internal: Sync from downstream
Diffstat (limited to 'library/alloc/src')
36 files changed, 1051 insertions, 248 deletions
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index db2d752cfde..a91659b6de5 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -89,6 +89,7 @@ pub use std::alloc::Global; #[stable(feature = "global_alloc", since = "1.28.0")] #[must_use = "losing the pointer will leak memory"] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn alloc(layout: Layout) -> *mut u8 { unsafe { // Make sure we don't accidentally allow omitting the allocator shim in @@ -113,6 +114,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// See [`GlobalAlloc::dealloc`]. #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } } @@ -132,6 +134,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { #[stable(feature = "global_alloc", since = "1.28.0")] #[must_use = "losing the pointer will leak memory"] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } } @@ -166,13 +169,21 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 #[stable(feature = "global_alloc", since = "1.28.0")] #[must_use = "losing the pointer will leak memory"] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { - unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } + unsafe { + // Make sure we don't accidentally allow omitting the allocator shim in + // stable code until it is actually stabilized. + core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); + + __rust_alloc_zeroed(layout.size(), layout.align()) + } } #[cfg(not(test))] impl Global { #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), @@ -187,6 +198,7 @@ impl Global { // SAFETY: Same as `Allocator::grow` #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn grow_impl( &self, ptr: NonNull<u8>, @@ -237,16 +249,19 @@ impl Global { #[cfg(not(test))] unsafe impl Allocator for Global { #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { self.alloc_impl(layout, false) } #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { self.alloc_impl(layout, true) } #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, @@ -256,6 +271,7 @@ unsafe impl Allocator for Global { } #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn grow( &self, ptr: NonNull<u8>, @@ -267,6 +283,7 @@ unsafe impl Allocator for Global { } #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, @@ -278,6 +295,7 @@ unsafe impl Allocator for Global { } #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn shrink( &self, ptr: NonNull<u8>, @@ -325,6 +343,7 @@ unsafe impl Allocator for Global { #[cfg(all(not(no_global_oom_handling), not(test)))] #[lang = "exchange_malloc"] #[inline] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.allocate(layout) { @@ -372,6 +391,7 @@ extern "Rust" { #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] #[cold] +#[optimize(size)] pub const fn handle_alloc_error(layout: Layout) -> ! { const fn ct_error(_: Layout) -> ! { panic!("allocation failed"); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 38b1766c174..f61a484499f 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -53,22 +53,20 @@ //! //! # Memory layout //! -//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for -//! its allocation. It is valid to convert both ways between a [`Box`] and a -//! raw pointer allocated with the [`Global`] allocator, given that the -//! [`Layout`] used with the allocator is correct for the type. More precisely, -//! a `value: *mut T` that has been allocated with the [`Global`] allocator -//! with `Layout::for_value(&*value)` may be converted into a box using -//! [`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut -//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the -//! [`Global`] allocator with [`Layout::for_value(&*value)`]. +//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for its allocation. It is +//! valid to convert both ways between a [`Box`] and a raw pointer allocated with the [`Global`] +//! allocator, given that the [`Layout`] used with the allocator is correct for the type and the raw +//! pointer points to a valid value of the right type. More precisely, a `value: *mut T` that has +//! been allocated with the [`Global`] allocator with `Layout::for_value(&*value)` may be converted +//! into a box using [`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut T` +//! obtained from [`Box::<T>::into_raw`] may be deallocated using the [`Global`] allocator with +//! [`Layout::for_value(&*value)`]. //! -//! For zero-sized values, the `Box` pointer still has to be [valid] for reads -//! and writes and sufficiently aligned. In particular, casting any aligned -//! non-zero integer literal to a raw pointer produces a valid pointer, but a -//! pointer pointing into previously allocated memory that since got freed is -//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot -//! be used is to use [`ptr::NonNull::dangling`]. +//! For zero-sized values, the `Box` pointer has to be non-null and sufficiently aligned. The +//! recommended way to build a Box to a ZST if `Box::new` cannot be used is to use +//! [`ptr::NonNull::dangling`]. +//! +//! On top of these basic layout requirements, a `Box<T>` must point to a valid value of `T`. //! //! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented //! as a single pointer and is also ABI-compatible with C pointers @@ -201,7 +199,7 @@ use core::ops::{ DerefPure, DispatchFromDyn, Receiver, }; use core::pin::{Pin, PinCoerceUnsized}; -use core::ptr::{self, addr_of_mut, NonNull, Unique}; +use core::ptr::{self, NonNull, Unique, addr_of_mut}; use core::task::{Context, Poll}; use core::{borrow, fmt, slice}; @@ -252,6 +250,7 @@ impl<T> Box<T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[rustc_diagnostic_item = "box_new"] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn new(x: T) -> Self { #[rustc_box] Box::new(x) @@ -274,7 +273,7 @@ impl<T> Box<T> { /// assert_eq!(*five, 5) /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] #[inline] pub fn new_uninit() -> Box<mem::MaybeUninit<T>> { @@ -665,7 +664,7 @@ impl<T> Box<[T]> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { unsafe { RawVec::with_capacity(len).into_box(len) } @@ -932,7 +931,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { /// /// assert_eq!(*five, 5) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[inline] pub unsafe fn assume_init(self) -> Box<T, A> { let (raw, alloc) = Box::into_raw_with_allocator(self); @@ -1005,7 +1004,7 @@ impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> { /// /// assert_eq!(*values, [1, 2, 3]) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[inline] pub unsafe fn assume_init(self) -> Box<[T], A> { let (raw, alloc) = Box::into_raw_with_allocator(self); @@ -1061,6 +1060,59 @@ impl<T: ?Sized> Box<T> { pub unsafe fn from_raw(raw: *mut T) -> Self { unsafe { Self::from_raw_in(raw, Global) } } + + /// Constructs a box from a `NonNull` pointer. + /// + /// After calling this function, the `NonNull` pointer is owned by + /// the resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same `NonNull` pointer. + /// + /// The safety conditions are described in the [memory layout] section. + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a `NonNull` + /// pointer using [`Box::into_non_null`]: + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// let x = Box::new(5); + /// let non_null = Box::into_non_null(x); + /// let x = unsafe { Box::from_non_null(non_null) }; + /// ``` + /// Manually create a `Box` from scratch by using the global allocator: + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// use std::alloc::{alloc, Layout}; + /// use std::ptr::NonNull; + /// + /// unsafe { + /// let non_null = NonNull::new(alloc(Layout::new::<i32>()).cast::<i32>()) + /// .expect("allocation failed"); + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `non_null`. + /// non_null.write(5); + /// let x = Box::from_non_null(non_null); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + /// [`Layout`]: crate::Layout + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + #[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"] + pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self { + unsafe { Self::from_raw(ptr.as_ptr()) } + } } impl<T: ?Sized, A: Allocator> Box<T, A> { @@ -1118,6 +1170,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { Box(unsafe { Unique::new_unchecked(raw) }, alloc) } + /// Constructs a box from a `NonNull` pointer in the given allocator. + /// + /// After calling this function, the `NonNull` pointer is owned by + /// the resulting `Box`. Specifically, the `Box` destructor will call + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . + /// + /// # Safety + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// + /// # Examples + /// + /// Recreate a `Box` which was previously converted to a `NonNull` pointer + /// using [`Box::into_non_null_with_allocator`]: + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(5, System); + /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); + /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; + /// ``` + /// Manually create a `Box` from scratch by using the system allocator: + /// ``` + /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// unsafe { + /// let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>(); + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `non_null`. + /// non_null.write(5); + /// let x = Box::from_non_null_in(non_null, System); + /// } + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [memory layout]: self#memory-layout + /// [`Layout`]: crate::Layout + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[rustc_const_unstable(feature = "const_box", issue = "92521")] + #[inline] + pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self { + // SAFETY: guaranteed by the caller. + unsafe { Box::from_raw_in(raw.as_ptr(), alloc) } + } + /// Consumes the `Box`, returning a wrapped raw pointer. /// /// The pointer will be properly aligned and non-null. @@ -1173,6 +1280,66 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) } } + /// Consumes the `Box`, returning a wrapped `NonNull` pointer. + /// + /// The pointer will be properly aligned. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Box`. In particular, the + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the `NonNull` pointer back into a `Box` with the + /// [`Box::from_non_null`] function, allowing the `Box` destructor to + /// perform the cleanup. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_non_null(b)` instead of `b.into_non_null()`. + /// This is so that there is no conflict with a method on the inner type. + /// + /// # Examples + /// Converting the `NonNull` pointer back into a `Box` with [`Box::from_non_null`] + /// for automatic cleanup: + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// let x = Box::new(String::from("Hello")); + /// let non_null = Box::into_non_null(x); + /// let x = unsafe { Box::from_non_null(non_null) }; + /// ``` + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// use std::alloc::{dealloc, Layout}; + /// + /// let x = Box::new(String::from("Hello")); + /// let non_null = Box::into_non_null(x); + /// unsafe { + /// non_null.drop_in_place(); + /// dealloc(non_null.as_ptr().cast::<u8>(), Layout::new::<String>()); + /// } + /// ``` + /// Note: This is equivalent to the following: + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// let x = Box::new(String::from("Hello")); + /// let non_null = Box::into_non_null(x); + /// unsafe { + /// drop(Box::from_non_null(non_null)); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + pub fn into_non_null(b: Self) -> NonNull<T> { + // SAFETY: `Box` is guaranteed to be non-null. + unsafe { NonNull::new_unchecked(Self::into_raw(b)) } + } + /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. /// /// The pointer will be properly aligned and non-null. @@ -1234,6 +1401,61 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { (ptr, alloc) } + /// Consumes the `Box`, returning a wrapped `NonNull` pointer and the allocator. + /// + /// The pointer will be properly aligned. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Box`. In particular, the + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the `NonNull` pointer back into a `Box` with the + /// [`Box::from_non_null_in`] function, allowing the `Box` destructor to + /// perform the cleanup. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `Box::into_non_null_with_allocator(b)` instead of + /// `b.into_non_null_with_allocator()`. This is so that there is no + /// conflict with a method on the inner type. + /// + /// # Examples + /// Converting the `NonNull` pointer back into a `Box` with + /// [`Box::from_non_null_in`] for automatic cleanup: + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// let x = Box::new_in(String::from("Hello"), System); + /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); + /// let x = unsafe { Box::from_non_null_in(non_null, alloc) }; + /// ``` + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::{Allocator, Layout, System}; + /// + /// let x = Box::new_in(String::from("Hello"), System); + /// let (non_null, alloc) = Box::into_non_null_with_allocator(x); + /// unsafe { + /// non_null.drop_in_place(); + /// alloc.deallocate(non_null.cast::<u8>(), Layout::new::<String>()); + /// } + /// ``` + /// + /// [memory layout]: self#memory-layout + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + pub fn into_non_null_with_allocator(b: Self) -> (NonNull<T>, A) { + let (ptr, alloc) = Box::into_raw_with_allocator(b); + // SAFETY: `Box` is guaranteed to be non-null. + unsafe { (NonNull::new_unchecked(ptr), alloc) } + } + #[unstable( feature = "ptr_internals", issue = "none", @@ -2258,7 +2480,10 @@ impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args> #[unstable(feature = "async_fn_traits", issue = "none")] impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> for Box<F, A> { - type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> { F::async_call_mut(self, args) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 88701370c10..5e59abf54ee 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -145,7 +145,7 @@ use core::alloc::Allocator; use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen}; -use core::mem::{self, swap, ManuallyDrop}; +use core::mem::{self, ManuallyDrop, swap}; use core::num::NonZero; use core::ops::{Deref, DerefMut}; use core::{fmt, ptr}; @@ -959,6 +959,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "binaryheap_iter")] pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.data.iter() } } @@ -1433,7 +1434,7 @@ pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, } -#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "default_iters_sequel", since = "1.82.0")] impl<T> Default for Iter<'_, T> { /// Creates an empty `binary_heap::Iter`. /// diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs index 1cb07c62149..c18318724a4 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/src/collections/binary_heap/tests.rs @@ -1,4 +1,4 @@ -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use super::*; use crate::boxed::Box; diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs index 4c1e19ead40..95fb52b7f77 100644 --- a/library/alloc/src/collections/btree/fix.rs +++ b/library/alloc/src/collections/btree/fix.rs @@ -3,7 +3,7 @@ use core::alloc::Allocator; use super::map::MIN_LEN; use super::node::ForceResult::*; use super::node::LeftOrRight::*; -use super::node::{marker, Handle, NodeRef, Root}; +use super::node::{Handle, NodeRef, Root, marker}; impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> { /// Stocks up a possibly underfull node by merging with or stealing from a diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index f6f773cc42a..55649d865fc 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -13,7 +13,7 @@ use super::borrow::DormantMutRef; use super::dedup_sorted_iter::DedupSortedIter; use super::navigate::{LazyLeafRange, LeafRange}; use super::node::ForceResult::*; -use super::node::{self, marker, Handle, NodeRef, Root}; +use super::node::{self, Handle, NodeRef, Root, marker}; use super::search::SearchBound; use super::search::SearchResult::*; use super::set_val::SetValZST; @@ -22,9 +22,9 @@ use crate::vec::Vec; mod entry; +use Entry::*; #[stable(feature = "rust1", since = "1.0.0")] pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry}; -use Entry::*; /// Minimum number of elements in a node that is not a root. /// We might temporarily have fewer elements during methods. @@ -916,6 +916,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// assert_eq!(map.contains_key(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "btreemap_contains_key")] pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool where K: Borrow<Q> + Ord, @@ -981,6 +982,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push", "put", "set")] + #[cfg_attr(not(test), rustc_diagnostic_item = "btreemap_insert")] pub fn insert(&mut self, key: K, value: V) -> Option<V> where K: Ord, @@ -2016,7 +2018,7 @@ impl<K, V> Default for Range<'_, K, V> { } } -#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "default_iters_sequel", since = "1.82.0")] impl<K, V> Default for RangeMut<'_, K, V> { /// Creates an empty `btree_map::RangeMut`. /// @@ -2064,7 +2066,7 @@ impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl<K, V> FusedIterator for ValuesMut<'_, K, V> {} -#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "default_iters_sequel", since = "1.82.0")] impl<K, V> Default for ValuesMut<'_, K, V> { /// Creates an empty `btree_map::ValuesMut`. /// @@ -3302,7 +3304,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { Some(kv) } - /// Removes the precending element from the `BTreeMap`. + /// Removes the preceding element from the `BTreeMap`. /// /// The element that was removed is returned. The cursor position is /// unchanged (after the removed element). @@ -3408,7 +3410,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { self.inner.remove_next() } - /// Removes the precending element from the `BTreeMap`. + /// Removes the preceding element from the `BTreeMap`. /// /// The element that was removed is returned. The cursor position is /// unchanged (after the removed element). diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index d128ad8ee5f..75bb86916a8 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -5,7 +5,7 @@ use core::mem; use Entry::*; use super::super::borrow::DormantMutRef; -use super::super::node::{marker, Handle, NodeRef}; +use super::super::node::{Handle, NodeRef, marker}; use super::BTreeMap; use crate::alloc::{Allocator, Global}; diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index ff1254a5a0c..d0e413778f8 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,7 +1,7 @@ use core::assert_matches::assert_matches; use std::iter; use std::ops::Bound::{Excluded, Included, Unbounded}; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index f5c621e2c17..14b7d4ad71f 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -3,7 +3,7 @@ use core::ops::RangeBounds; use core::{hint, ptr}; use super::node::ForceResult::*; -use super::node::{marker, Handle, NodeRef}; +use super::node::{Handle, NodeRef, marker}; use super::search::SearchBound; use crate::alloc::Allocator; // `front` and `back` are always both `None` or both `Some`. diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index d230749d712..4d2fa0f0941 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -90,7 +90,7 @@ fn test_partial_eq() { #[test] #[cfg(target_arch = "x86_64")] -#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization +#[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization fn test_sizes() { assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16); assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8); diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index c46422c2f1d..56f2824b782 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -3,7 +3,7 @@ use core::alloc::Allocator; use super::map::MIN_LEN; use super::node::ForceResult::*; use super::node::LeftOrRight::*; -use super::node::{marker, Handle, NodeRef}; +use super::node::{Handle, NodeRef, marker}; impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key-value pair from the tree, and returns that pair, as well as diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 1d5c927175e..22e015edac3 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -6,7 +6,7 @@ use SearchBound::*; use SearchResult::*; use super::node::ForceResult::*; -use super::node::{marker, Handle, NodeRef}; +use super::node::{Handle, NodeRef, marker}; pub enum SearchBound<T> { /// An inclusive bound to look for, just like `Bound::Included(T)`. diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 973e7c66067..a40209fa2e3 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -7,10 +7,10 @@ use core::iter::{FusedIterator, Peekable}; use core::mem::ManuallyDrop; use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub}; +use super::Recover; use super::map::{BTreeMap, Keys}; use super::merge_iter::MergeIterInner; use super::set_val::SetValZST; -use super::Recover; use crate::alloc::{Allocator, Global}; use crate::vec::Vec; @@ -1132,6 +1132,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// assert_eq!(set_iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "btreeset_iter")] pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.map.keys() } } @@ -2298,7 +2299,7 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { self.inner.remove_next().map(|(k, _)| k) } - /// Removes the precending element from the `BTreeSet`. + /// Removes the preceding element from the `BTreeSet`. /// /// The element that was removed is returned. The cursor position is /// unchanged (after the removed element). @@ -2384,7 +2385,7 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMutKey<'a, T, A> { self.inner.remove_next().map(|(k, _)| k) } - /// Removes the precending element from the `BTreeSet`. + /// Removes the preceding element from the `BTreeSet`. /// /// The element that was removed is returned. The cursor position is /// unchanged (after the removed element). diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index f947b6108c9..990044e069f 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,5 +1,5 @@ use std::ops::Bound::{Excluded, Included}; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use super::*; use crate::testing::crash_test::{CrashTestDummy, Panic}; @@ -132,11 +132,9 @@ fn test_difference() { check_difference(&[1, 3, 5, 9, 11], &[3, 6, 9], &[1, 5, 11]); check_difference(&[1, 3, 5, 9, 11], &[0, 1], &[3, 5, 9, 11]); check_difference(&[1, 3, 5, 9, 11], &[11, 12], &[1, 3, 5, 9]); - check_difference( - &[-5, 11, 22, 33, 40, 42], - &[-12, -5, 14, 23, 34, 38, 39, 50], - &[11, 22, 33, 40, 42], - ); + check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[ + 11, 22, 33, 40, 42, + ]); if cfg!(miri) { // Miri is too slow @@ -252,11 +250,9 @@ fn test_union() { check_union(&[], &[], &[]); check_union(&[1, 2, 3], &[2], &[1, 2, 3]); check_union(&[2], &[1, 2, 3], &[1, 2, 3]); - check_union( - &[1, 3, 5, 9, 11, 16, 19, 24], - &[-2, 1, 5, 9, 13, 19], - &[-2, 1, 3, 5, 9, 11, 13, 16, 19, 24], - ); + check_union(&[1, 3, 5, 9, 11, 16, 19, 24], &[-2, 1, 5, 9, 13, 19], &[ + -2, 1, 3, 5, 9, 11, 13, 16, 19, 24, + ]); } #[test] diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 9b3c9ac5ce5..b7d4f8512a0 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1,4 +1,7 @@ -use std::panic::{catch_unwind, AssertUnwindSafe}; +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::thread; use rand::RngCore; @@ -693,10 +696,9 @@ fn test_cursor_mut_insert() { cursor.splice_after(p); cursor.splice_before(q); check_links(&m); - assert_eq!( - m.iter().cloned().collect::<Vec<_>>(), - &[200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6] - ); + assert_eq!(m.iter().cloned().collect::<Vec<_>>(), &[ + 200, 201, 202, 203, 1, 100, 101, 102, 103, 8, 2, 3, 4, 5, 6 + ]); let mut cursor = m.cursor_front_mut(); cursor.move_prev(); let tmp = cursor.split_before(); @@ -913,10 +915,9 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 14); - assert_eq!( - list.into_iter().collect::<Vec<_>>(), - vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39] - ); + assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![ + 1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39 + ]); } { @@ -931,10 +932,9 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 13); - assert_eq!( - list.into_iter().collect::<Vec<_>>(), - vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39] - ); + assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![ + 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39 + ]); } { @@ -949,10 +949,9 @@ fn extract_if_complex() { assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); assert_eq!(list.len(), 11); - assert_eq!( - list.into_iter().collect::<Vec<_>>(), - vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35] - ); + assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![ + 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35 + ]); } { diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 7be3de16b2d..2b09a5e7ddc 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -121,8 +121,6 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { { match self.try_fold(init, |b, item| Ok::<B, !>(f(b, item))) { Ok(b) => b, - #[cfg(bootstrap)] - Err(e) => match e {}, } } @@ -243,8 +241,6 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { { match self.try_rfold(init, |b, item| Ok::<B, !>(f(b, item))) { Ok(b) => b, - #[cfg(bootstrap)] - Err(e) => match e {}, } } } diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 67b5b91c4d4..6922ea9b79b 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -28,7 +28,7 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> { } } -#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "default_iters_sequel", since = "1.82.0")] impl<T> Default for Iter<'_, T> { /// Creates an empty `vec_deque::Iter`. /// @@ -73,7 +73,7 @@ impl<'a, T> Iterator for Iter<'a, T> { fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { let remaining = self.i1.advance_by(n); match remaining { - Ok(()) => return Ok(()), + Ok(()) => Ok(()), Err(n) => { mem::swap(&mut self.i1, &mut self.i2); self.i1.advance_by(n.get()) @@ -144,7 +144,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { match self.i2.advance_back_by(n) { - Ok(()) => return Ok(()), + Ok(()) => Ok(()), Err(n) => { mem::swap(&mut self.i1, &mut self.i2); self.i2.advance_back_by(n.get()) diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 2726e3e4252..84b74109580 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -28,7 +28,7 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> { } } -#[stable(feature = "default_iters_sequel", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "default_iters_sequel", since = "1.82.0")] impl<T> Default for IterMut<'_, T> { /// Creates an empty `vec_deque::IterMut`. /// @@ -64,7 +64,7 @@ impl<'a, T> Iterator for IterMut<'a, T> { fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { match self.i1.advance_by(n) { - Ok(()) => return Ok(()), + Ok(()) => Ok(()), Err(remaining) => { mem::swap(&mut self.i1, &mut self.i2); self.i1.advance_by(remaining.get()) @@ -135,7 +135,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { match self.i2.advance_back_by(n) { - Ok(()) => return Ok(()), + Ok(()) => Ok(()), Err(remaining) => { mem::swap(&mut self.i1, &mut self.i2); self.i2.advance_back_by(remaining.get()) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index dc725ec0f56..b1759a486ac 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -9,7 +9,7 @@ use core::cmp::{self, Ordering}; use core::hash::{Hash, Hasher}; -use core::iter::{repeat_n, repeat_with, ByRefSized}; +use core::iter::{ByRefSized, repeat_n, repeat_with}; // This is used in a bunch of intra-doc links. // FIXME: For some reason, `#[cfg(doc)]` wasn't sufficient, resulting in // failures in linkchecker even though rustdoc built the docs just fine. @@ -554,8 +554,8 @@ impl<T> VecDeque<T> { #[rustc_const_stable(feature = "const_vec_deque_new", since = "1.68.0")] #[must_use] pub const fn new() -> VecDeque<T> { - // FIXME: This should just be `VecDeque::new_in(Global)` once that hits stable. - VecDeque { head: 0, len: 0, buf: RawVec::NEW } + // FIXME(const-hack): This should just be `VecDeque::new_in(Global)` once that hits stable. + VecDeque { head: 0, len: 0, buf: RawVec::new() } } /// Creates an empty deque with space for at least `capacity` elements. @@ -1201,6 +1201,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert_eq!(&c[..], b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_iter")] pub fn iter(&self) -> Iter<'_, T> { let (a, b) = self.as_slices(); Iter::new(a.iter(), b.iter()) diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index f8ce4ca9788..6328b3b4db8 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -1,3 +1,6 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use core::iter::TrustedLen; use super::*; @@ -559,10 +562,9 @@ fn make_contiguous_head_to_end() { tester.push_front(i as char); } - assert_eq!( - tester, - ['P', 'O', 'N', 'M', 'L', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'] - ); + assert_eq!(tester, [ + 'P', 'O', 'N', 'M', 'L', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' + ]); // ABCDEFGHIJKPONML let expected_start = 0; diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index e32676a6543..797d591a8b5 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -4,7 +4,7 @@ mod tests; use core::borrow::Borrow; -use core::ffi::{c_char, CStr}; +use core::ffi::{CStr, c_char}; use core::num::NonZero; use core::slice::memchr; use core::str::{self, Utf8Error}; @@ -576,6 +576,7 @@ impl CString { #[inline] #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")] pub fn as_c_str(&self) -> &CStr { &*self } diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 571fcd177aa..3da71038a5e 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -580,10 +580,8 @@ pub use core::fmt::Alignment; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; -#[unstable(feature = "debug_closure_helpers", issue = "117729")] -pub use core::fmt::{from_fn, FromFn}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{write, Arguments}; +pub use core::fmt::{Arguments, write}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] @@ -592,6 +590,8 @@ pub use core::fmt::{Debug, Display}; pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Formatter, Result, Write}; +#[unstable(feature = "debug_closure_helpers", issue = "117729")] +pub use core::fmt::{FromFn, from_fn}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{LowerExp, UpperExp}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index c459a8da820..ff5ddd16e07 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -93,6 +93,7 @@ // tidy-alphabetical-start #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))] +#![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] @@ -110,11 +111,9 @@ #![feature(const_cow_is_borrowed)] #![feature(const_eval_select)] #![feature(const_heap)] -#![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_write)] #![feature(const_option)] #![feature(const_pin)] -#![feature(const_refs_to_cell)] #![feature(const_size_of_val)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] @@ -164,13 +163,14 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_mut_refs))] +#![cfg_attr(bootstrap, feature(const_refs_to_cell))] #![cfg_attr(not(test), feature(coroutine_trait))] #![cfg_attr(test, feature(panic_update_hook))] #![cfg_attr(test, feature(test))] #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] -#![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_ptr_write)] #![feature(const_try)] @@ -183,6 +183,7 @@ #![feature(multiple_supertrait_upcastable)] #![feature(negative_impls)] #![feature(never_type)] +#![feature(optimize_attribute)] #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] #![feature(slice_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 9c8fa7ceff4..436e0596e3d 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -96,13 +96,6 @@ struct RawVecInner<A: Allocator = Global> { } impl<T> RawVec<T, Global> { - /// HACK(Centril): This exists because stable `const fn` can only call stable `const fn`, so - /// they cannot call `Self::new()`. - /// - /// If you change `RawVec<T>::new` or dependencies, please take care to not introduce anything - /// that would truly const-call something unstable. - pub const NEW: Self = Self::new(); - /// Creates the biggest possible `RawVec` (on the system heap) /// without allocating. If `T` has positive size, then this makes a /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a @@ -111,7 +104,7 @@ impl<T> RawVec<T, Global> { #[must_use] #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] pub const fn new() -> Self { - Self { inner: RawVecInner::new::<T>(), _marker: PhantomData } + Self::new_in(Global) } /// Creates a `RawVec` (on the system heap) with exactly the @@ -149,12 +142,6 @@ impl<T> RawVec<T, Global> { } impl RawVecInner<Global> { - #[must_use] - #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")] - const fn new<T>() -> Self { - Self::new_in(Global, core::mem::align_of::<T>()) - } - #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] #[inline] @@ -782,6 +769,7 @@ where // Central function for reserve error handling. #[cfg(not(no_global_oom_handling))] #[cold] +#[optimize(size)] fn handle_error(e: TryReserveError) -> ! { match e.kind() { CapacityOverflow => capacity_overflow(), diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1b31a78394e..54669bd310a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -251,13 +251,13 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw, ManuallyDrop}; +use core::mem::{self, ManuallyDrop, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; use core::pin::PinCoerceUnsized; -use core::ptr::{self, drop_in_place, NonNull}; +use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; @@ -460,42 +460,7 @@ impl<T> Rc<T> { where F: FnOnce(&Weak<T>) -> T, { - // Construct the inner in the "uninitialized" state with a single - // weak reference. - let uninit_ptr: NonNull<_> = Box::leak(Box::new(RcBox { - strong: Cell::new(0), - weak: Cell::new(1), - value: mem::MaybeUninit::<T>::uninit(), - })) - .into(); - - let init_ptr: NonNull<RcBox<T>> = uninit_ptr.cast(); - - let weak = Weak { ptr: init_ptr, alloc: Global }; - - // It's important we don't give up ownership of the weak pointer, or - // else the memory might be freed by the time `data_fn` returns. If - // we really wanted to pass ownership, we could create an additional - // weak pointer for ourselves, but this would result in additional - // updates to the weak reference count which might not be necessary - // otherwise. - let data = data_fn(&weak); - - let strong = unsafe { - let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).value), data); - - let prev_value = (*inner).strong.get(); - debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); - (*inner).strong.set(1); - - Rc::from_inner(init_ptr) - }; - - // Strong references should collectively own a shared weak reference, - // so don't run the destructor for our old weak reference. - mem::forget(weak); - strong + Self::new_cyclic_in(data_fn, Global) } /// Constructs a new `Rc` with uninitialized contents. @@ -517,7 +482,7 @@ impl<T> Rc<T> { /// assert_eq!(*five, 5) /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> { unsafe { @@ -762,6 +727,84 @@ impl<T, A: Allocator> Rc<T, A> { } } + /// Constructs a new `Rc<T, A>` in the given allocator while giving you a `Weak<T, A>` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc<T, A>` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic_in` first allocates the managed allocation for the `Rc<T, A>`, + /// then calls your closure, giving it a `Weak<T, A>` to this allocation, + /// and only afterwards completes the construction of the `Rc<T, A>` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Rc<T, A>` is not fully-constructed until `Rc<T, A>::new_cyclic_in` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak<T, A>`] is dropped normally. + /// + /// # Examples + /// + /// See [`new_cyclic`]. + /// + /// [`new_cyclic`]: Rc::new_cyclic + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_cyclic_in<F>(data_fn: F, alloc: A) -> Rc<T, A> + where + F: FnOnce(&Weak<T, A>) -> T, + { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( + RcBox { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::<T>::uninit(), + }, + alloc, + )); + let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); + let init_ptr: NonNull<RcBox<T>> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr, alloc: alloc }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + let strong = unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(ptr::addr_of_mut!((*inner).value), data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + // Calling into_raw_with_allocator has the double effect of giving us back the allocator, + // and forgetting the weak reference. + let alloc = weak.into_raw_with_allocator().1; + + Rc::from_inner_in(init_ptr, alloc) + }; + + strong + } + /// Constructs a new `Rc<T>` in the provided allocator, returning an error if the allocation /// fails /// @@ -980,7 +1023,7 @@ impl<T> Rc<[T]> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> { unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } @@ -1127,7 +1170,7 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> { /// /// assert_eq!(*five, 5) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[inline] pub unsafe fn assume_init(self) -> Rc<T, A> { let (ptr, alloc) = Rc::into_inner_with_allocator(self); @@ -1167,7 +1210,7 @@ impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> { /// /// assert_eq!(*values, [1, 2, 3]) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[inline] pub unsafe fn assume_init(self) -> Rc<[T], A> { let (ptr, alloc) = Rc::into_inner_with_allocator(self); diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 84e8b325f71..333e1bde31c 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -448,7 +448,11 @@ fn test_from_box_str() { use std::string::String; let s = String::from("foo").into_boxed_str(); + assert_eq!((&&&s).as_str(), "foo"); + let r: Rc<str> = Rc::from(s); + assert_eq!((&r).as_str(), "foo"); + assert_eq!(r.as_str(), "foo"); assert_eq!(&r[..], "foo"); } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 9d704870326..f636f10d5c0 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -43,14 +43,6 @@ pub use core::slice::ArrayWindows; pub use core::slice::EscapeAscii; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; -#[stable(feature = "from_ref", since = "1.28.0")] -pub use core::slice::{from_mut, from_ref}; -#[unstable(feature = "slice_from_ptr_range", issue = "89792")] -pub use core::slice::{from_mut_ptr_range, from_ptr_range}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::slice::{from_raw_parts, from_raw_parts_mut}; -#[unstable(feature = "slice_range", issue = "76393")] -pub use core::slice::{range, try_range}; #[stable(feature = "slice_group_by", since = "1.77.0")] pub use core::slice::{ChunkBy, ChunkByMut}; #[stable(feature = "rust1", since = "1.0.0")] @@ -69,6 +61,14 @@ pub use core::slice::{RSplit, RSplitMut}; pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use core::slice::{SplitInclusive, SplitInclusiveMut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use core::slice::{from_mut, from_ref}; +#[unstable(feature = "slice_from_ptr_range", issue = "89792")] +pub use core::slice::{from_mut_ptr_range, from_ptr_range}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::slice::{from_raw_parts, from_raw_parts_mut}; +#[unstable(feature = "slice_range", issue = "76393")] +pub use core::slice::{range, try_range}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods @@ -96,6 +96,7 @@ pub(crate) mod hack { // We shouldn't add inline attribute to this since this is used in // `vec!` macro mostly and causes perf regression. See #71204 for // discussion and perf results. + #[allow(missing_docs)] pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> { unsafe { let len = b.len(); @@ -105,6 +106,7 @@ pub(crate) mod hack { } #[cfg(not(no_global_oom_handling))] + #[allow(missing_docs)] #[inline] pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> { T::to_vec(s, alloc) @@ -494,6 +496,7 @@ impl<T> [T] { #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")] pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> { // N.B., see the `hack` module in this file for more details. hack::into_vec(self) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index d7fba3ae159..32212b61c6e 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -9,9 +9,6 @@ use core::borrow::{Borrow, BorrowMut}; use core::iter::FusedIterator; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::pattern; -use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] @@ -20,12 +17,11 @@ pub use core::str::SplitAsciiWhitespace; pub use core::str::SplitInclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::SplitWhitespace; -#[unstable(feature = "str_from_raw_parts", issue = "119206")] -pub use core::str::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8, from_utf8_mut, Bytes, CharIndices, Chars}; +pub use core::str::pattern; +use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; +pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut}; #[stable(feature = "str_escape", since = "1.34.0")] pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; #[stable(feature = "rust1", since = "1.0.0")] @@ -38,6 +34,8 @@ pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{ParseBoolError, from_utf8_unchecked, from_utf8_unchecked_mut}; +#[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplit, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; @@ -45,6 +43,8 @@ pub use core::str::{RSplitN, SplitN}; pub use core::str::{RSplitTerminator, SplitTerminator}; #[stable(feature = "utf8_chunks", since = "1.79.0")] pub use core::str::{Utf8Chunk, Utf8Chunks}; +#[unstable(feature = "str_from_raw_parts", issue = "119206")] +pub use core::str::{from_raw_parts, from_raw_parts_mut}; use core::unicode::conversions; use core::{mem, ptr}; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e628be1546f..ee878e879e9 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -43,9 +43,9 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::error::Error; +use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::iter::from_fn; -use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] @@ -62,9 +62,9 @@ use crate::alloc::Allocator; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, from_utf8_unchecked_mut, Chars, Utf8Error}; +use crate::str::{self, Chars, Utf8Error, from_utf8_unchecked_mut}; #[cfg(not(no_global_oom_handling))] -use crate::str::{from_boxed_utf8_unchecked, FromStr}; +use crate::str::{FromStr, from_boxed_utf8_unchecked}; use crate::vec::Vec; /// A UTF-8–encoded, growable string. @@ -440,6 +440,7 @@ impl String { /// ``` #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> String { @@ -508,6 +509,7 @@ impl String { // NB see the slice::hack module in slice.rs for more information #[inline] #[cfg(test)] + #[allow(missing_docs)] pub fn from_str(_: &str) -> String { panic!("not available with cfg(test)"); } @@ -570,6 +572,7 @@ impl String { /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")] pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> { match str::from_utf8(&vec) { Ok(..) => Ok(String { vec }), @@ -659,6 +662,56 @@ impl String { Cow::Owned(res) } + /// Converts a [`Vec<u8>`] to a `String`, substituting invalid UTF-8 + /// sequences with replacement characters. + /// + /// See [`from_utf8_lossy`] for more details. + /// + /// [`from_utf8_lossy`]: String::from_utf8_lossy + /// + /// Note that this function does not guarantee reuse of the original `Vec` + /// allocation. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(string_from_utf8_lossy_owned)] + /// // some bytes, in a vector + /// let sparkle_heart = vec![240, 159, 146, 150]; + /// + /// let sparkle_heart = String::from_utf8_lossy_owned(sparkle_heart); + /// + /// assert_eq!(String::from("💖"), sparkle_heart); + /// ``` + /// + /// Incorrect bytes: + /// + /// ``` + /// #![feature(string_from_utf8_lossy_owned)] + /// // some invalid bytes + /// let input: Vec<u8> = b"Hello \xF0\x90\x80World".into(); + /// let output = String::from_utf8_lossy_owned(input); + /// + /// assert_eq!(String::from("Hello �World"), output); + /// ``` + #[must_use] + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_from_utf8_lossy_owned", issue = "129436")] + pub fn from_utf8_lossy_owned(v: Vec<u8>) -> String { + if let Cow::Owned(string) = String::from_utf8_lossy(&v) { + string + } else { + // SAFETY: `String::from_utf8_lossy`'s contract ensures that if + // it returns a `Cow::Borrowed`, it is a valid UTF-8 string. + // Otherwise, it returns a new allocation of an owned `String`, with + // replacement characters for invalid sequences, which is returned + // above. + unsafe { String::from_utf8_unchecked(v) } + } + } + /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`] /// if `v` contains any invalid data. /// @@ -1022,6 +1075,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] pub fn as_str(&self) -> &str { self } @@ -1041,6 +1095,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] pub fn as_mut_str(&mut self) -> &mut str { self } @@ -1060,6 +1115,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")] pub fn push_str(&mut self, string: &str) { self.vec.extend_from_slice(string.as_bytes()) } @@ -1694,6 +1750,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "insert_str", since = "1.16.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -2009,6 +2066,54 @@ impl FromUtf8Error { &self.bytes[..] } + /// Converts the bytes into a `String` lossily, substituting invalid UTF-8 + /// sequences with replacement characters. + /// + /// See [`String::from_utf8_lossy`] for more details on replacement of + /// invalid sequences, and [`String::from_utf8_lossy_owned`] for the + /// `String` function which corresponds to this function. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_from_utf8_lossy_owned)] + /// // some invalid bytes + /// let input: Vec<u8> = b"Hello \xF0\x90\x80World".into(); + /// let output = String::from_utf8(input).unwrap_or_else(|e| e.into_utf8_lossy()); + /// + /// assert_eq!(String::from("Hello �World"), output); + /// ``` + #[must_use] + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_from_utf8_lossy_owned", issue = "129436")] + pub fn into_utf8_lossy(self) -> String { + const REPLACEMENT: &str = "\u{FFFD}"; + + let mut res = { + let mut v = Vec::with_capacity(self.bytes.len()); + + // `Utf8Error::valid_up_to` returns the maximum index of validated + // UTF-8 bytes. Copy the valid bytes into the output buffer. + v.extend_from_slice(&self.bytes[..self.error.valid_up_to()]); + + // SAFETY: This is safe because the only bytes present in the buffer + // were validated as UTF-8 by the call to `String::from_utf8` which + // produced this `FromUtf8Error`. + unsafe { String::from_utf8_unchecked(v) } + }; + + let iter = self.bytes[self.error.valid_up_to()..].utf8_chunks(); + + for chunk in iter { + res.push_str(chunk.valid()); + if !chunk.invalid().is_empty() { + res.push_str(REPLACEMENT); + } + } + + res + } + /// Returns the bytes that were attempted to convert to a `String`. /// /// This method is carefully constructed to avoid allocation. It will @@ -2313,7 +2418,7 @@ impl<'b> Pattern for &'b String { } #[inline] - fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str> + fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str> where Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>, { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 024a794f17b..50886244d58 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -17,7 +17,7 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -use core::mem::{self, align_of_val_raw, ManuallyDrop}; +use core::mem::{self, ManuallyDrop, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::{Pin, PinCoerceUnsized}; @@ -450,54 +450,7 @@ impl<T> Arc<T> { where F: FnOnce(&Weak<T>) -> T, { - // Construct the inner in the "uninitialized" state with a single - // weak reference. - let uninit_ptr: NonNull<_> = Box::leak(Box::new(ArcInner { - strong: atomic::AtomicUsize::new(0), - weak: atomic::AtomicUsize::new(1), - data: mem::MaybeUninit::<T>::uninit(), - })) - .into(); - let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast(); - - let weak = Weak { ptr: init_ptr, alloc: Global }; - - // It's important we don't give up ownership of the weak pointer, or - // else the memory might be freed by the time `data_fn` returns. If - // we really wanted to pass ownership, we could create an additional - // weak pointer for ourselves, but this would result in additional - // updates to the weak reference count which might not be necessary - // otherwise. - let data = data_fn(&weak); - - // Now we can properly initialize the inner value and turn our weak - // reference into a strong reference. - let strong = unsafe { - let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).data), data); - - // The above write to the data field must be visible to any threads which - // observe a non-zero strong count. Therefore we need at least "Release" ordering - // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`. - // - // "Acquire" ordering is not required. When considering the possible behaviours - // of `data_fn` we only need to look at what it could do with a reference to a - // non-upgradeable `Weak`: - // - It can *clone* the `Weak`, increasing the weak reference count. - // - It can drop those clones, decreasing the weak reference count (but never to zero). - // - // These side effects do not impact us in any way, and no other side effects are - // possible with safe code alone. - let prev_value = (*inner).strong.fetch_add(1, Release); - debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); - - Arc::from_inner(init_ptr) - }; - - // Strong references should collectively own a shared weak reference, - // so don't run the destructor for our old weak reference. - mem::forget(weak); - strong + Self::new_cyclic_in(data_fn, Global) } /// Constructs a new `Arc` with uninitialized contents. @@ -520,7 +473,7 @@ impl<T> Arc<T> { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> { unsafe { @@ -781,6 +734,98 @@ impl<T, A: Allocator> Arc<T, A> { } } + /// Constructs a new `Arc<T, A>` in the given allocator while giving you a `Weak<T, A>` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Arc<T, A>` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic_in` first allocates the managed allocation for the `Arc<T, A>`, + /// then calls your closure, giving it a `Weak<T, A>` to this allocation, + /// and only afterwards completes the construction of the `Arc<T, A>` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Arc<T, A>` is not fully-constructed until `Arc<T, A>::new_cyclic_in` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. + /// + /// # Panics + /// + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak<T>`] is dropped normally. + /// + /// # Example + /// + /// See [`new_cyclic`] + /// + /// [`new_cyclic`]: Arc::new_cyclic + /// [`upgrade`]: Weak::upgrade + #[cfg(not(no_global_oom_handling))] + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_cyclic_in<F>(data_fn: F, alloc: A) -> Arc<T, A> + where + F: FnOnce(&Weak<T, A>) -> T, + { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( + ArcInner { + strong: atomic::AtomicUsize::new(0), + weak: atomic::AtomicUsize::new(1), + data: mem::MaybeUninit::<T>::uninit(), + }, + alloc, + )); + let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); + let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr, alloc: alloc }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + // Now we can properly initialize the inner value and turn our weak + // reference into a strong reference. + let strong = unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(ptr::addr_of_mut!((*inner).data), data); + + // The above write to the data field must be visible to any threads which + // observe a non-zero strong count. Therefore we need at least "Release" ordering + // in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`. + // + // "Acquire" ordering is not required. When considering the possible behaviours + // of `data_fn` we only need to look at what it could do with a reference to a + // non-upgradeable `Weak`: + // - It can *clone* the `Weak`, increasing the weak reference count. + // - It can drop those clones, decreasing the weak reference count (but never to zero). + // + // These side effects do not impact us in any way, and no other side effects are + // possible with safe code alone. + let prev_value = (*inner).strong.fetch_add(1, Release); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + // Calling into_raw_with_allocator has the double effect of giving us back the allocator, + // and forgetting the weak reference. + let alloc = weak.into_raw_with_allocator().1; + + Arc::from_inner_in(init_ptr, alloc) + }; + + strong + } + /// Constructs a new `Pin<Arc<T, A>>` in the provided allocator. If `T` does not implement `Unpin`, /// then `data` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] @@ -1115,7 +1160,7 @@ impl<T> Arc<[T]> { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) } @@ -1262,7 +1307,7 @@ impl<T, A: Allocator> Arc<mem::MaybeUninit<T>, A> { /// /// assert_eq!(*five, 5) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc<T, A> { @@ -1303,7 +1348,7 @@ impl<T, A: Allocator> Arc<[mem::MaybeUninit<T>], A> { /// /// assert_eq!(*values, [1, 2, 3]) /// ``` - #[stable(feature = "new_uninit", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc<[T], A> { diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index d6b3de87577..3f66c889923 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -1,10 +1,10 @@ use std::clone::Clone; use std::mem::MaybeUninit; use std::option::Option::None; +use std::sync::Mutex; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::mpsc::channel; -use std::sync::Mutex; use std::thread; use super::*; diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index d119e6ca397..fd94bbbdeb1 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -163,7 +163,7 @@ use core::num::NonZero; use core::ptr; use super::{InPlaceDrop, InPlaceDstDataSrcBufDrop, SpecFromIter, SpecFromIterNested, Vec}; -use crate::alloc::{handle_alloc_error, Global}; +use crate::alloc::{Global, handle_alloc_error}; const fn in_place_collectible<DEST, SRC>( step_merge: Option<NonZero<usize>>, @@ -191,7 +191,7 @@ const fn in_place_collectible<DEST, SRC>( const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool { if const { mem::align_of::<SRC>() != mem::align_of::<DEST>() } { - // FIXME: use unreachable! once that works in const + // FIXME(const-hack): use unreachable! once that works in const panic!("in_place_collectible() prevents this"); } @@ -208,7 +208,7 @@ const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool { // type layouts don't guarantee a fit, so do a runtime check to see if // the allocations happen to match - return src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>(); + src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>() } /// This provides a shorthand for the source type since local type aliases aren't a thing. @@ -328,7 +328,7 @@ where mem::forget(dst_guard); - let vec = unsafe { Vec::from_nonnull(dst_buf, len, dst_cap) }; + let vec = unsafe { Vec::from_parts(dst_buf, len, dst_cap) }; vec } diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 27f75979310..4d5b4e47d39 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use core::ptr::{self, drop_in_place, NonNull}; +use core::ptr::{self, NonNull, drop_in_place}; use core::slice::{self}; use crate::alloc::Global; diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index fad8abad493..f7aad56695d 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -142,7 +142,7 @@ impl<T, A: Allocator> IntoIter<T, A> { // struct and then overwriting &mut self. // this creates less assembly self.cap = 0; - self.buf = RawVec::NEW.non_null(); + self.buf = RawVec::new().non_null(); self.ptr = self.buf; self.end = self.buf.as_ptr(); @@ -288,11 +288,11 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { // Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize // the array. - return unsafe { + unsafe { ptr::copy_nonoverlapping(self.ptr.as_ptr(), raw_ary.as_mut_ptr() as *mut T, N); self.ptr = self.ptr.add(N); Ok(raw_ary.transpose().assume_init()) - }; + } } fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index cfd2e4a1512..1984cfeefc1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -416,10 +416,11 @@ impl<T> Vec<T> { /// ``` #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> Self { - Vec { buf: RawVec::NEW, len: 0 } + Vec { buf: RawVec::new(), len: 0 } } /// Constructs a new, empty `Vec<T>` with at least the specified capacity. @@ -476,6 +477,7 @@ impl<T> Vec<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -603,15 +605,116 @@ impl<T> Vec<T> { unsafe { Self::from_raw_parts_in(ptr, length, capacity, Global) } } - /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts`]. + #[doc(alias = "from_non_null_parts")] + /// Creates a `Vec<T>` directly from a `NonNull` pointer, a length, and a capacity. /// /// # Safety /// - /// See [`Vec::from_raw_parts`]. + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` must have been allocated using the global allocator, such as via + /// the [`alloc::alloc`] function. + /// * `T` needs to have the same alignment as what `ptr` was allocated with. + /// (`T` having a less strict alignment is not sufficient, the alignment really + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be + /// allocated and deallocated with the same layout.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// to be the same size as the pointer was allocated with. (Because similar to + /// alignment, [`dealloc`] must be called with the same layout `size`.) + /// * `length` needs to be less than or equal to `capacity`. + /// * The first `length` values must be properly initialized values of type `T`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`]. + /// + /// These requirements are always upheld by any `ptr` that has been allocated + /// via `Vec<T>`. Other allocation sources are allowed if the invariants are + /// upheld. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is normally **not** safe + /// to build a `Vec<u8>` from a pointer to a C `char` array with length + /// `size_t`, doing so is only safe if the array was initially allocated by + /// a `Vec` or `String`. + /// It's also not safe to build one from a `Vec<u16>` and its length, because + /// the allocator cares about the alignment, and these two types have different + /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after + /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1. To avoid + /// these issues, it is often preferable to do casting/transmuting using + /// [`NonNull::slice_from_raw_parts`] instead. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec<T>` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: crate::string::String + /// [`alloc::alloc`]: crate::alloc::alloc + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc + /// + /// # Examples + /// + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// use std::ptr::NonNull; + /// use std::mem; + /// + /// let v = vec![1, 2, 3]; + /// + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); + /// + /// // Pull out the various important pieces of information about `v` + /// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) }; + /// let len = v.len(); + /// let cap = v.capacity(); + /// + /// unsafe { + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len { + /// p.add(i).write(4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_parts(p, len, cap); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } + /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// #![feature(box_vec_non_null)] + /// + /// use std::alloc::{alloc, Layout}; + /// use std::ptr::NonNull; + /// + /// fn main() { + /// let layout = Layout::array::<u32>(16).expect("overflow cannot happen"); + /// + /// let vec = unsafe { + /// let Some(mem) = NonNull::new(alloc(layout).cast::<u32>()) else { + /// return; + /// }; + /// + /// mem.write(1_000_000); + /// + /// Vec::from_parts(mem, 1, 16) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` #[inline] - #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling - pub(crate) unsafe fn from_nonnull(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { - unsafe { Self::from_nonnull_in(ptr, length, capacity, Global) } + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { + unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } } @@ -830,19 +933,119 @@ impl<T, A: Allocator> Vec<T, A> { unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } - /// A convenience method for hoisting the non-null precondition out of [`Vec::from_raw_parts_in`]. + #[doc(alias = "from_non_null_parts_in")] + /// Creates a `Vec<T, A>` directly from a `NonNull` pointer, a length, a capacity, + /// and an allocator. /// /// # Safety /// - /// See [`Vec::from_raw_parts_in`]. + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` must be [*currently allocated*] via the given allocator `alloc`. + /// * `T` needs to have the same alignment as what `ptr` was allocated with. + /// (`T` having a less strict alignment is not sufficient, the alignment really + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be + /// allocated and deallocated with the same layout.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// to be the same size as the pointer was allocated with. (Because similar to + /// alignment, [`dealloc`] must be called with the same layout `size`.) + /// * `length` needs to be less than or equal to `capacity`. + /// * The first `length` values must be properly initialized values of type `T`. + /// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`]. + /// + /// These requirements are always upheld by any `ptr` that has been allocated + /// via `Vec<T, A>`. Other allocation sources are allowed if the invariants are + /// upheld. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. For example it is **not** safe + /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`. + /// It's also not safe to build one from a `Vec<u16>` and its length, because + /// the allocator cares about the alignment, and these two types have different + /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after + /// turning it into a `Vec<u8>` it'll be deallocated with alignment 1. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec<T>` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// [`String`]: crate::string::String + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc + /// [*currently allocated*]: crate::alloc::Allocator#currently-allocated-memory + /// [*fit*]: crate::alloc::Allocator#memory-fitting + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// use std::ptr::NonNull; + /// use std::mem; + /// + /// let mut v = Vec::with_capacity_in(3, System); + /// v.push(1); + /// v.push(2); + /// v.push(3); + /// + // FIXME Update this when vec_into_raw_parts is stabilized + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); + /// + /// // Pull out the various important pieces of information about `v` + /// let p = unsafe { NonNull::new_unchecked(v.as_mut_ptr()) }; + /// let len = v.len(); + /// let cap = v.capacity(); + /// let alloc = v.allocator(); + /// + /// unsafe { + /// // Overwrite memory with 4, 5, 6 + /// for i in 0..len { + /// p.add(i).write(4 + i); + /// } + /// + /// // Put everything back together into a Vec + /// let rebuilt = Vec::from_parts_in(p, len, cap, alloc.clone()); + /// assert_eq!(rebuilt, [4, 5, 6]); + /// } + /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// #![feature(allocator_api, box_vec_non_null)] + /// + /// use std::alloc::{AllocError, Allocator, Global, Layout}; + /// + /// fn main() { + /// let layout = Layout::array::<u32>(16).expect("overflow cannot happen"); + /// + /// let vec = unsafe { + /// let mem = match Global.allocate(layout) { + /// Ok(mem) => mem.cast::<u32>(), + /// Err(AllocError) => return, + /// }; + /// + /// mem.write(1_000_000); + /// + /// Vec::from_parts_in(mem, 1, 16, Global) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` #[inline] - #[cfg(not(no_global_oom_handling))] // required by tests/run-make/alloc-no-oom-handling - pub(crate) unsafe fn from_nonnull_in( - ptr: NonNull<T>, - length: usize, - capacity: usize, - alloc: A, - ) -> Self { + #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", issue = "130364")] + pub unsafe fn from_parts_in(ptr: NonNull<T>, length: usize, capacity: usize, alloc: A) -> Self { unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } @@ -885,6 +1088,49 @@ impl<T, A: Allocator> Vec<T, A> { (me.as_mut_ptr(), me.len(), me.capacity()) } + #[doc(alias = "into_non_null_parts")] + /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`. + /// + /// Returns the `NonNull` pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the `NonNull` pointer, length, and capacity back + /// into a `Vec` with the [`from_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_parts`]: Vec::from_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts, box_vec_non_null)] + /// + /// let v: Vec<i32> = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr.cast::<u32>(); + /// + /// Vec::from_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_parts(self) -> (NonNull<T>, usize, usize) { + let (ptr, len, capacity) = self.into_raw_parts(); + // SAFETY: A `Vec` always has a non-null pointer. + (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) + } + /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity, allocator)`. /// /// Returns the raw pointer to the underlying data, the length of the vector (in elements), @@ -934,6 +1180,54 @@ impl<T, A: Allocator> Vec<T, A> { (ptr, len, capacity, alloc) } + #[doc(alias = "into_non_null_parts_with_alloc")] + /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity, allocator)`. + /// + /// Returns the `NonNull` pointer to the underlying data, the length of the vector (in elements), + /// the allocated capacity of the data (in elements), and the allocator. These are the same + /// arguments in the same order as the arguments to [`from_parts_in`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the `NonNull` pointer, length, and capacity back + /// into a `Vec` with the [`from_parts_in`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_parts_in`]: Vec::from_parts_in + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, vec_into_raw_parts, box_vec_non_null)] + /// + /// use std::alloc::System; + /// + /// let mut v: Vec<i32, System> = Vec::new_in(System); + /// v.push(-1); + /// v.push(0); + /// v.push(1); + /// + /// let (ptr, len, cap, alloc) = v.into_parts_with_alloc(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr.cast::<u32>(); + /// + /// Vec::from_parts_in(ptr, len, cap, alloc) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[must_use = "losing the pointer will leak memory"] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_parts_with_alloc(self) -> (NonNull<T>, usize, usize, A) { + let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc(); + // SAFETY: A `Vec` always has a non-null pointer. + (unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc) + } + /// Returns the total number of elements the vector can hold without /// reallocating. /// @@ -1253,6 +1547,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] pub fn as_slice(&self) -> &[T] { self } @@ -1270,6 +1565,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] pub fn as_mut_slice(&mut self) -> &mut [T] { self } @@ -1288,7 +1584,8 @@ impl<T, A: Allocator> Vec<T, A> { /// /// This method guarantees that for the purpose of the aliasing model, this method /// does not materialize a reference to the underlying slice, and thus the returned pointer - /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`]. + /// will remain valid when mixed with other calls to [`as_ptr`], [`as_mut_ptr`], + /// and [`as_non_null`]. /// Note that calling other methods that materialize mutable references to the slice, /// or mutable references to specific elements you are planning on accessing through this pointer, /// as well as writing to those elements, may still invalidate this pointer. @@ -1325,6 +1622,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr + /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_never_returns_null_ptr] #[inline] @@ -1344,7 +1642,8 @@ impl<T, A: Allocator> Vec<T, A> { /// /// This method guarantees that for the purpose of the aliasing model, this method /// does not materialize a reference to the underlying slice, and thus the returned pointer - /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`]. + /// will remain valid when mixed with other calls to [`as_ptr`], [`as_mut_ptr`], + /// and [`as_non_null`]. /// Note that calling other methods that materialize references to the slice, /// or references to specific elements you are planning on accessing through this pointer, /// may still invalidate this pointer. @@ -1384,6 +1683,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr + /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_never_returns_null_ptr] #[inline] @@ -1393,6 +1693,69 @@ impl<T, A: Allocator> Vec<T, A> { self.buf.ptr() } + /// Returns a `NonNull` pointer to the vector's buffer, or a dangling + /// `NonNull` pointer valid for zero sized reads if the vector didn't allocate. + /// + /// The caller must ensure that the vector outlives the pointer this + /// function returns, or else it will end up dangling. + /// Modifying the vector may cause its buffer to be reallocated, + /// which would also make any pointers to it invalid. + /// + /// This method guarantees that for the purpose of the aliasing model, this method + /// does not materialize a reference to the underlying slice, and thus the returned pointer + /// will remain valid when mixed with other calls to [`as_ptr`], [`as_mut_ptr`], + /// and [`as_non_null`]. + /// Note that calling other methods that materialize references to the slice, + /// or references to specific elements you are planning on accessing through this pointer, + /// may still invalidate this pointer. + /// See the second example below for how this guarantee can be used. + /// + /// # Examples + /// + /// ``` + /// #![feature(box_vec_non_null)] + /// + /// // Allocate vector big enough for 4 elements. + /// let size = 4; + /// let mut x: Vec<i32> = Vec::with_capacity(size); + /// let x_ptr = x.as_non_null(); + /// + /// // Initialize elements via raw pointer writes, then set length. + /// unsafe { + /// for i in 0..size { + /// x_ptr.add(i).write(i as i32); + /// } + /// x.set_len(size); + /// } + /// assert_eq!(&*x, &[0, 1, 2, 3]); + /// ``` + /// + /// Due to the aliasing guarantee, the following code is legal: + /// + /// ```rust + /// #![feature(box_vec_non_null)] + /// + /// unsafe { + /// let mut v = vec![0]; + /// let ptr1 = v.as_non_null(); + /// ptr1.write(1); + /// let ptr2 = v.as_non_null(); + /// ptr2.write(2); + /// // Notably, the write to `ptr2` did *not* invalidate `ptr1`: + /// ptr1.write(3); + /// } + /// ``` + /// + /// [`as_mut_ptr`]: Vec::as_mut_ptr + /// [`as_ptr`]: Vec::as_ptr + /// [`as_non_null`]: Vec::as_non_null + #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] + #[inline] + pub fn as_non_null(&mut self) -> NonNull<T> { + // SAFETY: A `Vec` always has a non-null pointer. + unsafe { NonNull::new_unchecked(self.as_mut_ptr()) } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] @@ -1519,6 +1882,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] + #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { panic!("swap_remove index (is {index}) should be < len (is {len})"); } @@ -1567,6 +1931,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] + #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { panic!("insertion index (is {index}) should be <= len (is {len})"); } @@ -1629,6 +1994,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] + #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { panic!("removal index (is {index}) should be < len (is {len})"); } @@ -2085,6 +2451,7 @@ impl<T, A: Allocator> Vec<T, A> { /// Takes *O*(1) time. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")] pub fn pop(&mut self) -> Option<T> { if self.len == 0 { None @@ -2278,6 +2645,7 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] pub fn is_empty(&self) -> bool { self.len() == 0 } @@ -2317,6 +2685,7 @@ impl<T, A: Allocator> Vec<T, A> { #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] + #[optimize(size)] fn assert_failed(at: usize, len: usize) -> ! { panic!("`at` split index (is {at}) should be <= len (is {len})"); } @@ -2748,6 +3117,7 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")] pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> { <T as SpecFromElem>::from_elem(elem, n, Global) } diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index 6646ae7bccb..e1f0b639bdf 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -51,7 +51,7 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> { if has_advanced { ptr::copy(it.ptr.as_ptr(), it.buf.as_ptr(), it.len()); } - return Vec::from_nonnull(it.buf, it.len(), it.cap); + return Vec::from_parts(it.buf, it.len(), it.cap); } } |
