1+ use core:: mem:: SizedTypeProperties ;
12use core:: num:: { NonZero , Saturating , Wrapping } ;
23
34use crate :: boxed:: Box ;
@@ -20,6 +21,8 @@ macro_rules! impl_is_zero {
2021 } ;
2122}
2223
24+ impl_is_zero ! ( ( ) , |_: ( ) | true ) ; // It is needed to impl for arrays and tuples of ().
25+
2326impl_is_zero ! ( i8 , |x| x == 0 ) ; // It is needed to impl for arrays and tuples of i8.
2427impl_is_zero ! ( i16 , |x| x == 0 ) ;
2528impl_is_zero ! ( i32 , |x| x == 0 ) ;
@@ -43,25 +46,46 @@ impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
4346// `IsZero` cannot be soundly implemented for pointers because of provenance
4447// (see #135338).
4548
49+ unsafe impl < T , const N : usize > IsZero for [ T ; N ] {
50+ #[ inline]
51+ default fn is_zero ( & self ) -> bool {
52+ // If the array is of length zero,
53+ // then it doesn't actually contain any `T`s,
54+ // so `T::clone` doesn't need to be called,
55+ // and we can "zero-initialize" all zero bytes of the array.
56+ N == 0
57+ }
58+ }
59+
4660unsafe impl < T : IsZero , const N : usize > IsZero for [ T ; N ] {
4761 #[ inline]
4862 fn is_zero ( & self ) -> bool {
49- // Because this is generated as a runtime check, it's not obvious that
50- // it's worth doing if the array is really long. The threshold here
51- // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
52- // fails to const-fold the check in `vec![[1; 32]; n]`
53- // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
54- // Feel free to tweak if you have better evidence.
55-
56- N <= 16 && self . iter ( ) . all ( IsZero :: is_zero)
63+ if T :: IS_ZST {
64+ // If T is a ZST, then there is at most one possible value of `T`,
65+ // so we only need to check one element for zeroness.
66+ // We can't unconditionally return `true` here, since, e.g.
67+ // `T = [NonTrivialCloneZst; 5]` is a ZST that implements `IsZero`
68+ // due to the generic array impl, but `T::is_zero` returns `false`
69+ // since the length is not 0.
70+ self . get ( 0 ) . is_none_or ( IsZero :: is_zero)
71+ } else {
72+ // Because this is generated as a runtime check, it's not obvious that
73+ // it's worth doing if the array is really long. The threshold here
74+ // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
75+ // fails to const-fold the check in `vec![[1; 32]; n]`
76+ // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
77+ // Feel free to tweak if you have better evidence.
78+
79+ N <= 16 && self . iter ( ) . all ( IsZero :: is_zero)
80+ }
5781 }
5882}
5983
6084// This is recursive macro.
6185macro_rules! impl_is_zero_tuples {
6286 // Stopper
6387 ( ) => {
64- // No use for implementing for empty tuple because it is ZST .
88+ // We already have an impl for () above .
6589 } ;
6690 ( $first_arg: ident $( , $rest: ident) * ) => {
6791 unsafe impl <$first_arg: IsZero , $( $rest: IsZero , ) * > IsZero for ( $first_arg, $( $rest, ) * ) {
0 commit comments