about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/alloc.rs96
-rw-r--r--src/liballoc/alloc/tests.rs6
-rw-r--r--src/liballoc/boxed.rs15
-rw-r--r--src/liballoc/collections/btree/node.rs19
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/raw_vec.rs228
-rw-r--r--src/liballoc/raw_vec/tests.rs16
-rw-r--r--src/liballoc/rc.rs17
-rw-r--r--src/liballoc/sync.rs16
-rw-r--r--src/liballoc/tests/heap.rs9
-rw-r--r--src/liballoc/vec.rs3
11 files changed, 216 insertions, 210 deletions
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index 26524f62962..7eb9e0d5ea3 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -4,7 +4,7 @@
 
 use core::intrinsics::{self, min_align_of_val, size_of_val};
 use core::ptr::{NonNull, Unique};
-use core::usize;
+use core::{mem, usize};
 
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
@@ -165,102 +165,96 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for Global {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let new_size = layout.size();
-        if new_size == 0 {
-            Ok((layout.dangling(), 0))
-        } else {
-            unsafe {
+    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
+        unsafe {
+            if layout.size() == 0 {
+                Ok(MemoryBlock::new(layout.dangling(), layout))
+            } else {
                 let raw_ptr = match init {
                     AllocInit::Uninitialized => alloc(layout),
                     AllocInit::Zeroed => alloc_zeroed(layout),
                 };
                 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
-                Ok((ptr, new_size))
+                Ok(MemoryBlock::new(ptr, layout))
             }
         }
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
-        if layout.size() != 0 {
-            dealloc(ptr.as_ptr(), layout)
+    unsafe fn dealloc(&mut self, memory: MemoryBlock) {
+        if memory.size() != 0 {
+            dealloc(memory.ptr().as_ptr(), memory.layout())
         }
     }
 
     #[inline]
     unsafe fn grow(
         &mut self,
-        ptr: NonNull<u8>,
-        layout: Layout,
+        memory: &mut MemoryBlock,
         new_size: usize,
         placement: ReallocPlacement,
         init: AllocInit,
-    ) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let old_size = layout.size();
+    ) -> Result<(), AllocErr> {
+        let old_size = memory.size();
         debug_assert!(
             new_size >= old_size,
-            "`new_size` must be greater than or equal to `layout.size()`"
+            "`new_size` must be greater than or equal to `memory.size()`"
         );
 
         if old_size == new_size {
-            return Ok((ptr, new_size));
+            return Ok(());
         }
 
+        let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
         match placement {
+            ReallocPlacement::InPlace => return Err(AllocErr),
+            ReallocPlacement::MayMove if memory.size() == 0 => {
+                *memory = self.alloc(new_layout, init)?
+            }
             ReallocPlacement::MayMove => {
-                if old_size == 0 {
-                    self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()), init)
-                } else {
-                    // `realloc` probably checks for `new_size > old_size` or something similar.
-                    // `new_size` must be greater than or equal to `old_size` due to the safety constraint,
-                    // and `new_size` == `old_size` was caught before
-                    intrinsics::assume(new_size > old_size);
-                    let ptr =
-                        NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?;
-                    let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
-                    init.initialize_offset(ptr, new_layout, old_size);
-                    Ok((ptr, new_size))
-                }
+                // `realloc` probably checks for `new_size > old_size` or something similar.
+                intrinsics::assume(new_size > old_size);
+                let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
+                *memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
+                memory.init_offset(init, old_size);
             }
-            ReallocPlacement::InPlace => Err(AllocErr),
         }
+        Ok(())
     }
 
     #[inline]
     unsafe fn shrink(
         &mut self,
-        ptr: NonNull<u8>,
-        layout: Layout,
+        memory: &mut MemoryBlock,
         new_size: usize,
         placement: ReallocPlacement,
-    ) -> Result<(NonNull<u8>, usize), AllocErr> {
-        let old_size = layout.size();
+    ) -> Result<(), AllocErr> {
+        let old_size = memory.size();
         debug_assert!(
             new_size <= old_size,
-            "`new_size` must be smaller than or equal to `layout.size()`"
+            "`new_size` must be smaller than or equal to `memory.size()`"
         );
 
         if old_size == new_size {
-            return Ok((ptr, new_size));
+            return Ok(());
         }
 
+        let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
         match placement {
+            ReallocPlacement::InPlace => return Err(AllocErr),
+            ReallocPlacement::MayMove if new_size == 0 => {
+                let new_memory = MemoryBlock::new(new_layout.dangling(), new_layout);
+                let old_memory = mem::replace(memory, new_memory);
+                self.dealloc(old_memory)
+            }
             ReallocPlacement::MayMove => {
-                let ptr = if new_size == 0 {
-                    self.dealloc(ptr, layout);
-                    layout.dangling()
-                } else {
-                    // `realloc` probably checks for `new_size > old_size` or something similar.
-                    // `new_size` must be smaller than or equal to `old_size` due to the safety constraint,
-                    // and `new_size` == `old_size` was caught before
-                    intrinsics::assume(new_size < old_size);
-                    NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?
-                };
-                Ok((ptr, new_size))
+                // `realloc` probably checks for `new_size < old_size` or something similar.
+                intrinsics::assume(new_size < old_size);
+                let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
+                *memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
             }
-            ReallocPlacement::InPlace => Err(AllocErr),
         }
+        Ok(())
     }
 }
 
