Skip to content

Commit 602ee09

Browse files
committed
Asserts the maximum value that can be returned from Vec::len
1 parent 9c7013c commit 602ee09

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

library/alloc/src/vec/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
#[cfg(not(no_global_oom_handling))]
5757
use core::cmp;
5858
use core::cmp::Ordering;
59-
use core::fmt;
6059
use core::hash::{Hash, Hasher};
6160
#[cfg(not(no_global_oom_handling))]
6261
use core::iter;
@@ -65,6 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
6564
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
6665
use core::ptr::{self, NonNull};
6766
use core::slice::{self, SliceIndex};
67+
use core::{fmt, intrinsics};
6868

6969
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
7070
pub use self::extract_if::ExtractIf;
@@ -2630,7 +2630,14 @@ impl<T, A: Allocator> Vec<T, A> {
26302630
#[stable(feature = "rust1", since = "1.0.0")]
26312631
#[rustc_confusables("length", "size")]
26322632
pub fn len(&self) -> usize {
2633-
self.len
2633+
let len = self.len;
2634+
2635+
// SAFETY: The maximum capacity of `Vec<T>` is `isize::MAX` bytes, so the maximum value can
2636+
// be returned is `usize::checked_div(mem::size_of::<T>()).unwrap_or(usize::MAX)`, which
2637+
// matches the definition of `T::MAX_SLICE_LEN`.
2638+
unsafe { intrinsics::assume(self.len <= T::MAX_SLICE_LEN) };
2639+
2640+
len
26342641
}
26352642

26362643
/// Returns `true` if the vector contains no elements.

library/core/src/mem/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,17 @@ pub trait SizedTypeProperties: Sized {
12431243
#[doc(hidden)]
12441244
#[unstable(feature = "sized_type_properties", issue = "none")]
12451245
const LAYOUT: Layout = Layout::new::<Self>();
1246+
1247+
/// The largest safe length for a `[Self]`.
1248+
///
1249+
/// Anything larger than this would make `size_of_val` overflow `isize::MAX`,
1250+
/// which is never allowed for a single object.
1251+
#[doc(hidden)]
1252+
#[unstable(feature = "sized_type_properties", issue = "none")]
1253+
const MAX_SLICE_LEN: usize = match size_of::<Self>() {
1254+
0 => usize::MAX,
1255+
n => (isize::MAX as usize) / n,
1256+
};
12461257
}
12471258
#[doc(hidden)]
12481259
#[unstable(feature = "sized_type_properties", issue = "none")]

tests/codegen/vec-in-place.rs

+34
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub struct Baz {
3737
#[no_mangle]
3838
pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
3939
// CHECK-NOT: loop
40+
// CHECK: call
41+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
4042
// CHECK-NOT: call
4143
vec.into_iter().map(|e| e as u8).collect()
4244
}
@@ -45,14 +47,35 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
4547
#[no_mangle]
4648
pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
4749
// CHECK-NOT: loop
50+
// CHECK: call
51+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
4852
// CHECK-NOT: call
4953
vec.into_iter().map(|e| Wrapper(e)).collect()
5054
}
5155

56+
// CHECK-LABEL: @vec_iterator_cast_signed
57+
#[no_mangle]
58+
pub fn vec_iterator_cast_signed(vec: Vec<i32>) -> Vec<u32> {
59+
// CHECK-NOT: and i{{[0-9]+}} %{{.*}}, {{[0-9]+}}
60+
vec.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect()
61+
}
62+
63+
// CHECK-LABEL: @vec_iterator_cast_signed_nested
64+
#[no_mangle]
65+
pub fn vec_iterator_cast_signed_nested(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
66+
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
67+
// CHECK-NOT: %{{.*}} = udiv
68+
vec.into_iter()
69+
.map(|e| e.into_iter().map(|e| u32::from_ne_bytes(e.to_ne_bytes())).collect())
70+
.collect()
71+
}
72+
5273
// CHECK-LABEL: @vec_iterator_cast_unwrap
5374
#[no_mangle]
5475
pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
5576
// CHECK-NOT: loop
77+
// CHECK: call
78+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
5679
// CHECK-NOT: call
5780
vec.into_iter().map(|e| e.0).collect()
5881
}
@@ -61,6 +84,8 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
6184
#[no_mangle]
6285
pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
6386
// CHECK-NOT: loop
87+
// CHECK: call
88+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
6489
// CHECK-NOT: call
6590
vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
6691
}
@@ -69,6 +94,8 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
6994
#[no_mangle]
7095
pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
7196
// CHECK-NOT: loop
97+
// CHECK: call
98+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
7299
// CHECK-NOT: call
73100

74101
// Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
@@ -82,6 +109,8 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
82109
#[no_mangle]
83110
pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
84111
// CHECK-NOT: loop
112+
// CHECK: call
113+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
85114
// CHECK-NOT: call
86115

87116
// Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
@@ -95,6 +124,8 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
95124
#[no_mangle]
96125
pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
97126
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
127+
// CHECK: call
128+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
98129
// CHECK-NOT: call
99130
// CHECK-NOT: %{{.*}} = mul
100131
// CHECK-NOT: %{{.*}} = udiv
@@ -106,9 +137,12 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
106137
#[no_mangle]
107138
pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
108139
// CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
140+
// CHECK: call
141+
// CHECK-SAME: void @llvm.assume(i1 %{{.+}})
109142
// CHECK-NOT: call
110143
// CHECK-NOT: %{{.*}} = mul
111144
// CHECK-NOT: %{{.*}} = udiv
145+
// CHECK: ret void
112146

113147
vec.into_iter().map(Wrapper).collect()
114148
}

tests/codegen/vec_pop_push_noop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn noop(v: &mut Vec<u8>) {
99
// CHECK-NOT: call
1010
// CHECK: tail call void @llvm.assume
1111
// CHECK-NOT: grow_one
12-
// CHECK-NOT: call
12+
// CHECK-NOT: call {{(?!void @llvm.assume)}}
1313
// CHECK: ret
1414
if let Some(x) = v.pop() {
1515
v.push(x)

0 commit comments

Comments
 (0)