diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index c62a409ac02c..d997fb28d428 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,6 +15,7 @@ use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; +use hint; use self::BucketState::*; @@ -655,7 +656,17 @@ pub fn shift(mut self) -> Result, Bucket> { fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { let hashes = Layout::array::(capacity)?; let pairs = Layout::array::<(K, V)>(capacity)?; - hashes.extend(pairs) + hashes.extend(pairs).map(|(layout, _)| { + // LLVM seems to have trouble properly const-propagating pairs.align(), + // possibly due to the use of NonZeroUsize. This little hack allows it + // to generate optimal code. + // + // See https://github.com/rust-lang/rust/issues/51346 for more details. + ( + layout, + hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), + ) + }) } pub(crate) enum Fallibility { @@ -711,7 +722,8 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable { } fn raw_bucket_at(&self, index: usize) -> RawBucket { - let (_, pairs_offset) = calculate_layout::(self.capacity()).unwrap(); + let (_, pairs_offset) = calculate_layout::(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { @@ -1109,7 +1121,8 @@ fn drop(&mut self) { } } - let (layout, _) = calculate_layout::(self.capacity()).unwrap(); + let (layout, _) = calculate_layout::(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); // Remember how everything was allocated out of one buffer