diff --git a/zerocopy/src/pointer/transmute.rs b/zerocopy/src/pointer/transmute.rs index 7aabb149de..114e5bf0f3 100644 --- a/zerocopy/src/pointer/transmute.rs +++ b/zerocopy/src/pointer/transmute.rs @@ -241,8 +241,35 @@ macro_rules! unsafe_impl_shared_compatible { }}; } -impl_transitive_transmute_from!(T => MaybeUninit => T => Wrapping); -impl_transitive_transmute_from!(T => Wrapping => T => MaybeUninit); +impl_transitive_size_eq!(T => MaybeUninit => T => Wrapping); + +// FIXME: The pinned extractor makes MaybeUninit opaque without retaining its +// storage. These two conditional impls need that model before they can carry +// invariant_proof markers. +// +// SAFETY: The standard library guarantees that `MaybeUninit` and +// `Wrapping` have the same size as `T`. Thus both conditional bounds apply: +// `T: TransmuteFrom, Safe, Safe>` preserves bit validity, and +// `Wrapping: TransmuteFrom` preserves it again. +unsafe impl TransmuteFrom, Safe, Safe> for Wrapping +where + T: TransmuteFrom, Safe, Safe>, + Wrapping: TransmuteFrom, +{ +} + +impl_transitive_size_eq!(T => Wrapping => T => MaybeUninit); + +// SAFETY: All three types have the same size, as justified above. Thus both +// conditional bounds apply: `T: TransmuteFrom, Safe, Safe>` preserves +// bit validity, and `MaybeUninit: TransmuteFrom` preserves it +// again. +unsafe impl TransmuteFrom, Safe, Safe> for MaybeUninit +where + T: TransmuteFrom, Safe, Safe>, + MaybeUninit: TransmuteFrom, +{ +} // SAFETY: `ManuallyDrop` has the same size and bit validity as `T` [1], and // implements `Deref` [2]. Thus, it is already possible for safe @@ -336,9 +363,9 @@ impl SizeEq for T { type CastFrom = cast::IdCast; } -// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of -// initialized bit patterns, which is exactly the set allowed in the referent of -// any `Initialized` `Ptr`. +// SAFETY: `Src: IntoBytes` guarantees that every valid representation of +// `Src` is entirely initialized. If the referent widths agree, those same +// bytes satisfy `Initialized` for `Dst`. unsafe impl TransmuteFrom for Dst where Src: IntoBytes + ?Sized, @@ -347,8 +374,8 @@ where } // SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the -// referent of a `Ptr`. This is exactly equal to the set of -// bit patterns which may appear in the referent of any `Initialized` `Ptr`. +// referent of a `Ptr`. If the referent widths agree, +// `Initialized` source bytes therefore satisfy `Safe` for `Dst`. unsafe impl TransmuteFrom for Dst where Src: ?Sized, @@ -393,14 +420,31 @@ where // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` +unsafe impl TransmuteFrom for ManuallyDrop {} + +// SAFETY: By the preceding safety proof, `ManuallyDrop` and `T` have the +// same bit validity. +unsafe impl TransmuteFrom, Safe, Safe> for T {} + +// SAFETY: By the preceding safety proof, `ManuallyDrop` and `T` have the +// same size in both cast directions. #[allow(clippy::multiple_unsafe_ops_per_block)] -const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => ManuallyDrop) }; +const _: () = + unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => ManuallyDrop) }; // SAFETY: // - `Unalign` promises to have the same size as `T`. // - `Unalign` promises to have the same validity as `T`. +unsafe impl TransmuteFrom for Unalign {} + +// SAFETY: By the preceding safety proof, `Unalign` and `T` have the +// same bit validity. +unsafe impl TransmuteFrom, Safe, Safe> for T {} + +// SAFETY: By the preceding safety proof, `Unalign` and `T` have the +// same size in both cast directions. #[allow(clippy::multiple_unsafe_ops_per_block)] -const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign) }; +const _: () = unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T => Unalign) }; // SAFETY: `Unalign` promises to have the same size and validity as `T`. // Given `u: &Unalign`, it is already possible to obtain `let t = // u.try_deref().unwrap()`. Because `Unalign` has the same size as `T`, the @@ -432,8 +476,16 @@ const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Unalign) }; // #[repr(transparent)] // pub struct Wrapping(pub T); // ``` +unsafe impl TransmuteFrom for Wrapping {} + +// SAFETY: By the preceding safety proof, `Wrapping` and `T` have the +// same bit validity. +unsafe impl TransmuteFrom, Safe, Safe> for T {} + +// SAFETY: By the preceding safety proof, `Wrapping` and `T` have the +// same size in both cast directions. #[allow(clippy::multiple_unsafe_ops_per_block)] -const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping) }; +const _: () = unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T => Wrapping) }; // SAFETY: By the preceding safety proof, `Wrapping` and `T` have the same // layout and bit validity. Since a `Wrapping`'s `T` field is `pub`, given @@ -454,8 +506,17 @@ const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Wrapping) }; // `UnsafeCell` has the same in-memory representation as its inner type // `T`. A consequence of this guarantee is that it is possible to convert // between `T` and `UnsafeCell`. +unsafe impl TransmuteFrom for UnsafeCell {} + +// SAFETY: By the preceding safety proof, `UnsafeCell` and `T` have the +// same bit validity. +unsafe impl TransmuteFrom, Safe, Safe> for T {} + +// SAFETY: By the preceding safety proof, `UnsafeCell` and `T` have the +// same size in both cast directions. #[allow(clippy::multiple_unsafe_ops_per_block)] -const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => UnsafeCell) }; +const _: () = + unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => UnsafeCell) }; // SAFETY: // - `Cell` has the same size as `T` [1]. @@ -476,11 +537,43 @@ const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Uns // `UnsafeCell` has the same in-memory representation as its inner type // `T`. A consequence of this guarantee is that it is possible to convert // between `T` and `UnsafeCell`. +unsafe impl TransmuteFrom for Cell {} + +// SAFETY: By the preceding safety proof, `Cell` and `T` have the +// same bit validity. +unsafe impl TransmuteFrom, Safe, Safe> for T {} + +// SAFETY: By the preceding safety proof, `Cell` and `T` have the +// same size in both cast directions. #[allow(clippy::multiple_unsafe_ops_per_block)] -const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Cell) }; +const _: () = + unsafe { unsafe_impl_transparent_wrapper_casts_and_size_eq!(pub T: ?Sized => Cell) }; + +impl_transitive_size_eq!(T: ?Sized => Cell => T => UnsafeCell); + +// SAFETY: `Cell` and `UnsafeCell` have the same size as `T`, as justified +// above. Thus both conditional bounds apply: `T: TransmuteFrom, Safe, +// Safe>` preserves bit validity, and `UnsafeCell: TransmuteFrom` preserves it again. +unsafe impl TransmuteFrom, Safe, Safe> for UnsafeCell +where + T: TransmuteFrom, Safe, Safe>, + UnsafeCell: TransmuteFrom, +{ +} + +impl_transitive_size_eq!(T: ?Sized => UnsafeCell => T => Cell); -impl_transitive_transmute_from!(T: ?Sized => Cell => T => UnsafeCell); -impl_transitive_transmute_from!(T: ?Sized => UnsafeCell => T => Cell); +// SAFETY: All three types have the same size, as justified above. Thus both +// conditional bounds apply: `T: TransmuteFrom, Safe, Safe>` +// preserves bit validity, and `Cell: TransmuteFrom` preserves +// it again. +unsafe impl TransmuteFrom, Safe, Safe> for Cell +where + T: TransmuteFrom, Safe, Safe>, + Cell: TransmuteFrom, +{ +} // SAFETY: `MaybeUninit` has no validity requirements. Currently this is not // explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation diff --git a/zerocopy/src/util/macros.rs b/zerocopy/src/util/macros.rs index a12e7b4001..f106537058 100644 --- a/zerocopy/src/util/macros.rs +++ b/zerocopy/src/util/macros.rs @@ -743,26 +743,20 @@ macro_rules! define_cast { }; } -/// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper`. +/// Implements casts and `SizeEq` for `T` and `$wrapper`. /// /// # Safety /// -/// `T` and `$wrapper` must have the same bit validity, and must have the -/// same size in the sense of `CastExact` (specifically, both a -/// `T`-to-`$wrapper` cast and a `$wrapper`-to-`T` cast must be -/// size-preserving). -macro_rules! unsafe_impl_for_transparent_wrapper { +/// `T` and `$wrapper` must have the same size in the sense of `CastExact` +/// (specifically, both a `T`-to-`$wrapper` cast and a `$wrapper`-to-`T` +/// cast must be size-preserving). +macro_rules! unsafe_impl_transparent_wrapper_casts_and_size_eq { ($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident) => {{ crate::util::macros::__unsafe(); - use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Safe}; + use crate::pointer::{cast::{CastExact, TransitiveProject}, SizeEq}; use crate::wrappers::ReadOnly; - // SAFETY: The caller promises that `T` and `$wrapper` have the same - // bit validity. - unsafe impl TransmuteFrom for $wrapper {} - // SAFETY: See previous safety comment. - unsafe impl TransmuteFrom<$wrapper, Safe, Safe> for T {} // SAFETY: The caller promises that a `T` to `$wrapper` cast is // size-preserving. define_cast!(unsafe { $vis CastToWrapper = T => $wrapper }); @@ -815,10 +809,10 @@ macro_rules! unsafe_impl_for_transparent_wrapper { }}; } -macro_rules! impl_transitive_transmute_from { +macro_rules! impl_transitive_size_eq { ($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => { const _: () = { - use crate::pointer::{TransmuteFrom, SizeEq, invariant::Safe}; + use crate::pointer::SizeEq; impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v where @@ -831,16 +825,6 @@ macro_rules! impl_transitive_transmute_from { <$v as SizeEq<$u>>::CastFrom >; } - - // SAFETY: Since `$u: TransmuteFrom<$t, Safe, Safe>`, it is sound to - // transmute a bit-valid `$t` to a bit-valid `$u`. Since `$v: - // TransmuteFrom<$u, Safe, Safe>`, it is sound to transmute that - // bit-valid `$u` to a bit-valid `$v`. - unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Safe, Safe> for $v - where - $u: TransmuteFrom<$t, Safe, Safe>, - $v: TransmuteFrom<$u, Safe, Safe>, - {} }; }; }