@@ -272,7 +266,7 @@ unsafe impl AllocRef for Global {
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     let layout = Layout::from_size_align_unchecked(size, align);
     match Global.alloc(layout, AllocInit::Uninitialized) {
-        Ok((ptr, _)) => ptr.as_ptr(),
+        Ok(memory) => memory.ptr().as_ptr(),
         Err(_) => handle_alloc_error(layout),
     }
 }
@@ -288,7 +282,7 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     let size = size_of_val(ptr.as_ref());
     let align = min_align_of_val(ptr.as_ref());
     let layout = Layout::from_size_align_unchecked(size, align);
-    Global.dealloc(ptr.cast().into(), layout)
+    Global.dealloc(MemoryBlock::new(ptr.cast().into(), layout))
 }
 
 /// Abort on memory allocation error or failure.
diff --git a/src/liballoc/alloc/tests.rs b/src/liballoc/alloc/tests.rs
index 6a2130a7192..34380ba41b4 100644
--- a/src/liballoc/alloc/tests.rs
+++ b/src/liballoc/alloc/tests.rs
@@ -8,17 +8,17 @@ use test::Bencher;
 fn allocate_zeroed() {
     unsafe {
         let layout = Layout::from_size_align(1024, 1).unwrap();
-        let (ptr, _) = Global
+        let memory = Global
             .alloc(layout.clone(), AllocInit::Zeroed)
             .unwrap_or_else(|_| handle_alloc_error(layout));
 
-        let mut i = ptr.cast::<u8>().as_ptr();
+        let mut i = memory.ptr().cast::<u8>().as_ptr();
         let end = i.add(layout.size());
         while i < end {
             assert_eq!(*i, 0);
             i = i.offset(1);
         }
-        Global.dealloc(ptr, layout);
+        Global.dealloc(memory);
     }
 }
 
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 9690e311e96..03d759e4a9a 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -143,7 +143,6 @@ use core::ops::{
 };
 use core::pin::Pin;
 use core::ptr::{self, NonNull, Unique};
-use core::slice;
 use core::task::{Context, Poll};
 
 use crate::alloc::{self, AllocInit, AllocRef, Global};
@@ -199,7 +198,7 @@ impl<T> Box<T> {
         let ptr = Global
             .alloc(layout, AllocInit::Uninitialized)
             .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
-            .0
+            .ptr()
             .cast();
         unsafe { Box::from_raw(ptr.as_ptr()) }
     }
@@ -228,7 +227,7 @@ impl<T> Box<T> {
         let ptr = Global
             .alloc(layout, AllocInit::Zeroed)
             .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
-            .0
+            .ptr()
             .cast();
         unsafe { Box::from_raw(ptr.as_ptr()) }
     }
@@ -265,13 +264,7 @@ impl<T> Box<[T]> {
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
-        let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
-        let ptr = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
-            .0
-            .cast();
-        unsafe { Box::from_raw(slice::from_raw_parts_mut(ptr.as_ptr(), len)) }
+        unsafe { RawVec::with_capacity(len).into_box(len) }
     }
 }
 
@@ -776,7 +769,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
         let buf = RawVec::with_capacity(len);
         unsafe {
             ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
-            buf.into_box().assume_init()
+            buf.into_box(slice.len()).assume_init()
         }
     }
 }
diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs
index 6ebb98c42cd..8b4daa28ee8 100644
--- a/src/liballoc/collections/btree/node.rs
+++ b/src/liballoc/collections/btree/node.rs
@@ -31,6 +31,7 @@
 // - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges.
 //   This implies that even an empty internal node has at least one edge.
 
+use core::alloc::MemoryBlock;
 use core::cmp::Ordering;
 use core::marker::PhantomData;
 use core::mem::{self, MaybeUninit};
@@ -227,7 +228,10 @@ impl<K, V> Root<K, V> {
         }
 
         unsafe {
-            Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
+            Global.dealloc(MemoryBlock::new(
+                NonNull::from(top).cast(),
+                Layout::new::<InternalNode<K, V>>(),
+            ));
         }
     }
 }
@@ -392,14 +396,14 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
         let height = self.height;
         let node = self.node;
         let ret = self.ascend().ok();
-        Global.dealloc(
+        Global.dealloc(MemoryBlock::new(
             node.cast(),
             if height > 0 {
                 Layout::new::<InternalNode<K, V>>()
             } else {
                 Layout::new::<LeafNode<K, V>>()
             },
-        );
+        ));
         ret
     }
 }
@@ -1142,7 +1146,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
 
             (*left_node.as_leaf_mut()).len += right_len as u16 + 1;
 
-            if self.node.height > 1 {
+            let layout = if self.node.height > 1 {
                 ptr::copy_nonoverlapping(
                     right_node.cast_unchecked().as_internal().edges.as_ptr(),
                     left_node
@@ -1159,10 +1163,11 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
                         .correct_parent_link();
                 }
 
-                Global.dealloc(right_node.node.cast(), Layout::new::<InternalNode<K, V>>());
+                Layout::new::<InternalNode<K, V>>()
             } else {
-                Global.dealloc(right_node.node.cast(), Layout::new::<LeafNode<K, V>>());
-            }
+                Layout::new::<LeafNode<K, V>>()
+            };
+            Global.dealloc(MemoryBlock::new(right_node.node.cast(), layout));
 
             Handle::new_edge(self.node, self.idx)
         }
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 5857b79d5ee..121c1cde548 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -100,6 +100,7 @@
 #![feature(lang_items)]
 #![feature(libc)]
 #![cfg_attr(not(bootstrap), feature(negative_impls))]
+#![feature(new_uninit)]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
 #![feature(pattern)]
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 3a108adb218..aee2367bd95 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -1,6 +1,7 @@
 #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
 #![doc(hidden)]
 
+use core::alloc::MemoryBlock;
 use core::cmp;
 use core::mem::{self, MaybeUninit};
 use core::ops::Drop;
@@ -24,6 +25,9 @@ mod tests;
 /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
 /// In particular:
 ///
+/// * Produces `Unique::empty()` on zero-sized types.
+/// * Produces `Unique::empty()` on zero-length allocations.
+/// * Avoids freeing `Unique::empty()`.
 /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics).
 /// * Guards against 32-bit systems allocating more than isize::MAX bytes.
 /// * Guards against overflowing your length.
@@ -44,38 +48,7 @@ mod tests;
 pub struct RawVec<T, A: AllocRef = Global> {
     ptr: Unique<T>,
     cap: usize,
-    a: A,
-}
-
-impl<T, A: AllocRef> RawVec<T, A> {
-    /// Like `new`, but parameterized over the choice of allocator for
-    /// the returned `RawVec`.
-    pub const fn new_in(a: A) -> Self {
-        // `cap: 0` means "unallocated". zero-sized allocations are handled by `AllocRef`
-        Self { ptr: Unique::empty(), cap: 0, a }
-    }
-
-    /// Like `with_capacity`, but parameterized over the choice of
-    /// allocator for the returned `RawVec`.
-    #[inline]
-    pub fn with_capacity_in(capacity: usize, a: A) -> Self {
-        Self::allocate_in(capacity, Uninitialized, a)
-    }
-
-    /// Like `with_capacity_zeroed`, but parameterized over the choice
-    /// of allocator for the returned `RawVec`.
-    #[inline]
-    pub fn with_capacity_zeroed_in(capacity: usize, a: A) -> Self {
-        Self::allocate_in(capacity, Zeroed, a)
-    }
-
-    fn allocate_in(capacity: usize, init: AllocInit, mut a: A) -> Self {
-        let layout = Layout::array::<T>(capacity).unwrap_or_else(|_| capacity_overflow());
-        alloc_guard(layout.size()).unwrap_or_else(|_| capacity_overflow());
-
-        let (ptr, excess) = a.alloc(layout, init).unwrap_or_else(|_| handle_alloc_error(layout));
-        Self { ptr: ptr.cast().into(), cap: Self::capacity_from_bytes(excess), a }
-    }
+    alloc: A,
 }
 
 impl<T> RawVec<T, Global> {
@@ -126,23 +99,7 @@ impl<T> RawVec<T, Global> {
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         Self::with_capacity_zeroed_in(capacity, Global)
     }
-}
 
