about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-19 08:04:26 +0000
committerbors <bors@rust-lang.org>2023-01-19 08:04:26 +0000
commit705a96d39bbd97ac0cc8ae119b0f3c097ab62fc0 (patch)
treee150d8f5821c55d5d84905ee20560b9aba175264
parent65d2f2a5f9c323c88d1068e8e90d0b47a20d491c (diff)
parent50e9f2e6e87911659b6ae63230a5797f4cdf28e1 (diff)
downloadrust-705a96d39bbd97ac0cc8ae119b0f3c097ab62fc0.tar.gz
rust-705a96d39bbd97ac0cc8ae119b0f3c097ab62fc0.zip
Auto merge of #106989 - clubby789:is-zero-num, r=scottmcm
Implement `alloc::vec::IsZero` for `Option<$NUM>` types

Fixes #106911

Mirrors the `NonZero$NUM` implementations with an additional `assert_zero_valid`.
`None::<i32>` doesn't stricly satisfy `IsZero` but for the purpose of allocating we can produce more efficient codegen.
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec/is_zero.rs20
-rw-r--r--tests/codegen/vec-calloc.rs17
3 files changed, 37 insertions, 1 deletions
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index afc3a3dc6a8..ca75c3895f4 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -106,6 +106,7 @@
 #![feature(const_size_of_val)]
 #![feature(const_align_of_val)]
 #![feature(const_ptr_read)]
+#![feature(const_maybe_uninit_zeroed)]
 #![feature(const_maybe_uninit_write)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_refs_to_cell)]
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index 26120270c0c..cb9adf05c25 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -4,7 +4,8 @@ use crate::boxed::Box;
 
 #[rustc_specialization_trait]
 pub(super) unsafe trait IsZero {
-    /// Whether this value's representation is all zeros
+    /// Whether this value's representation is all zeros,
+    /// or can be represented with all zeroes.
     fn is_zero(&self) -> bool;
 }
 
@@ -147,6 +148,23 @@ impl_is_zero_option_of_nonzero!(
     NonZeroIsize,
 );
 
+macro_rules! impl_is_zero_option_of_num {
+    ($($t:ty,)+) => {$(
+        unsafe impl IsZero for Option<$t> {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                const {
+                    let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+                    assert!(none.is_none());
+                }
+                self.is_none()
+            }
+        }
+    )+};
+}
+
+impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
+
 unsafe impl<T: IsZero> IsZero for Wrapping<T> {
     #[inline]
     fn is_zero(&self) -> bool {
diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs
index 442cdd41dc6..4481a9d1e99 100644
--- a/tests/codegen/vec-calloc.rs
+++ b/tests/codegen/vec-calloc.rs
@@ -161,6 +161,23 @@ pub fn vec_option_bool(n: usize) -> Vec<Option<bool>> {
     vec![Some(false); n]
 }
 
+// CHECK-LABEL: @vec_option_i32
+#[no_mangle]
+pub fn vec_option_i32(n: usize) -> Vec<Option<i32>> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![None; n]
+}
+
 // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
 // CHECK: declare noalias noundef ptr @__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]