Skip to content

Commit 59a3409

Browse files
committed
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 rust-lang/wg-allocators#23
1 parent a92c29b commit 59a3409

File tree

8 files changed

+52
-42
lines changed

8 files changed

+52
-42
lines changed

src/liballoc/collections/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,28 @@ pub use linked_list::LinkedList;
4141
#[doc(no_inline)]
4242
pub use vec_deque::VecDeque;
4343

44-
use crate::alloc::{AllocErr, LayoutErr};
44+
use crate::alloc::{Layout, LayoutErr};
4545

46-
/// Augments `AllocErr` with a CapacityOverflow variant.
46+
/// The error type for `try_reserve` methods.
4747
#[derive(Clone, PartialEq, Eq, Debug)]
4848
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
4949
pub enum TryReserveError {
5050
/// Error due to the computed capacity exceeding the collection's maximum
5151
/// (usually `isize::MAX` bytes).
5252
CapacityOverflow,
53-
/// Error due to the allocator (see the `AllocErr` type's docs).
54-
AllocErr,
55-
}
5653

57-
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
58-
impl From<AllocErr> for TryReserveError {
59-
#[inline]
60-
fn from(AllocErr: AllocErr) -> Self {
61-
TryReserveError::AllocErr
62-
}
54+
/// The memory allocator returned an error
55+
AllocError {
56+
/// The layout of allocation request that failed
57+
layout: Layout,
58+
59+
#[doc(hidden)]
60+
#[unstable(feature = "container_error_extra", issue = "0", reason = "\
61+
Enable exposing the allocator’s custom error value \
62+
if an associated type is added in the future: \
63+
https://github.com/rust-lang/wg-allocators/issues/23")]
64+
non_exhaustive: (),
65+
},
6366
}
6467

6568
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
#![feature(const_in_array_repeat_expressions)]
8888
#![feature(dispatch_from_dyn)]
8989
#![feature(core_intrinsics)]
90+
#![feature(container_error_extra)]
9091
#![feature(dropck_eyepatch)]
9192
#![feature(exact_size_is_empty)]
9293
#![feature(fmt_internals)]

src/liballoc/raw_vec.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use core::ops::Drop;
77
use core::ptr::{self, NonNull, Unique};
88
use core::slice;
99

10-
use crate::alloc::{Alloc, Layout, Global, handle_alloc_error};
10+
use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error};
1111
use crate::collections::TryReserveError::{self, *};
1212
use crate::boxed::Box;
1313

