diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 940fce7377938..5f1fd39bbbc3b 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -3991,7 +3991,7 @@ impl From> for VecDeque { /// any additional memory. #[inline] fn from(other: Vec) -> Self { - let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc(); + let (ptr, len, cap, alloc) = other.into_raw_parts_with_allocator(); Self { head: WrappedIndex::zero(), len, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e639a32370703..30e4e1aa504bf 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -342,9 +342,12 @@ impl !Send for Rc {} impl !Sync for Rc {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Rc {} +impl UnwindSafe for Rc {} #[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")] -impl RefUnwindSafe for Rc {} +impl RefUnwindSafe + for Rc +{ +} #[unstable(feature = "coerce_unsized", issue = "18598")] impl, U: ?Sized, A: Allocator> CoerceUnsized> for Rc {} @@ -3002,7 +3005,7 @@ impl From> for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Rc<[T], A> { +impl From> for Rc<[T], A> { /// Allocates a reference-counted slice and moves `v`'s items into it. /// /// # Example @@ -3016,7 +3019,7 @@ impl From> for Rc<[T], A> { #[inline] fn from(v: Vec) -> Rc<[T], A> { unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_allocator(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5ea0fd3a394d4..706eba3aab8e5 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -281,12 +281,15 @@ pub struct Arc< } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Arc {} +unsafe impl Send for Arc {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for Arc {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Arc {} +impl UnwindSafe + for Arc +{ +} #[unstable(feature = "coerce_unsized", issue = "18598")] impl, U: ?Sized, A: Allocator> CoerceUnsized> for Arc {} @@ -364,7 +367,7 @@ pub struct Weak< } #[stable(feature = "arc_weak", since = "1.4.0")] -unsafe impl Send for Weak {} +unsafe impl Send for Weak {} #[stable(feature = "arc_weak", since = "1.4.0")] unsafe impl Sync for Weak {} @@ -4083,7 +4086,7 @@ impl From> for Arc<[T], A> { #[inline] fn from(v: Vec) -> Arc<[T], A> { unsafe { - let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_allocator(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len); @@ -4423,7 +4426,7 @@ pub struct UniqueArc< } #[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl Send for UniqueArc {} +unsafe impl Send for UniqueArc {} #[unstable(feature = "unique_rc_arc", issue = "112566")] unsafe impl Sync for UniqueArc {} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a619aa6e5427b..698379b96a696 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1140,7 +1140,7 @@ impl Vec { /// v.push(3); /// /// // Deconstruct the vector into parts. - /// let (p, len, cap, alloc) = v.into_raw_parts_with_alloc(); + /// let (p, len, cap, alloc) = v.into_raw_parts_with_allocator(); /// /// unsafe { /// // Overwrite memory with 4, 5, 6 @@ -1337,7 +1337,7 @@ impl Vec { /// v.push(0); /// v.push(1); /// - /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); + /// let (ptr, len, cap, alloc) = v.into_raw_parts_with_allocator(); /// /// let rebuilt = unsafe { /// // We can now make changes to the components, such as @@ -1351,7 +1351,7 @@ impl Vec { #[must_use = "losing the pointer will leak memory"] #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "allocator_api", issue = "32838")] - pub const fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) { + pub const fn into_raw_parts_with_allocator(self) -> (*mut T, usize, usize, A) { let mut me = ManuallyDrop::new(self); let len = me.len(); let capacity = me.capacity(); @@ -1402,7 +1402,7 @@ impl Vec { #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "allocator_api", issue = "32838")] pub const fn into_parts_with_alloc(self) -> (NonNull, usize, usize, A) { - let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc(); + let (ptr, len, capacity, alloc) = self.into_raw_parts_with_allocator(); // SAFETY: A `Vec` always has a non-null pointer. (unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc) } @@ -3439,10 +3439,10 @@ impl Vec { self.buf.shrink_to_fit(cap - cap_remainder); } - let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc(); + let (ptr, _, _, alloc) = self.into_raw_parts_with_allocator(); // SAFETY: - // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_allocator()` // - `[T; N]` has the same alignment as `T` // - `size_of::<[T; N]>() * cap / N == size_of::() * cap` // - `len / N <= cap / N` because `len <= cap` @@ -3515,7 +3515,7 @@ impl Vec { let (ptr, length, capacity, alloc) = self.into_parts_with_alloc(); debug_assert_eq!(length, 0); // SAFETY: - // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_allocator()` // - `T` & `U` have the same layout, so `capacity` does not need to be changed and we can safely use `alloc.dealloc` later // - the original vector was cleared, so there is no problem with "transmuting" the stored values unsafe { Vec::from_parts_in(ptr.cast::(), length, capacity, alloc) } @@ -3686,7 +3686,7 @@ impl Vec<[T; N], A> { /// ``` #[stable(feature = "slice_flatten", since = "1.80.0")] pub fn into_flattened(self) -> Vec { - let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc(); + let (ptr, len, cap, alloc) = self.into_raw_parts_with_allocator(); let (new_len, new_cap) = if T::IS_ZST { (len.checked_mul(N).expect("vec len overflow"), usize::MAX) } else { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 7816709ac4663..6069c468f96e4 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -49,21 +49,28 @@ impl fmt::Display for AllocError { /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// -/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers. -/// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the -/// allocated memory. +/// `Allocator` is mostly designed to be implemented on ZSTs, references, or smart pointers, +/// but can also be implemented directly on the underlying memory-owning type so long as it +/// upholds the necessary guarantees. In general, an allocator of the type `MyAlloc([u8; N])` +/// cannot be soundly created without being pinned or otherwise immovable in order to be +/// correct. /// /// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying /// allocator does not support this (like jemalloc) or responds by returning a null pointer /// (such as `libc::malloc`), this must be caught by the implementation. /// +/// In order to be usable in a flexible manner while still being sound, implementors of the trait +/// must uphold very detailed semantics as explained below; the following terms are thus provided +/// as vocabulary for allocator safety and implementation requirements: +/// /// ### Equivalent allocators /// /// Multiple allocator values can sometimes be interchangeable with each other. /// When this is the case, we refer to those allocators as being *equivalent* to /// each other. /// -/// The following conditions are sufficient conditions for allocators to be equivalent. +/// Users of allocators may assume the following are true of equivalent allocators, +/// and implementors must ensure these rules are upheld: /// * An allocator is equivalent to itself. (Equivalence is reflexive.) /// * If an allocator is equivalent to a second allocator, then /// the second allocator is also equivalent to the first. (Equivalence is symmetric.) @@ -73,9 +80,8 @@ impl fmt::Display for AllocError { /// (Equivalence is transitive.) /// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change /// what the allocator is equivalent to. -/// * Copying or cloning allocator results in an allocator that's -/// equivalent to the initial allocator, should the [`AllocatorClone`] trait -/// be implemented. +/// * Copying or cloning an allocator creates an equivalent one, should the +/// [`AllocatorClone`] trait be implemented. /// /// Additionally, implementors of `Allocator` may specify additional equivalences /// between allocators. It is the responsibility of such implementors to make sure @@ -104,14 +110,14 @@ impl fmt::Display for AllocError { /// * The memory block is deallocated. This occurs when the memory block /// is passed as an argument to a [`deallocate`] call, or when it is passed /// as an argument to a [`grow`], [`grow_zeroed`] or [`shrink`] call that returns `Ok`. -/// * All (equivalent) allocators that this memory block is allocated with, -/// each has one of the following happen to them: +/// * For all (equivalent) allocators that this memory block is currently allocated by, at +/// least one of the following has occurred: /// * The allocator's destructor runs. -/// * The allocator is mutated through public API taking `&mut` access. +/// * The allocator is mutated through a public or otherwise untrusted API taking `&mut` access. /// * One of the borrow-checker lifetimes in the allocator's type expires. /// /// Note that these conditions imply that a collection may ensure that -/// any specific currently allocated memory block won't be invalidated, by: +/// any specific currently allocated memory block won't be invalidated by: /// * not deallocating that memory block, /// * owning an allocator that memory block is allocated with, and /// * not publicly exposing `&mut` access to that allocator. @@ -120,11 +126,11 @@ impl fmt::Display for AllocError { /// allowed to invalidate its memory blocks. Furthermore, unsafe public API /// of an allocator with `&` access must document that they invalidate /// memory blocks (e.g., by calling `deallocate`) if they do. Therefore, -/// collections may safely expose `&` access to its allocator. +/// a collection may safely expose `&` access to its allocator. /// -/// Also note that, even in cases where are other "alive" allocators known to be -/// equivalent to a given collection's allocator, most collections still should -/// not publicly expose `&mut` access to its allocator. The fact that there are +/// Also note that, even in cases where there are other "alive" allocators known +/// to be equivalent to a given collection's allocator, most collections still should +/// not publicly expose `&mut` access to their allocators. The fact that there are /// other "alive" allocators would prevent this `&mut` access from invalidating /// the collection's memory block, but public `&mut` access is still likely to /// be unsound, since a user could replace the collection's allocator with @@ -140,8 +146,8 @@ impl fmt::Display for AllocError { /// /// ### Memory fitting /// -/// Some of the methods require that a `layout` *fit* a memory block or vice versa. This means that the -/// following conditions must hold: +/// Some of the methods require that a `layout` *fits* a memory block or vice versa. This means +/// that the following conditions must hold: /// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and /// * [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout used to allocate the block, and @@ -154,28 +160,32 @@ impl fmt::Display for AllocError { /// # Safety /// /// Implementors of `Allocator` must ensure that a memory block that -/// is [*currently allocated*] by the allocator points to valid memory, +/// is [*currently allocated*] by the allocator points to valid memory /// until that memory block is [*invalidated*]. The implementor must also /// not violate this invariant of `Allocator` via allocator equivalences -/// that are in the implementor's control (e.g., via an incorrect `unsafe -/// impl AllocatorClone for MyAllocator`). +/// that are in the implementor's control. /// /// Additionally, any memory block returned by the allocator must /// satisfy the allocation invariants described in `core::ptr`. /// In particular, if a block has base address `p` and size `n`, -/// then `p as usize + n <= usize::MAX` must hold. +/// then `p as usize + n <= usize::MAX` must hold. These blocks must also +/// be wholly disjoint. /// /// This ensures that pointer arithmetic within the allocation -/// (for example, `ptr.add(len)`) cannot overflow the address space. +/// (for example, `ptr.add(len)`) cannot overflow the address space, and +/// that it is possible to perform nonoverlapping copies between allocations. /// /// None of the allocating or deallocating methods may unwind. This restriction /// may be lifted in the future by ensuring unwinding out of an allocating function always /// aborts. If an implementor of `Allocator` also has drop glue or directly implements `Drop`, /// dropping the allocator must not result in an unwind. /// -/// Lastly, the methods on this trait must be *correct*; i.e. the layout requested +/// It is undefined behavior for the allocator to read, write, or deallocate any memory that +/// is currently allocated. This memory is owned by the user; the allocator must not touch it. +/// +/// Lastly, the methods on this trait must be *correct*; in particular, the layout requested /// must be respected, calls must zero out memory if the documentation so requires, -/// and returning an `AllocError` from a reallocating method must indeed ensure that +/// returning an `AllocError` from a reallocating method must indeed ensure that /// the old pointer was not invalidated, and de/reallocating calls must accept layouts /// in the ranges defined by their documentation. /// @@ -203,7 +213,7 @@ pub const unsafe trait Allocator { /// Note that the returned block of memory is considered [*currently allocated*] /// with this allocator (and equivalent allocators). /// Therefore, it is the responsibility of implementors of `Allocator` to make sure that - /// this block of memory points to valid memory until the block is [*invalidated*] + /// this block of memory remains valid until it is [*invalidated*]. /// /// [*currently allocated*]: #currently-allocated-memory /// [*invalidated*]: #invalidating-memory-blocks @@ -539,14 +549,15 @@ pub unsafe trait AllocatorClone: Allocator + Clone {} /// /// # Safety /// -/// Implementors must ensure that memory cannot be freed except via a call to -/// `Allocator::deallocate`, and that subtype coercion preserves this invariant. +/// Implementors must ensure that memory blocks are *only, ever* invalidated by a +/// call to a de/reallocating method on `Allocator`, and that this holds true for all +/// possible instances of all subtypes of the implementor as well. /// /// These requirements trivially apply to allocators that always maintain global state, such as /// `System` or `Global`. However, due to subtype coercion, it is *not* sound to implement -/// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with -/// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that an -/// impl of `StaticAllocator for MyAllocator + 'short` would be sound to write. +/// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with e.g. +/// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that any +/// value of `MyAllocator + 'short` also fulfills the requirements of `StaticAllocator`. /// /// The following must thus be guaranteed: /// - the `Drop` impl of the allocator does not invalidate any allocations; @@ -617,9 +628,10 @@ where } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for &mut A +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const unsafe impl Allocator for &mut A where - A: Allocator + ?Sized, + A: [const] Allocator + ?Sized, { #[inline] fn allocate(&self, layout: Layout) -> Result, AllocError> { @@ -678,3 +690,6 @@ unsafe impl AllocatorClone for &A {} // its semantics, and references are equivalent to the allocator they reference. #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl StaticAllocator for &A {} + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl StaticAllocator for &mut A {} diff --git a/tests/ui/allocator/157089-box-pin-in.stderr b/tests/ui/allocator/157089-box-pin-in.stderr index f25736d819a1f..e919eb8e3286e 100644 --- a/tests/ui/allocator/157089-box-pin-in.stderr +++ b/tests/ui/allocator/157089-box-pin-in.stderr @@ -15,6 +15,9 @@ help: the following other types implement trait `StaticAllocator` --> $SRC_DIR/core/src/alloc/mod.rs:LL:COL | = note: `&A` + ::: $SRC_DIR/core/src/alloc/mod.rs:LL:COL + | + = note: `&mut A` --> $SRC_DIR/std/src/alloc.rs:LL:COL | = note: `System` diff --git a/tests/ui/allocator/159445-unsize-pin-box.stderr b/tests/ui/allocator/159445-unsize-pin-box.stderr index 0fb3d0f176eb2..c17019be03799 100644 --- a/tests/ui/allocator/159445-unsize-pin-box.stderr +++ b/tests/ui/allocator/159445-unsize-pin-box.stderr @@ -13,6 +13,9 @@ help: the following other types implement trait `StaticAllocator` --> $SRC_DIR/core/src/alloc/mod.rs:LL:COL | = note: `&A` + ::: $SRC_DIR/core/src/alloc/mod.rs:LL:COL + | + = note: `&mut A` --> $SRC_DIR/std/src/alloc.rs:LL:COL | = note: `System`