Skip to content

Commit aec047e

Browse files
authored
Rollup merge of rust-lang#61780 - SimonSapin:container-error, r=Amanieu
Finalize the error type for `try_reserve` See tracking issue comments from rust-lang#48043 (comment). It is now: ```rust /// 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, /// 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: \ rust-lang/wg-allocators#23")] non_exhaustive: (), }, } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] impl From<LayoutErr> for TryReserveError { #[inline] fn from(_: LayoutErr) -> Self { TryReserveError::CapacityOverflow } } ``` Changes: * A `Layout` is included. Firefox wants to log the size of failed allocations. If this were not part of the return value of e.g. `HashMap::try_reserve`, users would only be able to estimate based on `HashMap::capacity` and assumptions about the allocation strategy of `HashMap`. * There’s a dummy field that can stay unstable when `try_reserve` and the rest of this enum are stabilized. This forces non-exhaustive matching ~(rust-lang#44109 is not implemented yet for variants)~ and allows adding another field in the future if we want to expose custom error values from the allocator. See rust-lang/wg-allocators#23. - If the `Alloc` trait is stabilized without an associated error type and with a zero-size `AllocErr` type, we can simply remove this dummy field. - If an associated type is added, we can add a default type parameter to `ContainerError` and a generic field to the `AllocError` variant. * ~Moved from the `collections` module to the `alloc` module, and replaced `Collection` in the enum name with `Container`. The wold collection implies a multiplicity of items which is not relevant to this type. For example we may want to use this error type in a future `Box::try_new` method.~ - Renamed to `TryReserveError`, after the methods that involve this type: rust-lang#61780 (comment) * Replaced `Err` with `Error` in the enum and variant names. There is more precedent for this in https://doc.rust-lang.org/std/error/trait.Error.html#implementors, `AllocErr` and `LayoutErr` are the odd ones. * ~Dropped `Alloc` in the enum name. `ContainerAllocError` with a mouthful, and being in the `alloc` module already provides the same indication.~
2 parents e632daf + 59a3409 commit aec047e

File tree

15 files changed

+97
-95
lines changed

15 files changed

+97
-95
lines changed

Cargo.lock