-impl<T, A: AllocRef> RawVec<T, A> {
-    /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
-    ///
-    /// # Undefined Behavior
-    ///
-    /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
-    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
-    /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
-    #[inline]
-    pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
-        Self { ptr: Unique::new_unchecked(ptr), cap: capacity, a }
-    }
-}
-
-impl<T> RawVec<T, Global> {
     /// Reconstitutes a `RawVec` from a pointer and capacity.
     ///
     /// # Undefined Behavior
@@ -166,6 +123,55 @@ impl<T> RawVec<T, Global> {
 }
 
 impl<T, A: AllocRef> RawVec<T, A> {
+    /// Like `new`, but parameterized over the choice of allocator for
+    /// the returned `RawVec`.
+    pub const fn new_in(alloc: A) -> Self {
+        // `cap: 0` means "unallocated". zero-sized types are ignored.
+        Self { ptr: Unique::empty(), cap: 0, alloc }
+    }
+
+    /// Like `with_capacity`, but parameterized over the choice of
+    /// allocator for the returned `RawVec`.
+    #[inline]
+    pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
+        Self::allocate_in(capacity, Uninitialized, alloc)
+    }
+
+    /// Like `with_capacity_zeroed`, but parameterized over the choice
+    /// of allocator for the returned `RawVec`.
+    #[inline]
+    pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
+        Self::allocate_in(capacity, Zeroed, alloc)
+    }
+
+    fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self {
+        if mem::size_of::<T>() == 0 {
+            Self::new_in(alloc)
+        } else {
+            let layout = Layout::array::<T>(capacity).unwrap_or_else(|_| capacity_overflow());
+            alloc_guard(layout.size()).unwrap_or_else(|_| capacity_overflow());
+
+            let memory = alloc.alloc(layout, init).unwrap_or_else(|_| handle_alloc_error(layout));
+            Self {
+                ptr: memory.ptr().cast().into(),
+                cap: Self::capacity_from_bytes(memory.size()),
+                alloc,
+            }
+        }
+    }
+
+    /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
+    ///
+    /// # Undefined Behavior
+    ///
+    /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
+    /// The `capacity` cannot exceed `isize::MAX` (only a concern on 32-bit systems).
+    /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
+    #[inline]
+    pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
+        Self { ptr: Unique::new_unchecked(ptr), cap: capacity, alloc: a }
+    }
+
     /// Gets a raw pointer to the start of the allocation. Note that this is
     /// `Unique::empty()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
