From 7a2678de7d3c0caa169542bd56a4fbf41b73a5b5 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet <44676486+Philippe-Cholet@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:12:13 +0200 Subject: [PATCH] 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`. --- .../alloc/src/collections/vec_deque/mod.rs | 10 ++- tests/codegen/vecdeque_pop_push.rs | 67 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/codegen/vecdeque_pop_push.rs 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 @@ pub fn pop_front(&mut self) -> Option { 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 @@ pub fn pop_back(&mut self) -> Option { 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) { + // 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) { + // 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) { + // 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) { + // 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) { + // CHECK: call {{.*}}grow + v.push_back(3); +} + +#[no_mangle] +// CHECK-LABEL: @push_front_byte( +pub fn push_front_byte(v: &mut VecDeque) { + // CHECK: call {{.*}}grow + v.push_front(3); +}