about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-27 18:36:32 +0000
committerbors <bors@rust-lang.org>2021-01-27 18:36:32 +0000
commita2f8f6281817d430e20726128b739d3c6708561c (patch)
tree28024be6199a7cc05e20fb034e4dfa94f62632f5
parent613ef740f3f37702728c6324f948d0abd1e9c82b (diff)
parentd069c58e78891d453b0b17adfecd368694fd289f (diff)
downloadrust-a2f8f6281817d430e20726128b739d3c6708561c.tar.gz
rust-a2f8f6281817d430e20726128b739d3c6708561c.zip
Auto merge of #81335 - thomwiggers:no-panic-shrink-to, r=Mark-Simulacrum
Trying to shrink_to greater than capacity should be no-op

Per the discussion in https://github.com/rust-lang/rust/issues/56431, `shrink_to` shouldn't panic if you try to make a vector shrink to a capacity greater than its current capacity.
-rw-r--r--library/alloc/src/collections/binary_heap.rs3
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs10
-rw-r--r--library/alloc/src/string.rs3
-rw-r--r--library/alloc/src/vec/mod.rs12
-rw-r--r--library/std/src/collections/hash/map.rs4
-rw-r--r--library/std/src/collections/hash/set.rs4
-rw-r--r--library/std/src/ffi/os_str.rs3
-rw-r--r--src/test/codegen/vec-shrink-panic.rs8
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<T> BinaryHeap<T> {
     /// 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<T> VecDeque<T> {
     /// 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<T> VecDeque<T> {
     /// ```
     #[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::<T>`]: core::mem::size_of
 /// [`len`]: Vec::len
@@ -909,10 +910,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// 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<T, A: Allocator> Vec<T, A> {
     #[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<u32>) {
-    // CHECK: panic
-    vec.shrink_to(42);
-}