Skip to content

Commit

Permalink
Auto merge of #85737 - scottmcm:vec-calloc-option-nonzero, r=m-ou-se
Browse files Browse the repository at this point in the history
Enable Vec's calloc optimization for Option<NonZero>

Someone on discord noticed that `vec![None::<NonZeroU32>; N]` wasn't getting the optimization, so here's a PR 🙃

We can certainly do this in the standard library because we know for sure this is ok, but I think it's also a necessary consequence of documented guarantees like those in https://doc.rust-lang.org/std/option/#representation and https://doc.rust-lang.org/core/num/struct.NonZeroU32.html

It feels weird to do this without adding a test, but I wasn't sure where that would belong.  Is it worth adding codegen tests for these?
  • Loading branch information
bors committed May 27, 2021
2 parents 8d1e3d3 + 04d34a9 commit ea78d1e
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions library/alloc/src/vec/is_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,36 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
self.is_none()
}
}

// `Option<num::NonZeroU32>` and similar have a representation guarantee that
// they're the same size as the corresponding `u32` type, as well as a guarantee
// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
// While the documentation officially makes in UB to transmute from `None`,
// we're the standard library so we can make extra inferences, and we know that
// the only niche available to represent `None` is the one that's all zeros.

macro_rules! impl_is_zero_option_of_nonzero {
($($t:ident,)+) => {$(
unsafe impl IsZero for Option<core::num::$t> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
}
}
)+};
}

impl_is_zero_option_of_nonzero!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroUsize,
NonZeroIsize,
);

0 comments on commit ea78d1e

Please sign in to comment.