From d069c58e78891d453b0b17adfecd368694fd289f Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Sun, 24 Jan 2021 13:29:39 +0100 Subject: [PATCH] shrink_to shouldn't panic on len greater than capacity --- library/alloc/src/collections/binary_heap.rs | 3 +-- library/alloc/src/collections/vec_deque/mod.rs | 10 ++++------ library/alloc/src/string.rs | 3 +-- library/alloc/src/vec/mod.rs | 12 ++++++------ library/std/src/collections/hash/map.rs | 4 +--- library/std/src/collections/hash/set.rs | 4 +--- library/std/src/ffi/os_str.rs | 3 +-- src/test/codegen/vec-shrink-panic.rs | 8 -------- 8 files changed, 15 insertions(+), 32 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 3c515af71f5..8a36b2af765 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -870,8 +870,7 @@ impl BinaryHeap { /// The capacity will remain at least as large as both the length /// and the supplied value. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 6f9133e2811..eb899468193 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -761,8 +761,7 @@ impl VecDeque { /// The capacity will remain at least as large as both the length /// and the supplied value. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// @@ -780,10 +779,9 @@ impl VecDeque { /// ``` #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); - - // +1 since the ringbuffer always leaves one space empty - // len + 1 can't overflow for an existing, well-formed ringbuffer. + let min_capacity = cmp::min(min_capacity, self.capacity()); + // We don't have to worry about an overflow as neither `self.len()` nor `self.capacity()` + // can ever be `usize::MAX`. +1 as the ringbuffer always leaves one space empty. let target_cap = cmp::max(cmp::max(min_capacity, self.len()) + 1, MINIMUM_CAPACITY + 1) .next_power_of_two(); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index b1f860d6b64..9b0b480a7e9 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1036,8 +1036,7 @@ impl String { /// The capacity will remain at least as large as both the length /// and the supplied value. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b533ce79420..13fcf5207e0 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -321,7 +321,7 @@ mod spec_extend; /// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` /// and then filling it back up to the same [`len`] should incur no calls to /// the allocator. If you wish to free up unused memory, use -/// [`shrink_to_fit`]. +/// [`shrink_to_fit`] or [`shrink_to`]. /// /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is /// sufficient. [`push`] and [`insert`] *will* (re)allocate if @@ -360,6 +360,7 @@ mod spec_extend; /// [`String`]: crate::string::String /// [`&str`]: type@str /// [`shrink_to_fit`]: Vec::shrink_to_fit +/// [`shrink_to`]: Vec::shrink_to /// [`capacity`]: Vec::capacity /// [`mem::size_of::`]: core::mem::size_of /// [`len`]: Vec::len @@ -909,10 +910,7 @@ impl Vec { /// The capacity will remain at least as large as both the length /// and the supplied value. /// - /// # Panics - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// @@ -929,7 +927,9 @@ impl Vec { #[doc(alias = "realloc")] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); + if self.capacity() > min_capacity { + self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); + } } /// Converts the vector into [`Box<[T]>`][owned slice]. diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 829fc3817af..28a25572dd8 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -658,8 +658,7 @@ where /// down no lower than the supplied limit while maintaining the internal rules /// and possibly leaving some space in accordance with the resize policy. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// @@ -679,7 +678,6 @@ where #[inline] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); self.base.shrink_to(min_capacity); } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index baa3026ff75..b08510d6b01 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -462,9 +462,7 @@ where /// down no lower than the supplied limit while maintaining the internal rules /// and possibly leaving some space in accordance with the resize policy. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// + /// If the current capacity is less than the lower limit, this is a no-op. /// # Examples /// /// ``` diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 32f0f8a52f8..21060182d60 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -304,8 +304,7 @@ impl OsString { /// The capacity will remain at least as large as both the length /// and the supplied value. /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. + /// If the current capacity is less than the lower limit, this is a no-op. /// /// # Examples /// diff --git a/src/test/codegen/vec-shrink-panic.rs b/src/test/codegen/vec-shrink-panic.rs index cee4128c650..6b0ac78857a 100644 --- a/src/test/codegen/vec-shrink-panic.rs +++ b/src/test/codegen/vec-shrink-panic.rs @@ -26,11 +26,3 @@ pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { // CHECK-NOT: panic iter.iter().copied().collect() } - -// Sanity-check that we do see a possible panic for an arbitrary `Vec::shrink_to`. -// CHECK-LABEL: @shrink_to -#[no_mangle] -pub fn shrink_to(vec: &mut Vec) { - // CHECK: panic - vec.shrink_to(42); -}