diff options
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 11 | ||||
| -rw-r--r-- | library/core/src/mem/mod.rs | 11 | ||||
| -rw-r--r-- | tests/codegen/vec-in-place.rs | 46 | ||||
| -rw-r--r-- | tests/codegen/vec_pop_push_noop.rs | 8 |
4 files changed, 73 insertions, 3 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 55496005f40..3a706d5f36b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -56,7 +56,6 @@ #[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; -use core::fmt; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; @@ -65,6 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; +use core::{fmt, intrinsics}; #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] pub use self::extract_if::ExtractIf; @@ -2680,7 +2680,14 @@ impl<T, A: Allocator> Vec<T, A> { #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { - self.len + let len = self.len; + + // SAFETY: The maximum capacity of `Vec<T>` is `isize::MAX` bytes, so the maximum value can + // be returned is `usize::checked_div(mem::size_of::<T>()).unwrap_or(usize::MAX)`, which + // matches the definition of `T::MAX_SLICE_LEN`. + unsafe { intrinsics::assume(len <= T::MAX_SLICE_LEN) }; + + len } /// Returns `true` if the vector contains no elements. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 78ad6880709..57acc9dcd6e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1241,6 +1241,17 @@ pub trait SizedTypeProperties: Sized { #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] const LAYOUT: Layout = Layout::new::<Self>(); + + /// The largest safe length for a `[Self]`. + /// + /// Anything larger than this would make `size_of_val` overflow `isize::MAX`, + /// which is never allowed for a single object. + #[doc(hidden)] + #[unstable(feature = "sized_type_properties", issue = "none")] + const MAX_SLICE_LEN: usize = match size_of::<Self>() { + 0 => usize::MAX, + n => (isize::MAX as usize) / n, + }; } #[doc(hidden)] #[unstable(feature = "sized_type_properties", issue = "none")] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index 5d05f242617..33de0913f77 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -37,6 +37,9 @@ pub struct Baz { #[no_mangle] pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> { // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop // CHECK-NOT: call vec.into_iter().map(|e| e as u8).collect() } @@ -45,14 +48,37 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> { #[no_mangle] pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> { // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // 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: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop // CHECK-NOT: call vec.into_iter().map(|e| e.0).collect() } @@ -61,6 +87,9 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> { #[no_mangle] pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> { // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop // CHECK-NOT: call vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() } @@ -69,6 +98,9 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> { #[no_mangle] pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> { // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. @@ -82,6 +114,9 @@ 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: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: loop // CHECK-NOT: call // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. @@ -95,6 +130,11 @@ 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: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv @@ -106,9 +146,15 @@ 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: %{{.*}} = mul + // CHECK-NOT: %{{.*}} = udiv + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) + // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} // CHECK-NOT: call // CHECK-NOT: %{{.*}} = mul // CHECK-NOT: %{{.*}} = udiv + // CHECK: ret void vec.into_iter().map(Wrapper).collect() } diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs index 4d76c24a9d9..a8ad5b6f1a3 100644 --- a/tests/codegen/vec_pop_push_noop.rs +++ b/tests/codegen/vec_pop_push_noop.rs @@ -1,3 +1,6 @@ +//@ revisions: llvm-pre-19 llvm-19 +//@ [llvm-19] min-llvm-version: 19 +//@ [llvm-pre-19] max-llvm-major-version: 18 //@ compile-flags: -O #![crate_type = "lib"] @@ -9,8 +12,11 @@ pub fn noop(v: &mut Vec<u8>) { // CHECK-NOT: call // CHECK: tail call void @llvm.assume // CHECK-NOT: grow_one + // llvm-pre-19: call + // llvm-pre-19-same: void @llvm.assume + // llvm-pre-19-NOT: grow_one // CHECK-NOT: call - // CHECK: ret + // CHECK: {{ret|[}]}} if let Some(x) = v.pop() { v.push(x) } |