+2-10
Original file line numberDiff line numberDiff line change
@@ -1138,19 +1138,12 @@ dependencies = [
11381138

11391139
[[package]]
11401140
name = "hashbrown"
1141-
version = "0.4.0"
1141+
version = "0.5.0"
11421142
source = "registry+https://github.com/rust-lang/crates.io-index"
11431143
dependencies = [
11441144
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
11451145
"rustc-std-workspace-alloc 1.0.0",
11461146
"rustc-std-workspace-core 1.0.0",
1147-
]
1148-
1149-
[[package]]
1150-
name = "hashbrown"
1151-
version = "0.5.0"
1152-
source = "registry+https://github.com/rust-lang/crates.io-index"
1153-
dependencies = [
11541147
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
11551148
]
11561149

@@ -3534,7 +3527,7 @@ dependencies = [
35343527
"core 0.0.0",
35353528
"dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
35363529
"fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
3537-
"hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
3530+
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
35383531
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
35393532
"panic_abort 0.0.0",
35403533
"panic_unwind 0.0.0",
@@ -4450,7 +4443,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
44504443
"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"
44514444
"checksum h2 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392"
44524445
"checksum handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
4453-
"checksum hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9529213c67695ca2d146e6f263b7b72df8fa973368beadf767e8ed80c03f2f36"
44544446
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
44554447
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
44564448
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"

src/liballoc/collections/mod.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,35 @@ 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")]
49-
pub enum CollectionAllocErr {
49+
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 CollectionAllocErr {
59-
#[inline]
60-
fn from(AllocErr: AllocErr) -> Self {
61-
CollectionAllocErr::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")]
66-
impl From<LayoutErr> for CollectionAllocErr {
69+
impl From<LayoutErr> for TryReserveError {
6770
#[inline]
6871
fn from(_: LayoutErr) -> Self {
69-
CollectionAllocErr::CapacityOverflow
72+
TryReserveError::CapacityOverflow
7073
}
7174
}
7275

src/liballoc/collections/vec_deque.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use core::ptr::{self, NonNull};
1818
use core::slice;
1919
use core::hash::{Hash, Hasher};
2020

21-
use crate::collections::CollectionAllocErr;
21+
use crate::collections::TryReserveError;
2222
use crate::raw_vec::RawVec;
2323
use crate::vec::Vec;
2424

@@ -576,10 +576,10 @@ impl<T> VecDeque<T> {
576576
///
577577
/// ```
578578
/// #![feature(try_reserve)]
579-
/// use std::collections::CollectionAllocErr;
579+
/// use std::collections::TryReserveError;
580580
/// use std::collections::VecDeque;
581581
///
582-
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
582+
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
583583
/// let mut output = VecDeque::new();
584584
///
585585
/// // Pre-reserve the memory, exiting if we can't
@@ -595,7 +595,7 @@ impl<T> VecDeque<T> {
595595
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
596596
/// ```
597597
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
598-
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
598+
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
599599
self.try_reserve(additional)
600600
}
601601

@@ -614,10 +614,10 @@ impl<T> VecDeque<T> {
614614
///
615615
/// ```
616616
/// #![feature(try_reserve)]
617-
/// use std::collections::CollectionAllocErr;
617+
/// use std::collections::TryReserveError;
618618
/// use std::collections::VecDeque;
619619
///
620-
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
620+
/// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
621621
/// let mut output = VecDeque::new();
622622
///
623623
/// // Pre-reserve the memory, exiting if we can't
@@ -633,12 +633,12 @@ impl<T> VecDeque<T> {
633633
/// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
634634
/// ```
635635
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
636-
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
636+
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
637637
let old_cap = self.cap();
638638
let used_cap = self.len() + 1;
639639
let new_cap = used_cap.checked_add(additional)
640640
.and_then(|needed_cap| needed_cap.checked_next_power_of_two())
641-
.ok_or(CollectionAllocErr::CapacityOverflow)?;
641+
.ok_or(TryReserveError::CapacityOverflow)?;
642642

643643
if new_cap > old_cap {
644644
self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?;

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

+17-15
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ 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};
11-
use crate::collections::CollectionAllocErr::{self, *};
10+
use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error};
11+
use crate::collections::TryReserveError::{self, *};
1212
use crate::boxed::Box;
1313

1414
#[cfg(test)]
@@ -385,7 +385,7 @@ impl<T, A: Alloc> RawVec<T, A> {
385385

386386
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
387387
pub fn try_reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize)
388-
-> Result<(), CollectionAllocErr> {
388+
-> Result<(), TryReserveError> {
389389

390390
self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Exact)
391391
}
@@ -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
}
@@ -422,7 +422,7 @@ impl<T, A: Alloc> RawVec<T, A> {
422422
/// needed_extra_capacity` elements. This logic is used in amortized reserve methods.
423423
/// Returns `(new_capacity, new_alloc_size)`.
424424
fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize)
425-
-> Result<usize, CollectionAllocErr> {
425+
-> Result<usize, TryReserveError> {
426426

427427
// Nothing we can really do about these checks :(
428428
let required_cap = used_capacity.checked_add(needed_extra_capacity)
@@ -435,7 +435,7 @@ impl<T, A: Alloc> RawVec<T, A> {
435435

436436
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
437437
pub fn try_reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize)
438-
-> Result<(), CollectionAllocErr> {
438+
-> Result<(), TryReserveError> {
439439
self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Amortized)
440440
}
441441

@@ -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
}
@@ -640,10 +640,8 @@ impl<T, A: Alloc> RawVec<T, A> {
640640
needed_extra_capacity: usize,
641641
fallibility: Fallibility,
642642
strategy: ReserveStrategy,
643-
) -> Result<(), CollectionAllocErr> {
643+
) -> 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(())
@@ -737,7 +739,7 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec<T, A> {
737739
// all 4GB in user-space. e.g., PAE or x32
738740

739741
#[inline]
740-
fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> {
742+
fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
741743
if mem::size_of::<usize>() < 8 && alloc_size > core::isize::MAX as usize {
742744
Err(CapacityOverflow)
743745
} else {

src/liballoc/string.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use core::ptr;
5656
use core::str::{pattern::Pattern, lossy};
5757

5858
use crate::borrow::{Cow, ToOwned};
59-
use crate::collections::CollectionAllocErr;
59+
use crate::collections::TryReserveError;
6060
use crate::boxed::Box;
6161
use crate::str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars};
6262
use crate::vec::Vec;
@@ -937,9 +937,9 @@ impl String {
937937
///
938938
/// ```
939939
/// #![feature(try_reserve)]
940-
/// use std::collections::CollectionAllocErr;
940+
/// use std::collections::TryReserveError;
941941
///
942-
/// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
942+
/// fn process_data(data: &str) -> Result<String, TryReserveError> {
943943
/// let mut output = String::new();
944944
///
945945
/// // Pre-reserve the memory, exiting if we can't
@@ -953,7 +953,7 @@ impl String {
953953
/// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
954954
/// ```
955955
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
956-
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
956+
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
957957
self.vec.try_reserve(additional)
958958
}
959959

@@ -975,9 +975,9 @@ impl String {
975975
///
976976
/// ```
977977
/// #![feature(try_reserve)]
978-
/// use std::collections::CollectionAllocErr;
978+
/// use std::collections::TryReserveError;
979979
///
980-
/// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
980+
/// fn process_data(data: &str) -> Result<String, TryReserveError> {
981981
/// let mut output = String::new();
982982
///
983983
/// // Pre-reserve the memory, exiting if we can't
@@ -991,7 +991,7 @@ impl String {
991991
/// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
992992
/// ```
993993
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
994-
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
994+
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
995995
self.vec.try_reserve_exact(additional)
996996
}
997997

src/liballoc/tests/string.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::borrow::Cow;
2-
use std::collections::CollectionAllocErr::*;
2+
use std::collections::TryReserveError::*;
33
use std::mem::size_of;
44
use std::{usize, isize};
55

@@ -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) {

0 commit comments

Comments
 (0)