about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilippe-Cholet <44676486+Philippe-Cholet@users.noreply.github.com>2024-04-08 12:12:13 +0200
committerPhilippe-Cholet <44676486+Philippe-Cholet@users.noreply.github.com>2024-04-08 12:12:13 +0200
commit7a2678de7d3c0caa169542bd56a4fbf41b73a5b5 (patch)
tree98c255136dbf53582cb78d71f15a621981460a65
parent7a495cc13d4361067d471faa3267dcdbacb3206c (diff)
downloadrust-7a2678de7d3c0caa169542bd56a4fbf41b73a5b5.tar.gz
rust-7a2678de7d3c0caa169542bd56a4fbf41b73a5b5.zip
Add invariant to VecDeque::pop_* that len < cap if pop successful
Similar to #114370 for VecDeque instead of Vec. It now uses `core::hint::assert_unchecked`.
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs10
-rw-r--r--tests/codegen/vecdeque_pop_push.rs67
2 files changed, 75 insertions, 2 deletions
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index e2fc320f280..693ecb0b6b4 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1614,7 +1614,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
             let old_head = self.head;
             self.head = self.to_physical_idx(1);
             self.len -= 1;
-            Some(unsafe { self.buffer_read(old_head) })
+            unsafe {
+                core::hint::assert_unchecked(self.len < self.capacity());
+                Some(self.buffer_read(old_head))
+            }
         }
     }
 
@@ -1638,7 +1641,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
             None
         } else {
             self.len -= 1;
-            Some(unsafe { self.buffer_read(self.to_physical_idx(self.len)) })
+            unsafe {
+                core::hint::assert_unchecked(self.len < self.capacity());
+                Some(self.buffer_read(self.to_physical_idx(self.len)))
+            }
         }
     }
 
diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs
new file mode 100644
index 00000000000..040d5a279dc
--- /dev/null
+++ b/tests/codegen/vecdeque_pop_push.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+#[no_mangle]
+// CHECK-LABEL: @noop_back(
+pub fn noop_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @noop_front(
+pub fn noop_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_front_to_back(
+pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_back_to_front(
+pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_back_byte(
+pub fn push_back_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_back(3);
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_front_byte(
+pub fn push_front_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_front(3);
+}