diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 90bdf630d062d..f91067526b13f 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(iter_zip)] #![feature(thread_local_const_init)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![feature(nonzero_ops)] #![recursion_limit = "512"] diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 6c14410a4cc70..00fb4902c61f7 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -30,6 +30,7 @@ Rust MIR: a lowered representation of Rust. #![feature(once_cell)] #![feature(control_flow_enum)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![recursion_limit = "256"] #[macro_use] diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 97bfe2f3984ea..3ee857f3399e0 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -58,7 +58,31 @@ use core::fmt::Display; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] -pub enum TryReserveError { +pub struct TryReserveError { + kind: TryReserveErrorKind, +} + +impl TryReserveError { + /// Details about the allocation that caused the error + #[inline] + #[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" + )] + pub fn kind(&self) -> TryReserveErrorKind { + self.kind.clone() + } +} + +/// Details of the allocation that caused a `TryReserveError` +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +pub enum TryReserveErrorKind { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). CapacityOverflow, @@ -81,12 +105,23 @@ pub enum TryReserveError { }, } +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +impl From for TryReserveError { + fn from(kind: TryReserveErrorKind) -> Self { + Self { kind } + } +} + #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] impl From for TryReserveError { - /// Always evaluates to [`TryReserveError::CapacityOverflow`]. + /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] fn from(_: LayoutError) -> Self { - TryReserveError::CapacityOverflow + TryReserveErrorKind::CapacityOverflow.into() } } @@ -97,11 +132,13 @@ impl Display for TryReserveError { fmt: &mut core::fmt::Formatter<'_>, ) -> core::result::Result<(), core::fmt::Error> { fmt.write_str("memory allocation failed")?; - let reason = match &self { - TryReserveError::CapacityOverflow => { + let reason = match self.kind { + TryReserveErrorKind::CapacityOverflow => { " because the computed capacity exceeded the collection's maximum" } - TryReserveError::AllocError { .. } => " because the memory allocator returned a error", + TryReserveErrorKind::AllocError { .. } => { + " because the memory allocator returned a error" + } }; fmt.write_str(reason) } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 6bbddeb69b296..bea5cf11be5e8 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -19,6 +19,7 @@ use core::slice; use crate::alloc::{Allocator, Global}; use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind; use crate::raw_vec::RawVec; use crate::vec::Vec; @@ -773,7 +774,7 @@ impl VecDeque { let new_cap = used_cap .checked_add(additional) .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) - .ok_or(TryReserveError::CapacityOverflow)?; + .ok_or(TryReserveErrorKind::CapacityOverflow)?; if new_cap > old_cap { self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index d11d4031f7754..3caada06f6b58 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -13,7 +13,8 @@ use core::slice; use crate::alloc::handle_alloc_error; use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; -use crate::collections::TryReserveError::{self, *}; +use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind::*; #[cfg(test)] mod tests; @@ -425,7 +426,7 @@ impl RawVec { if mem::size_of::() == 0 { // Since we return a capacity of `usize::MAX` when `elem_size` is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow); + return Err(CapacityOverflow.into()); } // Nothing we can really do about these checks, sadly. @@ -451,7 +452,7 @@ impl RawVec { if mem::size_of::() == 0 { // Since we return a capacity of `usize::MAX` when the type size is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow); + return Err(CapacityOverflow.into()); } let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; @@ -471,10 +472,9 @@ impl RawVec { let ptr = unsafe { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { - layout: new_layout, - non_exhaustive: (), - })? + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? }; self.set_ptr(ptr); Ok(()) @@ -510,7 +510,7 @@ where alloc.allocate(new_layout) }; - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) } unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { @@ -526,7 +526,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { #[cfg(not(no_global_oom_handling))] #[inline] fn handle_reserve(result: Result<(), TryReserveError>) { - match result { + match result.map_err(|e| e.kind()) { Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), Ok(()) => { /* yay */ } @@ -545,7 +545,7 @@ fn handle_reserve(result: Result<(), TryReserveError>) { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { if usize::BITS < 64 && alloc_size > isize::MAX as usize { - Err(CapacityOverflow) + Err(CapacityOverflow.into()) } else { Ok(()) } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 3143afa269dde..b3e048a6587b9 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(pattern)] #![feature(trusted_len)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] #![feature(binary_heap_into_iter_sorted)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 9ec0ee97ab926..cf9d734a9d54d 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cell::Cell; -use std::collections::TryReserveError::*; +use std::collections::TryReserveErrorKind::*; use std::ops::Bound; use std::ops::Bound::*; use std::ops::RangeBounds; @@ -703,35 +703,42 @@ fn test_try_reserve() { let mut empty_string: String = String::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(AllocError { .. }) = + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) { + if let Err(AllocError { .. }) = + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an OOM!") } @@ -742,25 +749,27 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: String = String::from("0123456789"); - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!") } @@ -782,30 +791,40 @@ fn test_try_reserve_exact() { { let mut empty_string: String = String::new(); - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocError { .. }) = + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(AllocError { .. }) = + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an OOM!") } @@ -815,24 +834,33 @@ fn test_try_reserve_exact() { { let mut ten_bytes: String = String::from("0123456789"); - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 3b7237016800f..d3a6dcfddc527 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cell::Cell; -use std::collections::TryReserveError::*; +use std::collections::TryReserveErrorKind::*; use std::fmt::Debug; use std::iter::InPlaceIterable; use std::mem::{size_of, swap}; @@ -1478,35 +1478,41 @@ fn test_try_reserve() { let mut empty_bytes: Vec = Vec::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(AllocError { .. }) = + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an OOM!") } @@ -1517,25 +1523,27 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1545,25 +1553,31 @@ fn test_try_reserve() { // Same basic idea, but with interesting type size let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { + if let Err(AllocError { .. }) = + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!"); } @@ -1585,30 +1599,40 @@ fn test_try_reserve_exact() { { let mut empty_bytes: Vec = Vec::new(); - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocError { .. }) = + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(AllocError { .. }) = + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an OOM!") } @@ -1618,24 +1642,33 @@ fn test_try_reserve_exact() { { let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1644,24 +1677,34 @@ fn test_try_reserve_exact() { { let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { + if let Err(AllocError { .. }) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index d7140cf97593c..e9fd19d76ea43 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1,4 +1,4 @@ -use std::collections::TryReserveError::*; +use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; @@ -1171,23 +1171,26 @@ fn test_try_reserve() { let mut empty_bytes: VecDeque = VecDeque::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1196,7 +1199,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(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } @@ -1207,25 +1210,27 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1235,25 +1240,31 @@ fn test_try_reserve() { // Same basic idea, but with interesting type size let mut ten_u32s: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { + if let Err(AllocError { .. }) = + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!"); } @@ -1275,20 +1286,26 @@ fn test_try_reserve_exact() { { let mut empty_bytes: VecDeque = VecDeque::new(); - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!") } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1297,7 +1314,9 @@ 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(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(AllocError { .. }) = + empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } @@ -1307,24 +1326,33 @@ fn test_try_reserve_exact() { { let mut ten_bytes: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocError { .. }) = + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } @@ -1333,24 +1361,34 @@ fn test_try_reserve_exact() { { let mut ten_u32s: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { + if let Err(AllocError { .. }) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()) + { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()) + { } else { panic!("usize::MAX should trigger an overflow!") } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1628e1bceda72..941708429b985 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -8,6 +8,7 @@ use hashbrown::hash_map as base; use crate::borrow::Borrow; use crate::cell::Cell; use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -2990,9 +2991,11 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, #[inline] pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { - hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, + hashbrown::TryReserveError::CapacityOverflow => { + TryReserveErrorKind::CapacityOverflow.into() + } hashbrown::TryReserveError::AllocError { layout } => { - TryReserveError::AllocError { layout, non_exhaustive: () } + TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into() } } } diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index def085e380b19..18d868d49a634 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -3,7 +3,7 @@ use super::HashMap; use super::RandomState; use crate::cell::RefCell; use rand::{thread_rng, Rng}; -use realstd::collections::TryReserveError::*; +use realstd::collections::TryReserveErrorKind::*; // https://github.com/rust-lang/rust/issues/62301 fn _assert_hashmap_is_unwind_safe() { @@ -821,12 +821,12 @@ fn test_try_reserve() { const MAX_USIZE: usize = usize::MAX; - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) { } else { panic!("usize::MAX should trigger an overflow!"); } - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()) { } else { panic!("usize::MAX / 8 should trigger an OOM!") } diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 8cda601edd141..130bb5cb2b3c2 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -422,6 +422,12 @@ pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub use alloc_crate::collections::TryReserveError; +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +pub use alloc_crate::collections::TryReserveErrorKind; mod hash; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9dd99e44e809b..1af6157ca68bf 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -326,6 +326,7 @@ #![feature(trace_macros)] #![feature(try_blocks)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(unsafe_cell_raw_get)] #![feature(unwrap_infallible)]