@@ -183,16 +189,16 @@ impl<T, A: AllocRef> RawVec<T, A> {
 
     /// Returns a shared reference to the allocator backing this `RawVec`.
     pub fn alloc(&self) -> &A {
-        &self.a
+        &self.alloc
     }
 
     /// Returns a mutable reference to the allocator backing this `RawVec`.
     pub fn alloc_mut(&mut self) -> &mut A {
-        &mut self.a
+        &mut self.alloc
     }
 
-    fn current_layout(&self) -> Option<Layout> {
-        if self.cap == 0 {
+    fn current_memory(&self) -> Option<MemoryBlock> {
+        if mem::size_of::<T>() == 0 || self.cap == 0 {
             None
         } else {
             // We have an allocated chunk of memory, so we can bypass runtime
@@ -200,7 +206,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
             unsafe {
                 let align = mem::align_of::<T>();
                 let size = mem::size_of::<T>() * self.cap;
-                Some(Layout::from_size_align_unchecked(size, align))
+                let layout = Layout::from_size_align_unchecked(size, align);
+                Some(MemoryBlock::new(self.ptr.cast().into(), layout))
             }
         }
     }
@@ -454,14 +461,19 @@ impl<T, A: AllocRef> RawVec<T, A> {
     /// Returns if the buffer needs to grow to fulfill the needed extra capacity.
     /// Mainly used to make inlining reserve-calls possible without inlining `grow`.
     fn needs_to_grow(&self, used_capacity: usize, needed_extra_capacity: usize) -> bool {
-        needed_extra_capacity > self.capacity().wrapping_sub(used_capacity)
+        mem::size_of::<T>() != 0
+            && needed_extra_capacity > self.capacity().wrapping_sub(used_capacity)
     }
 
     fn capacity_from_bytes(excess: usize) -> usize {
-        match mem::size_of::<T>() {
-            0 => usize::MAX,
-            elem_size => excess / elem_size,
-        }
+        debug_assert_ne!(mem::size_of::<T>(), 0);
+        excess / mem::size_of::<T>()
+    }
+
+    fn set_memory(&mut self, memory: MemoryBlock) {
+        self.ptr = memory.ptr().cast().into();
+        self.cap = Self::capacity_from_bytes(memory.size());
+        drop(memory);
     }
 
     /// Single method to handle all possibilities of growing the buffer.
@@ -471,9 +483,9 @@ impl<T, A: AllocRef> RawVec<T, A> {
         placement: ReallocPlacement,
         init: AllocInit,
     ) -> Result<(), TryReserveError> {
-        let elem_size = mem::size_of::<T>();
-        let new_layout = match strategy {
+        let layout = match strategy {
             Double => unsafe {
+                let elem_size = mem::size_of::<T>();
                 if elem_size == 0 {
                     // Since we return a capacity of `usize::MAX` when `elem_size` is
                     // 0, getting to here necessarily means the `RawVec` is overfull.
@@ -511,24 +523,24 @@ impl<T, A: AllocRef> RawVec<T, A> {
             }
         };
 
-        let allocation = if let Some(old_layout) = self.current_layout() {
-            debug_assert!(old_layout.align() == new_layout.align());
+        let memory = if let Some(mut memory) = self.current_memory() {
+            debug_assert_eq!(memory.align(), layout.align());
             unsafe {
-                self.a.grow(self.ptr.cast().into(), old_layout, new_layout.size(), placement, init)
-            }
+                self.alloc
+                    .grow(&mut memory, layout.size(), placement, init)
+                    .map_err(|_| AllocError { layout, non_exhaustive: () })?
+            };
+            memory
         } else {
             match placement {
-                MayMove => self.a.alloc(new_layout, init),
+                MayMove => self.alloc.alloc(layout, init),
                 InPlace => Err(AllocErr),
             }
+            .map_err(|_| AllocError { layout, non_exhaustive: () })?
         };
 
-        allocation
-            .map(|(ptr, excess)| {
-                self.ptr = ptr.cast().into();
-                self.cap = Self::capacity_from_bytes(excess);
-            })
-            .map_err(|_| TryReserveError::AllocError { layout: new_layout, non_exhaustive: () })
+        self.set_memory(memory);
+        Ok(())
     }
 
     fn shrink(
@@ -538,64 +550,52 @@ impl<T, A: AllocRef> RawVec<T, A> {
     ) -> Result<(), TryReserveError> {
         assert!(amount <= self.cap, "Tried to shrink to a larger capacity");
 
-        let elem_size = mem::size_of::<T>();
-        let old_layout =
-            if let Some(layout) = self.current_layout() { layout } else { return Ok(()) };
-        let old_ptr = self.ptr.cast().into();
-        let new_size = amount * elem_size;
-
-        let allocation = unsafe {
-            if amount == 0 && placement == MayMove {
-                self.dealloc_buffer();
-                Ok((old_layout.dangling(), 0))
-            } else {
-                self.a.shrink(old_ptr, old_layout, new_size, placement)
-            }
-        };
+        let mut memory = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
+        let new_size = amount * mem::size_of::<T>();
 
-        allocation
-            .map(|(ptr, excess)| {
-                self.ptr = ptr.cast().into();
-                self.cap = Self::capacity_from_bytes(excess);
-            })
-            .map_err(|_| TryReserveError::AllocError {
-                layout: unsafe { Layout::from_size_align_unchecked(new_size, old_layout.align()) },
-                non_exhaustive: (),
-            })
+        unsafe {
+            self.alloc.shrink(&mut memory, new_size, placement).map_err(|_| {
+                TryReserveError::AllocError {
+                    layout: Layout::from_size_align_unchecked(new_size, memory.align()),
+                    non_exhaustive: (),
+                }
+            })?;
+        }
+
+        self.set_memory(memory);
+        Ok(())
     }
 }
 
 impl<T> RawVec<T, Global> {
-    /// Converts the entire buffer into `Box<[T]>`.
+    /// Converts the entire buffer into `Box<[T]>` with the specified `len`.
     ///
     /// Note that this will correctly reconstitute any `cap` changes
     /// that may have been performed. (See description of type for details.)
-    pub fn into_box(self) -> Box<[MaybeUninit<T>]> {
-        unsafe {
-            // NOTE: not calling `capacity()` here; actually using the real `cap` field!
-            let slice = slice::from_raw_parts_mut(self.ptr() as *mut MaybeUninit<T>, self.cap);
-            let output = Box::from_raw(slice);
-            mem::forget(self);
-            output
-        }
-    }
-}
+    ///
+    /// # Safety
+    ///
+    /// * `len` must be smaller than or equal to `self.capacity()`
+    pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> {
+        debug_assert!(
+            len <= self.capacity(),
+            "`len` must be smaller than or equal to `self.capacity()`"
+        );
 
-impl<T, A: AllocRef> RawVec<T, A> {
-    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
-    pub unsafe fn dealloc_buffer(&mut self) {
-        if let Some(layout) = self.current_layout() {
-            self.a.dealloc(self.ptr.cast().into(), layout);
-            self.ptr = Unique::empty();
-            self.cap = 0;
-        }
+        // NOTE: not calling `capacity()` here; actually using the real `cap` field!
+        let slice = slice::from_raw_parts_mut(self.ptr() as *mut MaybeUninit<T>, len);
+        let output = Box::from_raw(slice);
+        mem::forget(self);
+        output
     }
 }
 
 unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> {
     /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
     fn drop(&mut self) {
-        unsafe { self.dealloc_buffer() }
+        if let Some(memory) = self.current_memory() {
+            unsafe { self.alloc.dealloc(memory) }
+        }
     }
 }
 
diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs
index a2d6cc63c92..4bdd36ed63a 100644
--- a/src/liballoc/raw_vec/tests.rs
+++ b/src/liballoc/raw_vec/tests.rs
@@ -1,5 +1,4 @@
 use super::*;
-use core::ptr::NonNull;
 
 #[test]
 fn allocator_param() {
@@ -13,6 +12,7 @@ fn allocator_param() {
     //
     // Instead, this just checks that the `RawVec` methods do at
     // least go through the Allocator API when it reserves
+
     // storage.
 
     // A dumb allocator that consumes a fixed amount of fuel
@@ -21,11 +21,7 @@ fn allocator_param() {
         fuel: usize,
     }
     unsafe impl AllocRef for BoundedAlloc {
-        fn alloc(
-            &mut self,
-            layout: Layout,
-            init: AllocInit,
-        ) -> Result<(NonNull<u8>, usize), AllocErr> {
+        fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
             let size = layout.size();
             if size > self.fuel {
                 return Err(AllocErr);
@@ -38,16 +34,16 @@ fn allocator_param() {
                 err @ Err(_) => err,
             }
         }
-        unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
-            Global.dealloc(ptr, layout)
+        unsafe fn dealloc(&mut self, memory: MemoryBlock) {
+            Global.dealloc(memory)
         }
     }
 
     let a = BoundedAlloc { fuel: 500 };
     let mut v: RawVec<u8, _> = RawVec::with_capacity_in(50, a);
-    assert_eq!(v.a.fuel, 450);
+    assert_eq!(v.alloc.fuel, 450);
     v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel)
-    assert_eq!(v.a.fuel, 250);
+    assert_eq!(v.alloc.fuel, 250);
 }
 
 #[test]
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 495e196df40..3625caf5f23 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -234,6 +234,7 @@ use crate::boxed::Box;
 #[cfg(test)]
 use std::boxed::Box;
 
+use core::alloc::MemoryBlock;
 use core::any::Any;
 use core::array::LengthAtMost32;
 use core::borrow;
@@ -936,12 +937,12 @@ impl<T: ?Sized> Rc<T> {
         let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
 
         // Allocate for the layout.
-        let (mem, _) = Global
+        let mem = Global
             .alloc(layout, AllocInit::Uninitialized)
             .unwrap_or_else(|_| handle_alloc_error(layout));
 
         // Initialize the RcBox
-        let inner = mem_to_rcbox(mem.as_ptr());
+        let inner = mem_to_rcbox(mem.ptr().as_ptr());
         debug_assert_eq!(Layout::for_value(&*inner), layout);
 
         ptr::write(&mut (*inner).strong, Cell::new(1));
@@ -1031,7 +1032,7 @@ impl<T> Rc<[T]> {
                     let slice = from_raw_parts_mut(self.elems, self.n_elems);
                     ptr::drop_in_place(slice);
 
-                    Global.dealloc(self.mem, self.layout);
+                    Global.dealloc(MemoryBlock::new(self.mem, self.layout));
                 }
             }
         }
@@ -1131,7 +1132,10 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
                 self.dec_weak();
 
                 if self.weak() == 0 {
-                    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
+                    Global.dealloc(MemoryBlock::new(
+                        self.ptr.cast(),
+                        Layout::for_value(self.ptr.as_ref()),
+                    ));
                 }
             }
         }
@@ -1939,7 +1943,10 @@ impl<T: ?Sized> Drop for Weak<T> {
             // the strong pointers have disappeared.
             if inner.weak() == 0 {
                 unsafe {
-                    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
+                    Global.dealloc(MemoryBlock::new(
+                        self.ptr.cast(),
+                        Layout::for_value(self.ptr.as_ref()),
+                    ));
                 }
             }
         }
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 048c89d1280..b5e6d669f80 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -6,6 +6,7 @@
 //!
 //! [arc]: struct.Arc.html
 
+use core::alloc::MemoryBlock;
 use core::any::Any;
 use core::array::LengthAtMost32;
 use core::borrow;
@@ -770,7 +771,7 @@ impl<T: ?Sized> Arc<T> {
 
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             acquire!(self.inner().weak);
-            Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
+            Global.dealloc(MemoryBlock::new(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())))
         }
     }
 
@@ -814,12 +815,12 @@ impl<T: ?Sized> Arc<T> {
         // reference (see #54908).
         let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align();
 
-        let (mem, _) = Global
+        let mem = Global
             .alloc(layout, AllocInit::Uninitialized)
             .unwrap_or_else(|_| handle_alloc_error(layout));
 
         // Initialize the ArcInner
-        let inner = mem_to_arcinner(mem.as_ptr());
+        let inner = mem_to_arcinner(mem.ptr().as_ptr());
         debug_assert_eq!(Layout::for_value(&*inner), layout);
 
         ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
@@ -909,7 +910,7 @@ impl<T> Arc<[T]> {
                     let slice = from_raw_parts_mut(self.elems, self.n_elems);
                     ptr::drop_in_place(slice);
 
-                    Global.dealloc(self.mem.cast(), self.layout);
+                    Global.dealloc(MemoryBlock::new(self.mem.cast(), self.layout));
                 }
             }
         }
@@ -1734,7 +1735,12 @@ impl<T: ?Sized> Drop for Weak<T> {
 
         if inner.weak.fetch_sub(1, Release) == 1 {
             acquire!(inner.weak);
-            unsafe { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) }
+            unsafe {
+                Global.dealloc(MemoryBlock::new(
+                    self.ptr.cast(),
+                    Layout::for_value(self.ptr.as_ref()),
+                ))
+            }
         }
     }
 }
diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs
index 690ae84a5df..4b0d7bc1f44 100644
--- a/src/liballoc/tests/heap.rs
+++ b/src/liballoc/tests/heap.rs
@@ -1,4 +1,4 @@
-use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
+use std::alloc::{AllocInit, AllocRef, Global, Layout, MemoryBlock, System};
 
 /// Issue #45955 and #62251.
 #[test]
@@ -26,7 +26,7 @@ fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
                                 AllocInit::Uninitialized,
                             )
                             .unwrap()
-                            .0
+                            .ptr()
                     })
                     .collect();
                 for &ptr in &pointers {
@@ -39,7 +39,10 @@ fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
 
                 // Clean up
                 for &ptr in &pointers {
-                    allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
+                    allocator.dealloc(MemoryBlock::new(
+                        ptr,
+                        Layout::from_size_align(size, align).unwrap(),
+                    ))
                 }
             }
         }
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 528a4f73293..ba49f043d46 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -678,8 +678,9 @@ impl<T> Vec<T> {
         unsafe {
             self.shrink_to_fit();
             let buf = ptr::read(&self.buf);
+            let len = self.len();
             mem::forget(self);
-            buf.into_box().assume_init()
+            buf.into_box(len).assume_init()
         }
     }