@@ -413,7 +413,7 @@ impl<T, A: Alloc> RawVec<T, A> {
413413
pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
414414
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Exact) {
415415
Err(CapacityOverflow) => capacity_overflow(),
416-
Err(AllocErr) => unreachable!(),
416+
Err(AllocError { .. }) => unreachable!(),
417417
Ok(()) => { /* yay */ }
418418
}
419419
}
@@ -494,7 +494,7 @@ impl<T, A: Alloc> RawVec<T, A> {
494494
pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
495495
match self.reserve_internal(used_capacity, needed_extra_capacity, Infallible, Amortized) {
496496
Err(CapacityOverflow) => capacity_overflow(),
497-
Err(AllocErr) => unreachable!(),
497+
Err(AllocError { .. }) => unreachable!(),
498498
Ok(()) => { /* yay */ }
499499
}
500500
}
@@ -642,8 +642,6 @@ impl<T, A: Alloc> RawVec<T, A> {
642642
strategy: ReserveStrategy,
643643
) -> Result<(), TryReserveError> {
644644
unsafe {
645-
use crate::alloc::AllocErr;
646-
647645
// NOTE: we don't early branch on ZSTs here because we want this
648646
// to actually catch "asking for more than usize::MAX" in that case.
649647
// If we make it past the first branch then we are guaranteed to
@@ -672,12 +670,16 @@ impl<T, A: Alloc> RawVec<T, A> {
672670
None => self.a.alloc(new_layout),
673671
};
674672

675-
match (&res, fallibility) {
673+
let ptr = match (res, fallibility) {
676674
(Err(AllocErr), Infallible) => handle_alloc_error(new_layout),
677-
_ => {}
678-
}
675+
(Err(AllocErr), Fallible) => return Err(TryReserveError::AllocError {
676+
layout: new_layout,
677+
non_exhaustive: (),
678+
}),
679+
(Ok(ptr), _) => ptr,
680+
};
679681

680-
self.ptr = res?.cast().into();
682+
self.ptr = ptr.cast().into();
681683
self.cap = new_cap;
682684

683685
Ok(())

src/liballoc/tests/string.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,11 @@ fn test_try_reserve() {
566566
} else { panic!("usize::MAX should trigger an overflow!") }
567567
} else {
568568
// Check isize::MAX + 1 is an OOM
569-
if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) {
569+
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) {
570570
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
571571

572572
// Check usize::MAX is an OOM
573-
if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) {
573+
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) {
574574
} else { panic!("usize::MAX should trigger an OOM!") }
575575
}
576576
}
@@ -590,7 +590,7 @@ fn test_try_reserve() {
590590
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
591591
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
592592
} else {
593-
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
593+
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
594594
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
595595
}
596596
// Should always overflow in the add-to-len
@@ -629,10 +629,10 @@ fn test_try_reserve_exact() {
629629
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) {
630630
} else { panic!("usize::MAX should trigger an overflow!") }
631631
} else {
632-
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) {
632+
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) {
633633
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
634634

635-
if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) {
635+
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) {
636636
} else { panic!("usize::MAX should trigger an OOM!") }
637637
}
638638
}
@@ -651,7 +651,7 @@ fn test_try_reserve_exact() {
651651
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
652652
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
653653
} else {
654-
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
654+
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
655655
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
656656
}
657657
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {

src/liballoc/tests/vec.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1121,11 +1121,11 @@ fn test_try_reserve() {
11211121
} else { panic!("usize::MAX should trigger an overflow!") }
11221122
} else {
11231123
// Check isize::MAX + 1 is an OOM
1124-
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) {
1124+
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) {
11251125
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
11261126

11271127
// Check usize::MAX is an OOM
1128-
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) {
1128+
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) {
11291129
} else { panic!("usize::MAX should trigger an OOM!") }
11301130
}
11311131
}
@@ -1145,7 +1145,7 @@ fn test_try_reserve() {
11451145
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
11461146
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
11471147
} else {
1148-
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
1148+
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
11491149
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
11501150
}
11511151
// Should always overflow in the add-to-len
@@ -1168,7 +1168,7 @@ fn test_try_reserve() {
11681168
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
11691169
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
11701170
} else {
1171-
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
1171+
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
11721172
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
11731173
}
11741174
// Should fail in the mul-by-size
@@ -1209,10 +1209,10 @@ fn test_try_reserve_exact() {
12091209
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) {
12101210
} else { panic!("usize::MAX should trigger an overflow!") }
12111211
} else {
1212-
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
1212+
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) {
12131213
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12141214

1215-
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) {
1215+
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) {
12161216
} else { panic!("usize::MAX should trigger an OOM!") }
12171217
}
12181218
}
@@ -1231,7 +1231,7 @@ fn test_try_reserve_exact() {
12311231
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
12321232
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
12331233
} else {
1234-
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
1234+
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
12351235
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12361236
}
12371237
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
@@ -1252,7 +1252,7 @@ fn test_try_reserve_exact() {
12521252
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
12531253
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
12541254
} else {
1255-
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
1255+
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
12561256
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12571257
}
12581258
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {

src/liballoc/tests/vec_deque.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ fn test_try_reserve() {
11681168
// VecDeque starts with capacity 7, always adds 1 to the capacity
11691169
// and also rounds the number to next power of 2 so this is the
11701170
// furthest we can go without triggering CapacityOverflow
1171-
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) {
1171+
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) {
11721172
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
11731173
}
11741174
}
@@ -1188,7 +1188,7 @@ fn test_try_reserve() {
11881188
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) {
11891189
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
11901190
} else {
1191-
if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) {
1191+
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) {
11921192
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
11931193
}
11941194
// Should always overflow in the add-to-len
@@ -1211,7 +1211,7 @@ fn test_try_reserve() {
12111211
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
12121212
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
12131213
} else {
1214-
if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
1214+
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP/4 - 9) {
12151215
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12161216
}
12171217
// Should fail in the mul-by-size
@@ -1256,7 +1256,7 @@ fn test_try_reserve_exact() {
12561256
// VecDeque starts with capacity 7, always adds 1 to the capacity
12571257
// and also rounds the number to next power of 2 so this is the
12581258
// furthest we can go without triggering CapacityOverflow
1259-
if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) {
1259+
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) {
12601260
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12611261
}
12621262
}
@@ -1275,7 +1275,7 @@ fn test_try_reserve_exact() {
12751275
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
12761276
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
12771277
} else {
1278-
if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
1278+
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) {
12791279
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
12801280
}
12811281
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) {
@@ -1296,7 +1296,7 @@ fn test_try_reserve_exact() {
12961296
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
12971297
} else { panic!("isize::MAX + 1 should trigger an overflow!"); }
12981298
} else {
1299-
if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
1299+
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) {
13001300
} else { panic!("isize::MAX + 1 should trigger an OOM!") }
13011301
}
13021302
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) {

src/libstd/collections/hash/map.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2545,7 +2545,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K,
25452545
fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError {
25462546
match err {
25472547
hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow,
2548-
hashbrown::CollectionAllocErr::AllocErr { .. } => TryReserveError::AllocErr,
2548+
hashbrown::CollectionAllocErr::AllocErr { layout } => TryReserveError::AllocError {
2549+
layout,
2550+
non_exhaustive: (),
2551+
},
25492552
}
25502553
}
25512554

@@ -3405,7 +3408,7 @@ mod test_map {
34053408
panic!("usize::MAX should trigger an overflow!");
34063409
}
34073410

3408-
if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE / 8) {
3411+
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
34093412
} else {
34103413
panic!("usize::MAX / 8 should trigger an OOM!")
34113414
}

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
#![feature(concat_idents)]
252252
#![feature(const_cstr_unchecked)]
253253
#![feature(const_raw_ptr_deref)]
254+
#![feature(container_error_extra)]
254255
#![feature(core_intrinsics)]
255256
#![feature(custom_test_frameworks)]
256257
#![feature(doc_alias)]

0 commit comments

Comments
 (0)