Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3991,7 +3991,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
/// any additional memory.
#[inline]
fn from(other: Vec<T, A>) -> 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,
Expand Down
11 changes: 7 additions & 4 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,12 @@ impl<T: ?Sized, A: Allocator> !Send for Rc<T, A> {}
impl<T: ?Sized, A: Allocator> !Sync for Rc<T, A> {}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe> UnwindSafe for Rc<T, A> {}
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe + RefUnwindSafe> UnwindSafe for Rc<T, A> {}
#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe> RefUnwindSafe for Rc<T, A> {}
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe + RefUnwindSafe> RefUnwindSafe
for Rc<T, A>
{
}

#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Rc<U, A>> for Rc<T, A> {}
Expand Down Expand Up @@ -3002,7 +3005,7 @@ impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Rc<T, A> {

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "shared_from_slice", since = "1.21.0")]
impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
impl<T, A: AllocatorClone> From<Vec<T, A>> for Rc<[T], A> {
/// Allocates a reference-counted slice and moves `v`'s items into it.
///
/// # Example
Expand All @@ -3016,7 +3019,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
#[inline]
fn from(v: Vec<T, A>) -> 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);
Expand Down
13 changes: 8 additions & 5 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,15 @@ pub struct Arc<
}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send> Send for Arc<T, A> {}
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send + Sync> Send for Arc<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Sync> Sync for Arc<T, A> {}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe> UnwindSafe for Arc<T, A> {}
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe + RefUnwindSafe> UnwindSafe
for Arc<T, A>
{
}

#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Arc<U, A>> for Arc<T, A> {}
Expand Down Expand Up @@ -364,7 +367,7 @@ pub struct Weak<
}

#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send> Send for Weak<T, A> {}
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send + Sync> Send for Weak<T, A> {}
#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Sync> Sync for Weak<T, A> {}

Expand Down Expand Up @@ -4083,7 +4086,7 @@ impl<T, A: AllocatorClone> From<Vec<T, A>> for Arc<[T], A> {
#[inline]
fn from(v: Vec<T, A>) -> 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);
Expand Down Expand Up @@ -4423,7 +4426,7 @@ pub struct UniqueArc<
}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send> Send for UniqueArc<T, A> {}
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send + Sync> Send for UniqueArc<T, A> {}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Sync> Sync for UniqueArc<T, A> {}
Expand Down
16 changes: 8 additions & 8 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// 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
Expand Down Expand Up @@ -1337,7 +1337,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// 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
Expand All @@ -1351,7 +1351,7 @@ impl<T, A: Allocator> Vec<T, A> {
#[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) {
Comment thread
nia-e marked this conversation as resolved.
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();
Expand Down Expand Up @@ -1402,7 +1402,7 @@ impl<T, A: Allocator> Vec<T, A> {
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "allocator_api", issue = "32838")]
pub const fn into_parts_with_alloc(self) -> (NonNull<T>, 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)
}
Expand Down Expand Up @@ -3439,10 +3439,10 @@ impl<T, A: Allocator> Vec<T, A> {
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::<T>() * cap`
// - `len / N <= cap / N` because `len <= cap`
Expand Down Expand Up @@ -3515,7 +3515,7 @@ impl<T, A: Allocator> Vec<T, A> {
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::<U>(), length, capacity, alloc) }
Expand Down Expand Up @@ -3686,7 +3686,7 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
/// ```
#[stable(feature = "slice_flatten", since = "1.80.0")]
pub fn into_flattened(self) -> Vec<T, A> {
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 {
Expand Down
79 changes: 47 additions & 32 deletions library/core/src/alloc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand All @@ -73,9 +80,8 @@ impl fmt::Display for AllocError {
/// (Equivalence is transitive.)
/// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change
Comment thread
clarfonthey marked this conversation as resolved.
/// 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
Comment thread
clarfonthey marked this conversation as resolved.
/// [`AllocatorClone`] trait be implemented.
///
/// Additionally, implementors of `Allocator` may specify additional equivalences
/// between allocators. It is the responsibility of such implementors to make sure
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Comment thread
nia-e marked this conversation as resolved.
/// 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
Expand All @@ -154,28 +160,32 @@ impl fmt::Display for AllocError {
/// # Safety
Comment thread
clarfonthey marked this conversation as resolved.
///
/// 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.
///
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -617,9 +628,10 @@ where
}

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl<A> Allocator for &mut A
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
Comment thread
nia-e marked this conversation as resolved.
const unsafe impl<A> Allocator for &mut A
where
A: Allocator + ?Sized,
A: [const] Allocator + ?Sized,
{
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Expand Down Expand Up @@ -678,3 +690,6 @@ unsafe impl<A: Allocator + ?Sized> AllocatorClone for &A {}
// its semantics, and references are equivalent to the allocator they reference.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl<A: StaticAllocator + ?Sized> StaticAllocator for &A {}

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl<A: StaticAllocator + ?Sized> StaticAllocator for &mut A {}
3 changes: 3 additions & 0 deletions tests/ui/allocator/157089-box-pin-in.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/allocator/159445-unsize-pin-box.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
Loading