about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-16 18:22:21 +0200
committerGitHub <noreply@github.com>2019-08-16 18:22:21 +0200
commitaec047edebb596c79852fc78c5cfcddbae595c08 (patch)
tree4b956b14e1b92d0ccacbca8b2a78fab3e429c45c /src
parente632dafba2782ce8f51c2e414290d36cf983896f (diff)
parent59a340963fa5d8b5507d95cd015f7ca2855ba151 (diff)
downloadrust-aec047edebb596c79852fc78c5cfcddbae595c08.tar.gz
rust-aec047edebb596c79852fc78c5cfcddbae595c08.zip
Rollup merge of #61780 - SimonSapin:container-error, r=Amanieu
Finalize the error type for `try_reserve`

See tracking issue comments from https://github.com/rust-lang/rust/issues/48043#issuecomment-500828346.

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: \
            https://github.com/rust-lang/wg-allocators/issues/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 ~(https://github.com/rust-lang/rust/issues/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 https://github.com/rust-lang/wg-allocators/issues/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: https://github.com/rust-lang/rust/pull/61780#issuecomment-501392487

* 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.~
Diffstat (limited to 'src')
-rw-r--r--src/liballoc/collections/mod.rs31
-rw-r--r--src/liballoc/collections/vec_deque.rs16
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/raw_vec.rs32
-rw-r--r--src/liballoc/string.rs14
-rw-r--r--src/liballoc/tests/string.rs14
-rw-r--r--src/liballoc/tests/vec.rs18
-rw-r--r--src/liballoc/tests/vec_deque.rs14
-rw-r--r--src/liballoc/vec.rs14
-rw-r--r--src/libstd/Cargo.toml2
-rw-r--r--src/libstd/collections/hash/map.rs17
-rw-r--r--src/libstd/collections/hash/set.rs4
-rw-r--r--src/libstd/collections/mod.rs2
-rw-r--r--src/libstd/lib.rs1
14 files changed, 95 insertions, 85 deletions
diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs
index 5a33ddc14f0..f1f22fe48c5 100644
--- a/src/liballoc/collections/mod.rs
+++ b/src/liballoc/collections/mod.rs
@@ -41,32 +41,35 @@ 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 CollectionAllocErr {
+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 CollectionAllocErr {
-    #[inline]
-    fn from(AllocErr: AllocErr) -> Self {
-        CollectionAllocErr::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")]
-impl From<LayoutErr> for CollectionAllocErr {
+impl From<LayoutErr> for TryReserveError {
     #[inline]
     fn from(_: LayoutErr) -> Self {
-        CollectionAllocErr::CapacityOverflow
+        TryReserveError::CapacityOverflow
     }
 }
 
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 9240346ace9..2fc87413367 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -18,7 +18,7 @@ use core::ptr::{self, NonNull};
 use core::slice;
 use core::hash::{Hash, Hasher};
 
-use crate::collections::CollectionAllocErr;
+use crate::collections::TryReserveError;
 use crate::raw_vec::RawVec;
 use crate::vec::Vec;
 
@@ -576,10 +576,10 @@ impl<T> VecDeque<T> {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     /// use std::collections::VecDeque;
     ///
-    /// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
+    /// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
     ///     let mut output = VecDeque::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -595,7 +595,7 @@ impl<T> VecDeque<T> {
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr>  {
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>  {
         self.try_reserve(additional)
     }
 
@@ -614,10 +614,10 @@ impl<T> VecDeque<T> {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     /// use std::collections::VecDeque;
     ///
-    /// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, CollectionAllocErr> {
+    /// fn process_data(data: &[u32]) -> Result<VecDeque<u32>, TryReserveError> {
     ///     let mut output = VecDeque::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -633,12 +633,12 @@ impl<T> VecDeque<T> {
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         let old_cap = self.cap();
         let used_cap = self.len() + 1;
         let new_cap = used_cap.checked_add(additional)
             .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
-            .ok_or(CollectionAllocErr::CapacityOverflow)?;
+            .ok_or(TryReserveError::CapacityOverflow)?;
 
         if new_cap > old_cap {
             self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?;
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 7421beddd95..4a48945adc3 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -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)]
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 0abab45e920..bc8a38f6b3a 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -7,8 +7,8 @@ use core::ops::Drop;
 use core::ptr::{self, NonNull, Unique};
 use core::slice;
 
-use crate::alloc::{Alloc, Layout, Global, handle_alloc_error};
-use crate::collections::CollectionAllocErr::{self, *};
+use crate::alloc::{Alloc, Layout, Global, AllocErr, handle_alloc_error};
+use crate::collections::TryReserveError::{self, *};
 use crate::boxed::Box;
 
 #[cfg(test)]
@@ -385,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_capacity: usize, needed_extra_capacity: usize)
-           -> Result<(), CollectionAllocErr> {
+           -> Result<(), TryReserveError> {
 
         self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Exact)
     }
@@ -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 */ }
          }
      }
@@ -422,7 +422,7 @@ impl<T, A: Alloc> RawVec<T, A> {
     /// needed_extra_capacity` elements. This logic is used in amortized reserve methods.
     /// Returns `(new_capacity, new_alloc_size)`.
     fn amortized_new_size(&self, used_capacity: usize, needed_extra_capacity: usize)
-        -> Result<usize, CollectionAllocErr> {
+        -> Result<usize, TryReserveError> {
 
         // Nothing we can really do about these checks :(
         let required_cap = used_capacity.checked_add(needed_extra_capacity)
@@ -435,7 +435,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_capacity: usize, needed_extra_capacity: usize)
-        -> Result<(), CollectionAllocErr> {
+        -> Result<(), TryReserveError> {
         self.reserve_internal(used_capacity, needed_extra_capacity, Fallible, Amortized)
     }
 
@@ -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 */ }
         }
     }
@@ -640,10 +640,8 @@ impl<T, A: Alloc> RawVec<T, A> {
         needed_extra_capacity: usize,
         fallibility: Fallibility,
         strategy: ReserveStrategy,
-    ) -> Result<(), CollectionAllocErr> {
+    ) -> 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(())
@@ -737,7 +739,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(alloc_size: usize) -> Result<(), TryReserveError> {
     if mem::size_of::<usize>() < 8 && alloc_size > core::isize::MAX as usize {
         Err(CapacityOverflow)
     } else {
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index eca726cd410..b65f191836e 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -56,7 +56,7 @@ use core::ptr;
 use core::str::{pattern::Pattern, lossy};
 
 use crate::borrow::{Cow, ToOwned};
-use crate::collections::CollectionAllocErr;
+use crate::collections::TryReserveError;
 use crate::boxed::Box;
 use crate::str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars};
 use crate::vec::Vec;
@@ -937,9 +937,9 @@ impl String {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     ///
-    /// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
+    /// fn process_data(data: &str) -> Result<String, TryReserveError> {
     ///     let mut output = String::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -953,7 +953,7 @@ impl String {
     /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.vec.try_reserve(additional)
     }
 
@@ -975,9 +975,9 @@ impl String {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     ///
-    /// fn process_data(data: &str) -> Result<String, CollectionAllocErr> {
+    /// fn process_data(data: &str) -> Result<String, TryReserveError> {
     ///     let mut output = String::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -991,7 +991,7 @@ impl String {
     /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr>  {
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>  {
         self.vec.try_reserve_exact(additional)
     }
 
diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs
index 765210e5aa6..55edf56345b 100644
--- a/src/liballoc/tests/string.rs
+++ b/src/liballoc/tests/string.rs
@@ -1,5 +1,5 @@
 use std::borrow::Cow;
-use std::collections::CollectionAllocErr::*;
+use std::collections::TryReserveError::*;
 use std::mem::size_of;
 use std::{usize, isize};
 
@@ -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) {
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index 6e8ffe18522..29a22aa0315 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 use std::mem::size_of;
 use std::{usize, isize};
 use std::vec::{Drain, IntoIter};
-use std::collections::CollectionAllocErr::*;
+use std::collections::TryReserveError::*;
 
 struct DropCounter<'a> {
     count: &'a mut u32,
@@ -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) {
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index 1bbcca97b3c..d49b553fc02 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -1,6 +1,6 @@
 use std::fmt::Debug;
 use std::collections::{VecDeque, vec_deque::Drain};
-use std::collections::CollectionAllocErr::*;
+use std::collections::TryReserveError::*;
 use std::mem::size_of;
 use std::{usize, isize};
 
@@ -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) {
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index dac04e4e624..d2798955c46 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -70,7 +70,7 @@ use core::ptr::{self, NonNull};
 use core::slice::{self, SliceIndex};
 
 use crate::borrow::{ToOwned, Cow};
-use crate::collections::CollectionAllocErr;
+use crate::collections::TryReserveError;
 use crate::boxed::Box;
 use crate::raw_vec::RawVec;
 
@@ -498,9 +498,9 @@ impl<T> Vec<T> {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     ///
-    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, CollectionAllocErr> {
+    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
     ///     let mut output = Vec::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -516,7 +516,7 @@ impl<T> Vec<T> {
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.buf.try_reserve(self.len, additional)
     }
 
@@ -538,9 +538,9 @@ impl<T> Vec<T> {
     ///
     /// ```
     /// #![feature(try_reserve)]
-    /// use std::collections::CollectionAllocErr;
+    /// use std::collections::TryReserveError;
     ///
-    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, CollectionAllocErr> {
+    /// fn process_data(data: &[u32]) -> Result<Vec<u32>, TryReserveError> {
     ///     let mut output = Vec::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
@@ -556,7 +556,7 @@ impl<T> Vec<T> {
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr>  {
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>  {
         self.buf.try_reserve_exact(self.len, additional)
     }
 
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 5334c4dfc68..3288d0b4df2 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -23,7 +23,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of
 compiler_builtins = { version = "0.1.16" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
-hashbrown = { version = "0.4.0", features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
 [dependencies.backtrace]
 version = "0.3.34"
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 1e28ee8da26..a0538986a22 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -6,7 +6,7 @@ use hashbrown::hash_map as base;
 
 use crate::borrow::Borrow;
 use crate::cell::Cell;
-use crate::collections::CollectionAllocErr;
+use crate::collections::TryReserveError;
 use crate::fmt::{self, Debug};
 #[allow(deprecated)]
 use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
@@ -588,7 +588,7 @@ where
     /// ```
     #[inline]
     #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.base
             .try_reserve(additional)
             .map_err(map_collection_alloc_err)
@@ -2542,10 +2542,13 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K,
 }
 
 #[inline]
-fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> CollectionAllocErr {
+fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError {
     match err {
-        hashbrown::CollectionAllocErr::CapacityOverflow => CollectionAllocErr::CapacityOverflow,
-        hashbrown::CollectionAllocErr::AllocErr => CollectionAllocErr::AllocErr,
+        hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow,
+        hashbrown::CollectionAllocErr::AllocErr { layout } => TryReserveError::AllocError {
+            layout,
+            non_exhaustive: (),
+        },
     }
 }
 
@@ -2605,7 +2608,7 @@ mod test_map {
     use super::RandomState;
     use crate::cell::RefCell;
     use rand::{thread_rng, Rng};
-    use realstd::collections::CollectionAllocErr::*;
+    use realstd::collections::TryReserveError::*;
     use realstd::usize;
 
     // https://github.com/rust-lang/rust/issues/62301
@@ -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!")
         }
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index d243412405a..26db651ef89 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -1,5 +1,5 @@
 use crate::borrow::Borrow;
-use crate::collections::CollectionAllocErr;
+use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, BuildHasher};
 use crate::iter::{Chain, FromIterator, FusedIterator};
@@ -383,7 +383,7 @@ impl<T, S> HashSet<T, S>
     /// ```
     #[inline]
     #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.map.try_reserve(additional)
     }
 
diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs
index 15c2532f8b4..f5957466be8 100644
--- a/src/libstd/collections/mod.rs
+++ b/src/libstd/collections/mod.rs
@@ -427,7 +427,7 @@ pub use self::hash_map::HashMap;
 pub use self::hash_set::HashSet;
 
 #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-pub use alloc_crate::collections::CollectionAllocErr;
+pub use alloc_crate::collections::TryReserveError;
 
 mod hash;
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 1f48315d3f8..760d92f1d7b 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -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)]