mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Add the Layout of the failed allocation to TryReserveError::AllocError
… and add a separately-unstable field to force non-exhaustive matching (`#[non_exhaustive]` is no implemented yet on enum variants) so that we have the option to later expose the allocator’s error value. CC https://github.com/rust-lang/wg-allocators/issues/23
This commit is contained in:
parent
a92c29b238
commit
59a340963f
@ -41,25 +41,28 @@ pub use linked_list::LinkedList;
|
||||
#[doc(no_inline)]
|
||||
pub use vec_deque::VecDeque;
|
||||
|
||||
use crate::alloc::{AllocErr, LayoutErr};
|
||||
use crate::alloc::{Layout, LayoutErr};
|
||||
|
||||
/// Augments `AllocErr` with a CapacityOverflow variant.
|
||||
/// The error type for `try_reserve` methods.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub enum TryReserveError {
|
||||
/// 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,
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
impl From<AllocErr> for TryReserveError {
|
||||
#[inline]
|
||||
fn from(AllocErr: AllocErr) -> Self {
|
||||
TryReserveError::AllocErr
|
||||
}
|
||||
/// The memory allocator returned an error
|
||||
AllocError {
|
||||
/// The layout of allocation request that failed
|
||||
layout: Layout,
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "container_error_extra", issue = "0", reason = "\
|
||||
Enable exposing the allocator’s custom error value \
|
||||
if an associated type is added in the future: \
|
||||
https://github.com/rust-lang/wg-allocators/issues/23")]
|
||||
non_exhaustive: (),
|
||||
},
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
|
@ -87,6 +87,7 @@
|
||||
#![feature(const_in_array_repeat_expressions)]
|
||||
#![feature(dispatch_from_dyn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(container_error_extra)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(fmt_internals)]
|
||||
|
@ -7,7 +7,7 @@ use core::ops::Drop;
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::slice;
|
||||
|
||||
use crate::alloc::{Alloc, Layout, Global, handle_alloc_error};
|
||||
use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error};
|
||||
use crate::collections::TryReserveError::{self, *};
|
||||
use crate::boxed::Box;
|
||||
|
||||
@ -413,7 +413,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocErr) => unreachable!(),
|
||||
Err(AllocError { .. }) => unreachable!(),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
@ -494,7 +494,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Amortized) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocErr) => unreachable!(),
|
||||
Err(AllocError { .. }) => unreachable!(),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
@ -642,8 +642,6 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
strategy: ReserveStrategy,
|
||||
) -> Result<(), TryReserveError> {
|
||||
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
|
||||
@ -672,12 +670,16 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
None => self.a.alloc(new_layout),
|
||||
};
|
||||
|
||||
match (&res, fallibility) {
|
||||
let ptr = match (res, fallibility) {
|
||||
(Err(AllocErr), Infallible) => handle_alloc_error(new_layout),
|
||||
_ => {}
|
||||
}
|
||||
(Err(AllocErr), Fallible) => return Err(TryReserveError::AllocError {
|
||||
layout: new_layout,
|
||||
non_exhaustive: (),
|
||||
}),
|
||||
(Ok(ptr), _) => ptr,
|
||||
};
|
||||
|
||||
self.ptr = res?.cast().into();
|
||||
self.ptr = ptr.cast().into();
|
||||
self.cap = new_cap;
|
||||
|
||||
Ok(())
|
||||
|
@ -566,11 +566,11 @@ fn test_try_reserve() {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
// Check isize::MAX + 1 is an OOM
|
||||
if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
// Check usize::MAX is an OOM
|
||||
if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -590,7 +590,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -629,10 +629,10 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -651,7 +651,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
|
@ -1121,11 +1121,11 @@ fn test_try_reserve() {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
// Check isize::MAX + 1 is an OOM
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
// Check usize::MAX is an OOM
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1145,7 +1145,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -1168,7 +1168,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should fail in the mul-by-size
|
||||
@ -1209,10 +1209,10 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an overflow!") }
|
||||
} else {
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
} else { panic!("usize::MAX should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1231,7 +1231,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
@ -1252,7 +1252,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {
|
||||
|
@ -1168,7 +1168,7 @@ fn test_try_reserve() {
|
||||
// VecDeque starts with capacity 7, always adds 1 to the capacity
|
||||
// and also rounds the number to next power of 2 so this is the
|
||||
// furthest we can go without triggering CapacityOverflow
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1188,7 +1188,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should always overflow in the add-to-len
|
||||
@ -1211,7 +1211,7 @@ fn test_try_reserve() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
// Should fail in the mul-by-size
|
||||
@ -1256,7 +1256,7 @@ fn test_try_reserve_exact() {
|
||||
// VecDeque starts with capacity 7, always adds 1 to the capacity
|
||||
// and also rounds the number to next power of 2 so this is the
|
||||
// furthest we can go without triggering CapacityOverflow
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
}
|
||||
@ -1275,7 +1275,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
|
||||
@ -1296,7 +1296,7 @@ fn test_try_reserve_exact() {
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
|
||||
} else {
|
||||
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
|
||||
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
|
||||
}
|
||||
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {
|
||||
|
@ -2545,7 +2545,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K,
|
||||
fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError {
|
||||
match err {
|
||||
hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow,
|
||||
hashbrown::CollectionAllocErr::AllocErr { .. } => TryReserveError::AllocErr,
|
||||
hashbrown::CollectionAllocErr::AllocErr { layout } => TryReserveError::AllocError {
|
||||
layout,
|
||||
non_exhaustive: (),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -3405,7 +3408,7 @@ mod test_map {
|
||||
panic!("usize::MAX should trigger an overflow!");
|
||||
}
|
||||
|
||||
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE / 8) {
|
||||
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
|
||||
} else {
|
||||
panic!("usize::MAX / 8 should trigger an OOM!")
|
||||
}
|
||||
|
@ -251,6 +251,7 @@
|
||||
#![feature(concat_idents)]
|
||||
#![feature(const_cstr_unchecked)]
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(container_error_extra)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(custom_test_frameworks)]
|
||||
#![feature(doc_alias)]
|
||||
|
Loading…
Reference in New Issue
Block a user