diff --git a/.gitignore b/.gitignore index 4fffb2f89c..5b70a8980e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /Cargo.lock +.vscode diff --git a/crates/abi/src/coder/impl_core.rs b/crates/abi/src/coder/impl_core.rs index bbc830b55b..bbc6388e60 100644 --- a/crates/abi/src/coder/impl_core.rs +++ b/crates/abi/src/coder/impl_core.rs @@ -1,7 +1,16 @@ //! Modified implementations of unstable libcore functions. +use crate::no_std_prelude::*; use core::mem::{self, MaybeUninit}; +trait Ext { + const IS_ZST: bool; +} + +impl Ext for T { + const IS_ZST: bool = mem::size_of::() == 0; +} + /// [`core::array::try_from_fn`] pub(crate) fn try_from_fn(mut cb: F) -> Result<[T; N], E> where @@ -81,6 +90,7 @@ unsafe fn array_assume_init(array: [MaybeUninit; N]) -> [T unsafe { transpose(array).assume_init() } } +/// [`MaybeUninit::transpose`] #[inline(always)] unsafe fn transpose(array: [MaybeUninit; N]) -> MaybeUninit<[T; N]> { mem::transmute_copy::<[MaybeUninit; N], MaybeUninit<[T; N]>>(&mem::ManuallyDrop::new(&array)) @@ -90,15 +100,30 @@ unsafe fn transpose(array: [MaybeUninit; N]) -> MaybeUnini /// [`Vec::into_flattened`]. #[inline] -pub(crate) fn into_flattened(vec: Vec<[u8; N]>) -> Vec { +pub(crate) fn into_flattened(vec: Vec<[T; N]>) -> Vec { let (ptr, len, cap) = into_raw_parts(vec); - unsafe { - Vec::from_raw_parts( - ptr.cast(), - len.checked_mul(N).unwrap_unchecked(), - cap.checked_mul(N).unwrap_unchecked(), - ) - } + let (new_len, new_cap) = if T::IS_ZST { + (len.checked_mul(N).expect("vec len overflow"), usize::MAX) + } else { + // SAFETY: + // - `cap * N` cannot overflow because the allocation is already in + // the address space. + // - Each `[T; N]` has `N` valid elements, so there are `len * N` + // valid elements in the allocation. + unsafe { + ( + len.checked_mul(N).unwrap_unchecked(), + cap.checked_mul(N).unwrap_unchecked(), + ) + } + }; + // SAFETY: + // - `ptr` was allocated by `self` + // - `ptr` is well-aligned because `[T; N]` has the same alignment as `T`. + // - `new_cap` refers to the same sized allocation as `cap` because + // `new_cap * size_of::()` == `cap * size_of::<[T; N]>()` + // - `len` <= `cap`, so `len * N` <= `cap * N`. + unsafe { Vec::from_raw_parts(ptr.cast(), new_len, new_cap) } } /// [`Vec::into_raw_parts`]