Skip to content

Commit

Permalink
Asserts the maximum value that can be returned from Vec::len
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Oct 3, 2024
1 parent 9c7013c commit 7705433
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 9 deletions.
8 changes: 8 additions & 0 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2630,6 +2630,14 @@ impl<T, A: Allocator> Vec<T, A> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("length", "size")]
pub fn len(&self) -> usize {
if !T::IS_ZST {
// SAFETY: The maximum capacity of `Vec<T>` is `isize::MAX` bytes, so if `T` non-ZST,
// `Vec<T>` can have at most `isize::MAX as usize / mem::size_of::<T>()` elements.
unsafe {
core::hint::assert_unchecked(self.len <= isize::MAX as usize / mem::size_of::<T>());
}
}

self.len
}

Expand Down
25 changes: 17 additions & 8 deletions tests/codegen/vec-in-place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,39 +37,51 @@ pub struct Baz {
#[no_mangle]
pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
// CHECK-NOT: loop
// CHECK-NOT: call
vec.into_iter().map(|e| e as u8).collect()
}

// CHECK-LABEL: @vec_iterator_cast_wrapper
#[no_mangle]
pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
// CHECK-NOT: loop
// CHECK-NOT: call
vec.into_iter().map(|e| Wrapper(e)).collect()
}

// CHECK-LABEL: @vec_iterator_cast_signed
#[no_mangle]
pub fn vec_iterator_cast_signed(vec: Vec<i32>) -> Vec<u32> {
// CHECK-NOT: and i{{[0-9]+}} %{{.*}}, {{[0-9]+}}
vec.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect()
}

// CHECK-LABEL: @vec_iterator_cast_signed_nested
#[no_mangle]
pub fn vec_iterator_cast_signed_nested(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
// CHECK-NOT: %{{.*}} = udiv
vec.into_iter()
.map(|e| e.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect())
.collect()
}

// CHECK-LABEL: @vec_iterator_cast_unwrap
#[no_mangle]
pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
// CHECK-NOT: loop
// CHECK-NOT: call
vec.into_iter().map(|e| e.0).collect()
}

// CHECK-LABEL: @vec_iterator_cast_aggregate
#[no_mangle]
pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
// CHECK-NOT: loop
// CHECK-NOT: call
vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
}

// CHECK-LABEL: @vec_iterator_cast_deaggregate_tra
#[no_mangle]
pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
// CHECK-NOT: loop
// CHECK-NOT: call

// Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
// This currently is not guaranteed for repr(Rust) types, but it happens to work here and
Expand All @@ -82,7 +94,6 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
#[no_mangle]
pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
// CHECK-NOT: loop
// CHECK-NOT: call

// Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
// This currently is not guaranteed for repr(Rust) types, but it happens to work here and
Expand All @@ -95,7 +106,6 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
#[no_mangle]
pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
// CHECK-NOT: call
// CHECK-NOT: %{{.*}} = mul
// CHECK-NOT: %{{.*}} = udiv

Expand All @@ -106,7 +116,6 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
#[no_mangle]
pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
// CHECK-NOT: call
// CHECK-NOT: %{{.*}} = mul
// CHECK-NOT: %{{.*}} = udiv

Expand Down
1 change: 0 additions & 1 deletion tests/codegen/vec_pop_push_noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub fn noop(v: &mut Vec<u8>) {
// CHECK-NOT: call
// CHECK: tail call void @llvm.assume
// CHECK-NOT: grow_one
// CHECK-NOT: call
// CHECK: ret
if let Some(x) = v.pop() {
v.push(x)
Expand Down

0 comments on commit 7705433

Please sign in to comment.