Skip to content

Commit 63f0cfc

Browse files
authored
Rollup merge of #161115 - nia-e:allocator-nitpicks, r=clarfonthey
Assorted allocator nitpicks Small things that got missed in #157428, doc language cleanup for allocator, and a rename that closes #158344. cc @rust-lang/wg-allocators. pending libs bikeshed decision on the naming of `into_raw_parts_with_alloc` r? clarfonthey
2 parents 6ff2141 + 7d40fdb commit 63f0cfc

7 files changed

Lines changed: 77 additions & 50 deletions

File tree

library/alloc/src/collections/vec_deque/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3991,7 +3991,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
39913991
/// any additional memory.
39923992
#[inline]
39933993
fn from(other: Vec<T, A>) -> Self {
3994-
let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc();
3994+
let (ptr, len, cap, alloc) = other.into_raw_parts_with_allocator();
39953995
Self {
39963996
head: WrappedIndex::zero(),
39973997
len,

library/alloc/src/rc.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,12 @@ impl<T: ?Sized, A: Allocator> !Send for Rc<T, A> {}
342342
impl<T: ?Sized, A: Allocator> !Sync for Rc<T, A> {}
343343

344344
#[stable(feature = "catch_unwind", since = "1.9.0")]
345-
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe> UnwindSafe for Rc<T, A> {}
345+
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe + RefUnwindSafe> UnwindSafe for Rc<T, A> {}
346346
#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
347-
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe> RefUnwindSafe for Rc<T, A> {}
347+
impl<T: RefUnwindSafe + ?Sized, A: Allocator + UnwindSafe + RefUnwindSafe> RefUnwindSafe
348+
for Rc<T, A>
349+
{
350+
}
348351

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

30033006
#[cfg(not(no_global_oom_handling))]
30043007
#[stable(feature = "shared_from_slice", since = "1.21.0")]
3005-
impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
3008+
impl<T, A: AllocatorClone> From<Vec<T, A>> for Rc<[T], A> {
30063009
/// Allocates a reference-counted slice and moves `v`'s items into it.
30073010
///
30083011
/// # Example
@@ -3016,7 +3019,7 @@ impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
30163019
#[inline]
30173020
fn from(v: Vec<T, A>) -> Rc<[T], A> {
30183021
unsafe {
3019-
let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
3022+
let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_allocator();
30203023

30213024
let rc_ptr = Self::allocate_for_slice_in(len, &alloc);
30223025
ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len);

library/alloc/src/sync.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,15 @@ pub struct Arc<
281281
}
282282

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

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

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

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

@@ -4083,7 +4086,7 @@ impl<T, A: AllocatorClone> From<Vec<T, A>> for Arc<[T], A> {
40834086
#[inline]
40844087
fn from(v: Vec<T, A>) -> Arc<[T], A> {
40854088
unsafe {
4086-
let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
4089+
let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_allocator();
40874090

40884091
let rc_ptr = Self::allocate_for_slice_in(len, &alloc);
40894092
ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len);
@@ -4423,7 +4426,7 @@ pub struct UniqueArc<
44234426
}
44244427

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

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

library/alloc/src/vec/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ impl<T, A: Allocator> Vec<T, A> {
11401140
/// v.push(3);
11411141
///
11421142
/// // Deconstruct the vector into parts.
1143-
/// let (p, len, cap, alloc) = v.into_raw_parts_with_alloc();
1143+
/// let (p, len, cap, alloc) = v.into_raw_parts_with_allocator();
11441144
///
11451145
/// unsafe {
11461146
/// // Overwrite memory with 4, 5, 6
@@ -1337,7 +1337,7 @@ impl<T, A: Allocator> Vec<T, A> {
13371337
/// v.push(0);
13381338
/// v.push(1);
13391339
///
1340-
/// let (ptr, len, cap, alloc) = v.into_raw_parts_with_alloc();
1340+
/// let (ptr, len, cap, alloc) = v.into_raw_parts_with_allocator();
13411341
///
13421342
/// let rebuilt = unsafe {
13431343
/// // We can now make changes to the components, such as
@@ -1351,7 +1351,7 @@ impl<T, A: Allocator> Vec<T, A> {
13511351
#[must_use = "losing the pointer will leak memory"]
13521352
#[unstable(feature = "allocator_api", issue = "32838")]
13531353
#[rustc_const_unstable(feature = "allocator_api", issue = "32838")]
1354-
pub const fn into_raw_parts_with_alloc(self) -> (*mut T, usize, usize, A) {
1354+
pub const fn into_raw_parts_with_allocator(self) -> (*mut T, usize, usize, A) {
13551355
let mut me = ManuallyDrop::new(self);
13561356
let len = me.len();
13571357
let capacity = me.capacity();
@@ -1402,7 +1402,7 @@ impl<T, A: Allocator> Vec<T, A> {
14021402
#[unstable(feature = "allocator_api", issue = "32838")]
14031403
#[rustc_const_unstable(feature = "allocator_api", issue = "32838")]
14041404
pub const fn into_parts_with_alloc(self) -> (NonNull<T>, usize, usize, A) {
1405-
let (ptr, len, capacity, alloc) = self.into_raw_parts_with_alloc();
1405+
let (ptr, len, capacity, alloc) = self.into_raw_parts_with_allocator();
14061406
// SAFETY: A `Vec` always has a non-null pointer.
14071407
(unsafe { NonNull::new_unchecked(ptr) }, len, capacity, alloc)
14081408
}
@@ -3439,10 +3439,10 @@ impl<T, A: Allocator> Vec<T, A> {
34393439
self.buf.shrink_to_fit(cap - cap_remainder);
34403440
}
34413441

3442-
let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc();
3442+
let (ptr, _, _, alloc) = self.into_raw_parts_with_allocator();
34433443

34443444
// SAFETY:
3445-
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3445+
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_allocator()`
34463446
// - `[T; N]` has the same alignment as `T`
34473447
// - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap`
34483448
// - `len / N <= cap / N` because `len <= cap`
@@ -3515,7 +3515,7 @@ impl<T, A: Allocator> Vec<T, A> {
35153515
let (ptr, length, capacity, alloc) = self.into_parts_with_alloc();
35163516
debug_assert_eq!(length, 0);
35173517
// SAFETY:
3518-
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3518+
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_allocator()`
35193519
// - `T` & `U` have the same layout, so `capacity` does not need to be changed and we can safely use `alloc.dealloc` later
35203520
// - the original vector was cleared, so there is no problem with "transmuting" the stored values
35213521
unsafe { Vec::from_parts_in(ptr.cast::<U>(), length, capacity, alloc) }
@@ -3686,7 +3686,7 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
36863686
/// ```
36873687
#[stable(feature = "slice_flatten", since = "1.80.0")]
36883688
pub fn into_flattened(self) -> Vec<T, A> {
3689-
let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc();
3689+
let (ptr, len, cap, alloc) = self.into_raw_parts_with_allocator();
36903690
let (new_len, new_cap) = if T::IS_ZST {
36913691
(
36923692
len.checked_mul(N).expect("the product of vec len and N shouldn't overflow"),

library/core/src/alloc/mod.rs

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,28 @@ impl fmt::Display for AllocError {
4949
/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
5050
/// data described via [`Layout`][].
5151
///
52-
/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers.
53-
/// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
54-
/// allocated memory.
52+
/// `Allocator` is mostly designed to be implemented on ZSTs, references, or smart pointers,
53+
/// but can also be implemented directly on the underlying memory-owning type so long as it
54+
/// upholds the necessary guarantees. In general, an allocator of the type `MyAlloc([u8; N])`
55+
/// cannot be soundly created without being pinned or otherwise immovable in order to be
56+
/// correct.
5557
///
5658
/// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying
5759
/// allocator does not support this (like jemalloc) or responds by returning a null pointer
5860
/// (such as `libc::malloc`), this must be caught by the implementation.
5961
///
62+
/// In order to be usable in a flexible manner while still being sound, implementors of the trait
63+
/// must uphold very detailed semantics as explained below; the following terms are thus provided
64+
/// as vocabulary for allocator safety and implementation requirements:
65+
///
6066
/// ### Equivalent allocators
6167
///
6268
/// Multiple allocator values can sometimes be interchangeable with each other.
6369
/// When this is the case, we refer to those allocators as being *equivalent* to
6470
/// each other.
6571
///
66-
/// The following conditions are sufficient conditions for allocators to be equivalent.
72+
/// Users of allocators may assume the following are true of equivalent allocators,
73+
/// and implementors must ensure these rules are upheld:
6774
/// * An allocator is equivalent to itself. (Equivalence is reflexive.)
6875
/// * If an allocator is equivalent to a second allocator, then
6976
/// the second allocator is also equivalent to the first. (Equivalence is symmetric.)
@@ -73,9 +80,8 @@ impl fmt::Display for AllocError {
7380
/// (Equivalence is transitive.)
7481
/// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change
7582
/// what the allocator is equivalent to.
76-
/// * Copying or cloning allocator results in an allocator that's
77-
/// equivalent to the initial allocator, should the [`AllocatorClone`] trait
78-
/// be implemented.
83+
/// * Copying or cloning an allocator creates an equivalent one, should the
84+
/// [`AllocatorClone`] trait be implemented.
7985
///
8086
/// Additionally, implementors of `Allocator` may specify additional equivalences
8187
/// between allocators. It is the responsibility of such implementors to make sure
@@ -104,14 +110,14 @@ impl fmt::Display for AllocError {
104110
/// * The memory block is deallocated. This occurs when the memory block
105111
/// is passed as an argument to a [`deallocate`] call, or when it is passed
106112
/// as an argument to a [`grow`], [`grow_zeroed`] or [`shrink`] call that returns `Ok`.
107-
/// * All (equivalent) allocators that this memory block is allocated with,
108-
/// each has one of the following happen to them:
113+
/// * For all (equivalent) allocators that this memory block is currently allocated by, at
114+
/// least one of the following has occurred:
109115
/// * The allocator's destructor runs.
110-
/// * The allocator is mutated through public API taking `&mut` access.
116+
/// * The allocator is mutated through a public or otherwise untrusted API taking `&mut` access.
111117
/// * One of the borrow-checker lifetimes in the allocator's type expires.
112118
///
113119
/// Note that these conditions imply that a collection may ensure that
114-
/// any specific currently allocated memory block won't be invalidated, by:
120+
/// any specific currently allocated memory block won't be invalidated by:
115121
/// * not deallocating that memory block,
116122
/// * owning an allocator that memory block is allocated with, and
117123
/// * not publicly exposing `&mut` access to that allocator.
@@ -120,11 +126,11 @@ impl fmt::Display for AllocError {
120126
/// allowed to invalidate its memory blocks. Furthermore, unsafe public API
121127
/// of an allocator with `&` access must document that they invalidate
122128
/// memory blocks (e.g., by calling `deallocate`) if they do. Therefore,
123-
/// collections may safely expose `&` access to its allocator.
129+
/// a collection may safely expose `&` access to its allocator.
124130
///
125-
/// Also note that, even in cases where are other "alive" allocators known to be
126-
/// equivalent to a given collection's allocator, most collections still should
127-
/// not publicly expose `&mut` access to its allocator. The fact that there are
131+
/// Also note that, even in cases where there are other "alive" allocators known
132+
/// to be equivalent to a given collection's allocator, most collections still should
133+
/// not publicly expose `&mut` access to their allocators. The fact that there are
128134
/// other "alive" allocators would prevent this `&mut` access from invalidating
129135
/// the collection's memory block, but public `&mut` access is still likely to
130136
/// be unsound, since a user could replace the collection's allocator with
@@ -140,8 +146,8 @@ impl fmt::Display for AllocError {
140146
///
141147
/// ### Memory fitting
142148
///
143-
/// Some of the methods require that a `layout` *fit* a memory block or vice versa. This means that the
144-
/// following conditions must hold:
149+
/// Some of the methods require that a `layout` *fits* a memory block or vice versa. This means
150+
/// that the following conditions must hold:
145151
/// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and
146152
/// * [`layout.size()`] must fall in the range `min ..= max`, where:
147153
/// - `min` is the size of the layout used to allocate the block, and
@@ -154,28 +160,32 @@ impl fmt::Display for AllocError {
154160
/// # Safety
155161
///
156162
/// Implementors of `Allocator` must ensure that a memory block that
157-
/// is [*currently allocated*] by the allocator points to valid memory,
163+
/// is [*currently allocated*] by the allocator points to valid memory
158164
/// until that memory block is [*invalidated*]. The implementor must also
159165
/// not violate this invariant of `Allocator` via allocator equivalences
160-
/// that are in the implementor's control (e.g., via an incorrect `unsafe
161-
/// impl AllocatorClone for MyAllocator`).
166+
/// that are in the implementor's control.
162167
///
163168
/// Additionally, any memory block returned by the allocator must
164169
/// satisfy the allocation invariants described in `core::ptr`.
165170
/// In particular, if a block has base address `p` and size `n`,
166-
/// then `p as usize + n <= usize::MAX` must hold.
171+
/// then `p as usize + n <= usize::MAX` must hold. These blocks must also
172+
/// be wholly disjoint.
167173
///
168174
/// This ensures that pointer arithmetic within the allocation
169-
/// (for example, `ptr.add(len)`) cannot overflow the address space.
175+
/// (for example, `ptr.add(len)`) cannot overflow the address space, and
176+
/// that it is possible to perform nonoverlapping copies between allocations.
170177
///
171178
/// None of the allocating or deallocating methods may unwind. This restriction
172179
/// may be lifted in the future by ensuring unwinding out of an allocating function always
173180
/// aborts. If an implementor of `Allocator` also has drop glue or directly implements `Drop`,
174181
/// dropping the allocator must not result in an unwind.
175182
///
176-
/// Lastly, the methods on this trait must be *correct*; i.e. the layout requested
183+
/// It is undefined behavior for the allocator to read, write, or deallocate any memory that
184+
/// is currently allocated. This memory is owned by the user; the allocator must not touch it.
185+
///
186+
/// Lastly, the methods on this trait must be *correct*; in particular, the layout requested
177187
/// must be respected, calls must zero out memory if the documentation so requires,
178-
/// and returning an `AllocError` from a reallocating method must indeed ensure that
188+
/// returning an `AllocError` from a reallocating method must indeed ensure that
179189
/// the old pointer was not invalidated, and de/reallocating calls must accept layouts
180190
/// in the ranges defined by their documentation.
181191
///
@@ -203,7 +213,7 @@ pub const unsafe trait Allocator {
203213
/// Note that the returned block of memory is considered [*currently allocated*]
204214
/// with this allocator (and equivalent allocators).
205215
/// Therefore, it is the responsibility of implementors of `Allocator` to make sure that
206-
/// this block of memory points to valid memory until the block is [*invalidated*]
216+
/// this block of memory remains valid until it is [*invalidated*].
207217
///
208218
/// [*currently allocated*]: #currently-allocated-memory
209219
/// [*invalidated*]: #invalidating-memory-blocks
@@ -539,14 +549,15 @@ pub unsafe trait AllocatorClone: Allocator + Clone {}
539549
///
540550
/// # Safety
541551
///
542-
/// Implementors must ensure that memory cannot be freed except via a call to
543-
/// `Allocator::deallocate`, and that subtype coercion preserves this invariant.
552+
/// Implementors must ensure that memory blocks are *only, ever* invalidated by a
553+
/// call to a de/reallocating method on `Allocator`, and that this holds true for all
554+
/// possible instances of all subtypes of the implementor as well.
544555
///
545556
/// These requirements trivially apply to allocators that always maintain global state, such as
546557
/// `System` or `Global`. However, due to subtype coercion, it is *not* sound to implement
547-
/// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with
548-
/// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that an
549-
/// impl of `StaticAllocator for MyAllocator + 'short` would be sound to write.
558+
/// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with e.g.
559+
/// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that any
560+
/// value of `MyAllocator + 'short` also fulfills the requirements of `StaticAllocator`.
550561
///
551562
/// The following must thus be guaranteed:
552563
/// - the `Drop` impl of the allocator does not invalidate any allocations;
@@ -617,9 +628,10 @@ where
617628
}
618629

619630
#[unstable(feature = "allocator_api", issue = "32838")]
620-
unsafe impl<A> Allocator for &mut A
631+
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
632+
const unsafe impl<A> Allocator for &mut A
621633
where
622-
A: Allocator + ?Sized,
634+
A: [const] Allocator + ?Sized,
623635
{
624636
#[inline]
625637
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
@@ -678,3 +690,6 @@ unsafe impl<A: Allocator + ?Sized> AllocatorClone for &A {}
678690
// its semantics, and references are equivalent to the allocator they reference.
679691
#[unstable(feature = "allocator_api", issue = "32838")]
680692
unsafe impl<A: StaticAllocator + ?Sized> StaticAllocator for &A {}
693+
694+
#[unstable(feature = "allocator_api", issue = "32838")]
695+
unsafe impl<A: StaticAllocator + ?Sized> StaticAllocator for &mut A {}

tests/ui/allocator/157089-box-pin-in.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ help: the following other types implement trait `StaticAllocator`
1515
--> $SRC_DIR/core/src/alloc/mod.rs:LL:COL
1616
|
1717
= note: `&A`
18+
::: $SRC_DIR/core/src/alloc/mod.rs:LL:COL
19+
|
20+
= note: `&mut A`
1821
--> $SRC_DIR/std/src/alloc.rs:LL:COL
1922
|
2023
= note: `System`

tests/ui/allocator/159445-unsize-pin-box.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ help: the following other types implement trait `StaticAllocator`
1313
--> $SRC_DIR/core/src/alloc/mod.rs:LL:COL
1414
|
1515
= note: `&A`
16+
::: $SRC_DIR/core/src/alloc/mod.rs:LL:COL
17+
|
18+
= note: `&mut A`
1619
--> $SRC_DIR/std/src/alloc.rs:LL:COL
1720
|
1821
= note: `System`

0 commit comments

Comments
 (0)