Skip to content

Remove helper-methods from Alloc trait and add associated Err type. #60771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
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: 2 additions & 0 deletions src/liballoc/alloc.rs
Original file line number Diff line number Diff line change
@@ -146,6 +146,8 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global {
type Err = AllocErr;

#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(alloc(layout)).ok_or(AllocErr)
8 changes: 4 additions & 4 deletions src/liballoc/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -46,24 +46,24 @@ use crate::alloc::{AllocErr, LayoutErr};
/// Augments `AllocErr` with a CapacityOverflow variant.
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub enum CollectionAllocErr {
pub enum CollectionAllocErr<E = AllocErr> {
/// Error due to the computed capacity exceeding the collection's maximum
/// (usually `isize::MAX` bytes).
CapacityOverflow,
/// Error due to the allocator (see the `AllocErr` type's docs).
AllocErr,
AllocErr(E),
}

#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
impl From<AllocErr> for CollectionAllocErr {
#[inline]
fn from(AllocErr: AllocErr) -> Self {
CollectionAllocErr::AllocErr
CollectionAllocErr::AllocErr(AllocErr)
}
}

#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
impl From<LayoutErr> for CollectionAllocErr {
impl<E> From<LayoutErr> for CollectionAllocErr<E> {
#[inline]
fn from(_: LayoutErr) -> Self {
CollectionAllocErr::CapacityOverflow
37 changes: 19 additions & 18 deletions src/liballoc/raw_vec.rs
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let elem_size = mem::size_of::<T>();

let alloc_size = cap.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow());
alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow());
alloc_guard::<A::Err>(alloc_size).unwrap_or_else(|_| capacity_overflow());

// handles ZSTs and `cap = 0` alike
let ptr = if alloc_size == 0 {
@@ -305,7 +305,7 @@ impl<T, A: Alloc> RawVec<T, A> {
// `from_size_align_unchecked`.
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
alloc_guard::<A::Err>(new_size).unwrap_or_else(|_| capacity_overflow());
let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(),
cur,
new_size);
@@ -320,9 +320,12 @@ impl<T, A: Alloc> RawVec<T, A> {
// skip to 4 because tiny Vec's are dumb; but not if that
// would cause overflow
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
match self.a.alloc_array::<T>(new_cap) {
Ok(ptr) => (new_cap, ptr.into()),
Err(_) => handle_alloc_error(Layout::array::<T>(new_cap).unwrap()),
let layout = Layout::array::<T>(new_cap)
.expect("unable to create array layout");

match self.a.alloc(layout) {
Ok(ptr) => (new_cap, ptr.cast().into()),
Err(_) => handle_alloc_error(layout),
}
}
};
@@ -366,7 +369,7 @@ impl<T, A: Alloc> RawVec<T, A> {
// overflow and the alignment is sufficiently small.
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
alloc_guard::<A::Err>(new_size).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) {
Ok(_) => {
// We can't directly divide `size`.
@@ -382,7 +385,7 @@ impl<T, A: Alloc> RawVec<T, A> {

/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
-> Result<(), CollectionAllocErr<A::Err>> {

self.reserve_internal(used_cap, needed_extra_cap, Fallible, Exact)
}
@@ -410,7 +413,7 @@ impl<T, A: Alloc> RawVec<T, A> {
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Exact) {
Err(CapacityOverflow) => capacity_overflow(),
Err(AllocErr) => unreachable!(),
Err(AllocErr(_)) => unreachable!(),
Ok(()) => { /* yay */ }
}
}
@@ -419,7 +422,7 @@ impl<T, A: Alloc> RawVec<T, A> {
/// needed_extra_cap` elements. This logic is used in amortized reserve methods.
/// Returns `(new_capacity, new_alloc_size)`.
fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize)
-> Result<usize, CollectionAllocErr> {
-> Result<usize, CollectionAllocErr<A::Err>> {

// Nothing we can really do about these checks :(
let required_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?;
@@ -431,7 +434,7 @@ impl<T, A: Alloc> RawVec<T, A> {

/// The same as `reserve`, but returns on errors instead of panicking or aborting.
pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
-> Result<(), CollectionAllocErr<A::Err>> {
self.reserve_internal(used_cap, needed_extra_cap, Fallible, Amortized)
}

@@ -490,7 +493,7 @@ impl<T, A: Alloc> RawVec<T, A> {
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Amortized) {
Err(CapacityOverflow) => capacity_overflow(),
Err(AllocErr) => unreachable!(),
Err(AllocErr(_)) => unreachable!(),
Ok(()) => { /* yay */ }
}
}
@@ -538,7 +541,7 @@ impl<T, A: Alloc> RawVec<T, A> {

let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
// FIXME: may crash and burn on over-reserve
alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
alloc_guard::<A::Err>(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place(
NonNull::from(self.ptr).cast(), old_layout, new_layout.size(),
) {
@@ -636,10 +639,8 @@ impl<T, A: Alloc> RawVec<T, A> {
needed_extra_cap: usize,
fallibility: Fallibility,
strategy: ReserveStrategy,
) -> Result<(), CollectionAllocErr> {
) -> Result<(), CollectionAllocErr<A::Err>> {
unsafe {
use crate::alloc::AllocErr;

// NOTE: we don't early branch on ZSTs here because we want this
// to actually catch "asking for more than usize::MAX" in that case.
// If we make it past the first branch then we are guaranteed to
@@ -669,11 +670,11 @@ impl<T, A: Alloc> RawVec<T, A> {
};

match (&res, fallibility) {
(Err(AllocErr), Infallible) => handle_alloc_error(new_layout),
(Err(_), Infallible) => handle_alloc_error(new_layout),
_ => {}
}

self.ptr = res?.cast().into();
self.ptr = res.map_err(|e| CollectionAllocErr::AllocErr(e))?.cast().into();
self.cap = new_cap;

Ok(())
@@ -731,7 +732,7 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
// all 4GB in user-space. e.g., PAE or x32

#[inline]
fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> {
fn alloc_guard<E>(alloc_size: usize) -> Result<(), CollectionAllocErr<E>> {
if mem::size_of::<usize>() < 8 && alloc_size > core::isize::MAX as usize {
Err(CapacityOverflow)
} else {
Loading