From b5ea631fbd547c922a2b9fe09e1ae3794d4195ad Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sun, 15 Dec 2024 15:44:56 +0800 Subject: [PATCH 1/2] Asserts the maximum value that can be returned from `Vec::len` --- library/alloc/src/vec/mod.rs | 11 +++++-- library/core/src/mem/mod.rs | 11 +++++++ tests/codegen/vec-in-place.rs | 46 ++++++++++++++++++++++++++++++ tests/codegen/vec_pop_push_noop.rs | 6 ++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 457be3ae77fc6..b8dfa886f5db5 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; @@ -2675,7 +2675,14 @@ impl Vec { #[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` is `isize::MAX` bytes, so the maximum value can + // be returned is `usize::checked_div(mem::size_of::()).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 78ad6880709fb..57acc9dcd6ee7 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::(); + + /// 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::() { + 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 5d05f242617fb..33de0913f772f 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -36,6 +36,9 @@ pub struct Baz { // CHECK-LABEL: @vec_iterator_cast_primitive #[no_mangle] pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { + // 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() @@ -44,14 +47,37 @@ pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec { // CHECK-LABEL: @vec_iterator_cast_wrapper #[no_mangle] pub fn vec_iterator_cast_wrapper(vec: Vec) -> Vec> { + // 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) -> Vec { + // 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> { + // 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>) -> Vec { + // 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() @@ -60,6 +86,9 @@ pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec { // CHECK-LABEL: @vec_iterator_cast_aggregate #[no_mangle] pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { + // 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() @@ -68,6 +97,9 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec { // CHECK-LABEL: @vec_iterator_cast_deaggregate_tra #[no_mangle] pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { + // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call @@ -81,6 +113,9 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> { // CHECK-LABEL: @vec_iterator_cast_deaggregate_fold #[no_mangle] pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { + // CHECK-NOT: loop + // CHECK: call + // CHECK-SAME: void @llvm.assume(i1 %{{.+}}) // CHECK-NOT: loop // CHECK-NOT: call @@ -94,6 +129,11 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> { // CHECK-LABEL: @vec_iterator_cast_unwrap_drop #[no_mangle] pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { + // 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 @@ -105,10 +145,16 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec>) -> Vec { // CHECK-LABEL: @vec_iterator_cast_wrap_drop #[no_mangle] pub fn vec_iterator_cast_wrap_drop(vec: Vec) -> Vec> { + // 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 4d76c24a9d9f4..1e5bc2bf0fd7e 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,6 +12,9 @@ pub fn noop(v: &mut Vec) { // 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 if let Some(x) = v.pop() { From 7d450bbf31d18e868a0bea103792dd73786f6723 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sun, 15 Dec 2024 15:44:56 +0800 Subject: [PATCH 2/2] Fix `vec_pop_push_noop` codegen test on `wasm32-wasip1` target --- tests/codegen/vec_pop_push_noop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs index 1e5bc2bf0fd7e..a8ad5b6f1a3ab 100644 --- a/tests/codegen/vec_pop_push_noop.rs +++ b/tests/codegen/vec_pop_push_noop.rs @@ -16,7 +16,7 @@ pub fn noop(v: &mut Vec) { // 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) }