diff --git a/src/impls.rs b/src/impls.rs index 0a552d5231..4cf7360852 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -443,13 +443,13 @@ mod atomics { use super::*; macro_rules! impl_traits_for_atomics { - ($($atomics:ident),* $(,)?) => { + ($($atomics:ident[$repr:ty]),* $(,)?) => { $( impl_known_layout!($atomics); - impl_for_transparent_wrapper!(=> TryFromBytes for $atomics); - impl_for_transparent_wrapper!(=> FromZeros for $atomics); - impl_for_transparent_wrapper!(=> FromBytes for $atomics); - impl_for_transparent_wrapper!(=> IntoBytes for $atomics); + impl_for_transmute_from!(=> TryFromBytes for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> FromZeros for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> FromBytes for $atomics[UnsafeCell<$repr>]); + impl_for_transmute_from!(=> IntoBytes for $atomics[UnsafeCell<$repr>]); )* }; } @@ -461,13 +461,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU8, AtomicI8); + impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); impl_known_layout!(AtomicBool); - impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool); - impl_for_transparent_wrapper!(=> FromZeros for AtomicBool); - impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool); + impl_for_transmute_from!(=> TryFromBytes for AtomicBool[UnsafeCell]); + impl_for_transmute_from!(=> FromZeros for AtomicBool[UnsafeCell]); + impl_for_transmute_from!(=> IntoBytes for AtomicBool[UnsafeCell]); safety_comment! { /// SAFETY: @@ -497,7 +497,7 @@ mod atomics { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); + unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); } } @@ -508,13 +508,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU16, AtomicI16); + impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); + unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); } } @@ -525,13 +525,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU32, AtomicI32); + impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); + unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); } } @@ -542,13 +542,13 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU64, AtomicI64); + impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]); safety_comment! { /// SAFETY: /// All of these pass an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); + unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); } } @@ -559,21 +559,21 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicUsize, AtomicIsize); + impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]); impl_known_layout!(T => AtomicPtr); // TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement // those traits for `*mut T`. - impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr); - impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr); + impl_for_transmute_from!(T => TryFromBytes for AtomicPtr[UnsafeCell<*mut T>]); + impl_for_transmute_from!(T => FromZeros for AtomicPtr[UnsafeCell<*mut T>]); safety_comment! { /// SAFETY: /// This passes an atomic type and that type's native equivalent, as /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); - unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr [*mut T]); + unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); + unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr [*mut T]); } } } @@ -603,12 +603,12 @@ safety_comment! { assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping); -impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping); -impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping); -impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping); -impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping); +impl_for_transmute_from!(T: Immutable => Immutable for Wrapping[T]); +impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping[T]); +impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping[T]); +impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping[T]); +impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping[T]); +impl_for_transmute_from!(T: Unaligned => Unaligned for Wrapping[T]); assert_unaligned!(Wrapping<()>, Wrapping); safety_comment! { @@ -620,22 +620,22 @@ safety_comment! { unsafe_impl!(T => FromBytes for MaybeUninit); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit); +impl_for_transmute_from!(T: Immutable => Immutable for MaybeUninit[T]); +impl_for_transmute_from!(T: Unaligned => Unaligned for MaybeUninit[T]); assert_unaligned!(MaybeUninit<()>, MaybeUninit); -impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); +impl_for_transmute_from!(T: ?Sized + Immutable => Immutable for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop[T]); +impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop[T]); assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell); +impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell[T]); +impl_for_transmute_from!(T: ?Sized + Unaligned => Unaligned for UnsafeCell[T]); assert_unaligned!(UnsafeCell<()>, UnsafeCell); // SAFETY: See safety comment in `is_bit_valid` impl. diff --git a/src/lib.rs b/src/lib.rs index 32218dc8b4..d743557e2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2720,7 +2720,7 @@ unsafe fn try_read_from( // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. let c_ptr = Ptr::from_mut(&mut candidate); - let c_ptr = c_ptr.transparent_wrapper_into_inner(); + let c_ptr = c_ptr.transmute::<_, pointer::transmute::BecauseBidirectional>(); // SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from // `candidate`, which the caller promises is entirely initialized. let c_ptr = unsafe { c_ptr.assume_validity::() }; diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index dc11465940..f39676ac83 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -13,6 +13,8 @@ //! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) //! triples implementing the [`Invariants`] trait. +use super::*; + /// The invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; @@ -54,8 +56,23 @@ impl Invariants for (A, AA, V) { type WithValidity = (A, AA, VB); } +// NOTE: The `AliasingInner`/`Aliasing` distinction is required so that we can +// add a `MappedTo = Self` bound. For an explanation of the design +// space (and prior attempts), see: +// https://users.rust-lang.org/t/how-to-implement-a-type-level-map-with-an-identity-function/119745 +#[doc(hidden)] +pub trait AliasingInner: Sealed { + // type MappedTo: Aliasing; +} + /// The aliasing invariant of a [`Ptr`][super::Ptr]. -pub trait Aliasing: Sealed { +pub trait Aliasing: + // AliasingInner = Self> + // // + AliasingInner = Inaccessible> + // + AliasingInner = Shared> + // + AliasingInner = Exclusive> + Sealed +{ /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; @@ -67,51 +84,77 @@ pub trait Aliasing: Sealed { type Variance<'a, T: 'a + ?Sized>; } -/// The alignment invariant of a [`Ptr`][super::Ptr]. -pub trait Alignment: Sealed { - #[doc(hidden)] +#[doc(hidden)] +pub trait AlignmentInner: Sealed { type MappedTo: Alignment; } -/// The validity invariant of a [`Ptr`][super::Ptr]. -pub trait Validity: Sealed { - #[doc(hidden)] +/// The alignment invariant of a [`Ptr`][super::Ptr]. +pub trait Alignment: + AlignmentInner = Self> + + AlignmentInner = Unknown> + + AlignmentInner = Aligned> + + Sealed +{ +} +impl< + A: AlignmentInner = Self> + + AlignmentInner = Unknown> + + AlignmentInner = Aligned>, + > Alignment for A +{ +} + +#[doc(hidden)] +pub trait ValidityInner: Sealed { type MappedTo: Validity; } +/// The validity invariant of a [`Ptr`][super::Ptr]. +pub trait Validity: + ValidityInner = Self> + + ValidityInner = Unknown> + + ValidityInner = AsInitialized> + + ValidityInner = Initialized> + + ValidityInner = Valid> + + Sealed +{ +} +impl< + V: ValidityInner = Self> + + ValidityInner = Unknown> + + ValidityInner = AsInitialized> + + ValidityInner = Initialized> + + ValidityInner = Valid>, + > Validity for V +{ +} + /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. /// /// # Safety /// /// Given `A: Reference`, callers may assume that either `A = Shared` or `A = /// Exclusive`. -pub trait Reference: Aliasing + Sealed {} +pub trait Reference: Aliasing + Sealed { + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O; +} /// It is unknown whether any invariant holds. pub enum Unknown {} -impl Alignment for Unknown { +impl AlignmentInner for Unknown { type MappedTo = M::FromUnknown; } -impl Validity for Unknown { +impl ValidityInner for Unknown { type MappedTo = M::FromUnknown; } -/// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. -pub enum Inaccessible {} - -impl Aliasing for Inaccessible { - const IS_EXCLUSIVE: bool = false; - - // SAFETY: Inaccessible `Ptr`s permit neither reads nor writes, and so it - // doesn't matter how long the referent actually lives. Thus, covariance is - // fine (and is chosen because it is maximally permissive). Shared - // references are covariant [1]. - // - // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance - type Variance<'a, T: 'a + ?Sized> = &'a T; -} - /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// /// The referent of a shared-aliased `Ptr` may be concurrently referenced by any @@ -121,11 +164,25 @@ impl Aliasing for Inaccessible { /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub enum Shared {} +impl AliasingInner for Shared { + // type MappedTo = M::FromShared; +} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; type Variance<'a, T: 'a + ?Sized> = &'a T; } -impl Reference for Shared {} +impl Reference for Shared { + #[inline(always)] + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, shared: S, _exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + { + shared(ptr.unify_invariants()) + } +} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. /// @@ -133,16 +190,30 @@ impl Reference for Shared {} /// referenced by any other `Ptr`s or references, and may not be accessed (read /// or written) other than via this `Ptr`. pub enum Exclusive {} +impl AliasingInner for Exclusive { + // type MappedTo = M::FromExclusive; +} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; type Variance<'a, T: 'a + ?Sized> = &'a mut T; } -impl Reference for Exclusive {} +impl Reference for Exclusive { + #[inline(always)] + fn with<'a, T, I, S, E, O>(ptr: Ptr<'a, T, I>, _shared: S, exclusive: E) -> O + where + T: 'a + ?Sized, + I: Invariants, + S: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + E: FnOnce(Ptr<'a, T, I::WithAliasing>) -> O, + { + exclusive(ptr.unify_invariants()) + } +} -/// The referent is aligned: for `Ptr`, the referent's address is a -/// multiple of the `T`'s alignment. +/// The referent is aligned: for `Ptr`, the referent's address is a multiple +/// of the `T`'s alignment. pub enum Aligned {} -impl Alignment for Aligned { +impl AlignmentInner for Aligned { type MappedTo = M::FromAligned; } @@ -173,20 +244,20 @@ impl Alignment for Aligned { /// enum type, in which case the same rules apply depending on the state of /// its discriminant, and so on recursively). pub enum AsInitialized {} -impl Validity for AsInitialized { +impl ValidityInner for AsInitialized { type MappedTo = M::FromAsInitialized; } -/// The byte ranges in the referent are fully initialized. In other words, if -/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. +/// The byte ranges in the referent are fully initialized. In other words, +/// if the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. pub enum Initialized {} -impl Validity for Initialized { +impl ValidityInner for Initialized { type MappedTo = M::FromInitialized; } /// The referent is bit-valid for `T`. pub enum Valid {} -impl Validity for Valid { +impl ValidityInner for Valid { type MappedTo = M::FromValid; } @@ -234,7 +305,7 @@ mod sealed { impl Sealed for Unknown {} - impl Sealed for Inaccessible {} + // impl Sealed for Inaccessible {} impl Sealed for Shared {} impl Sealed for Exclusive {} @@ -285,6 +356,12 @@ mod mapping { type FromValid: Validity; } + /// A mapping which preserves all invariants as-is. + /// + /// `Preserved` is a valid type for any mapping trait ([`Mapping`], + /// [`AliasingMapping`], [`AlignmentMapping`], and [`ValidityMapping`]). + pub enum Preserved {} + /// The application of the [`AlignmentMapping`] `M` to the [`Alignment`] `A`. #[allow(type_alias_bounds)] pub type MappedAlignment = A::MappedTo; @@ -294,12 +371,27 @@ mod mapping { pub type MappedValidity = V::MappedTo; impl AlignmentMapping - for ((Unknown, FromUnknown), (Shared, FromAligned)) + for ((Unknown, FromUnknown), (Aligned, FromAligned)) { type FromUnknown = FromUnknown; type FromAligned = FromAligned; } + impl AlignmentMapping for Unknown { + type FromUnknown = Unknown; + type FromAligned = Unknown; + } + + impl AlignmentMapping for Preserved { + type FromUnknown = Unknown; + type FromAligned = Aligned; + } + + impl AlignmentMapping for Aligned { + type FromUnknown = Aligned; + type FromAligned = Aligned; + } + impl< FromUnknown: Validity, FromAsInitialized: Validity, @@ -325,4 +417,39 @@ mod mapping { type FromInitialized = FromInitialized; type FromValid = Unknown; } + + impl ValidityMapping for Unknown { + type FromUnknown = Unknown; + type FromAsInitialized = Unknown; + type FromInitialized = Unknown; + type FromValid = Unknown; + } + + impl ValidityMapping for Preserved { + type FromUnknown = Unknown; + type FromAsInitialized = AsInitialized; + type FromInitialized = Initialized; + type FromValid = Valid; + } + + impl ValidityMapping for AsInitialized { + type FromUnknown = AsInitialized; + type FromAsInitialized = AsInitialized; + type FromInitialized = AsInitialized; + type FromValid = AsInitialized; + } + + impl ValidityMapping for Initialized { + type FromUnknown = Initialized; + type FromAsInitialized = Initialized; + type FromInitialized = Initialized; + type FromValid = Initialized; + } + + impl ValidityMapping for Valid { + type FromUnknown = Valid; + type FromAsInitialized = Valid; + type FromInitialized = Valid; + type FromValid = Valid; + } } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 74219b7faa..99785c0f3e 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -172,9 +172,7 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::pointer::transmute::{ - AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance, - }; + use crate::pointer::transmute::TransmuteFromPtr; /// `&'a T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> @@ -350,49 +348,42 @@ mod _conversions { } } - /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` + /// `Ptr<'a, T>` → `Ptr<'a, U>` impl<'a, T, I> Ptr<'a, T, I> where - T: 'a + TransparentWrapper + ?Sized, + T: 'a + ?Sized, I: Invariants, { - /// Converts `self` to a transparent wrapper type into a `Ptr` to the - /// wrapped inner type. - pub(crate) fn transparent_wrapper_into_inner( + pub(crate) fn transmute( self, ) -> Ptr< 'a, - T::Inner, + U, ( I::Aliasing, - >::Applied, - >::Applied, + MappedAlignment, + MappedValidity, ), - > { + > + where + U: ?Sized + TransmuteFromPtr, + { // SAFETY: - // - By invariant on `TransparentWrapper::cast_into_inner`: + // - By invariant on `TransmuteFrom::cast_from`: // - This cast preserves address and referent size, and thus the // returned pointer addresses the same bytes as `p` // - This cast preserves provenance - // - By invariant on `TransparentWrapper`, `T` and `T::Inner` have `UnsafeCell`s at the same - // byte ranges. Since `p` and the returned pointer address the - // same byte range, they refer to `UnsafeCell`s at the same byte - // ranges. - let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; - // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the alignment invariant `I::Alignment`, `c` (of type - // `T::Inner`) satisfies the given "applied" alignment invariant. - let c = unsafe { - c.assume_alignment::<>::Applied>() - }; - // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the validity invariant `I::Validity`, `c` (of type - // `T::Inner`) satisfies the given "applied" validity invariant. - let c = unsafe { - c.assume_validity::<>::Applied>() - }; - c + // - By invariant on `TransmuteFromPtr`, if `A` is `Shared`, then + // `T` and `U` have `UnsafeCell`s at the same byte ranges + let ptr = unsafe { self.cast_unsized_unchecked(|p| U::cast_from(p)) }; + // SAFETY: By invariant on `TransmuteFromPtr`, it is sound to treat + // the resulting pointer as having alignment + // `MappedAlignment`. + let ptr = unsafe { ptr.assume_alignment() }; + // SAFETY: By invariant on `TransmuteFromPtr`, it is sound to treat + // the resulting pointer as having validity + // `MappedValidity`. + unsafe { ptr.assume_validity() } } } @@ -478,7 +469,7 @@ mod _transitions { /// # Safety /// /// The caller promises that `self` satisfies the invariants `H`. - const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { + pub(super) const unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs index 113eb60ec3..5b9af61105 100644 --- a/src/pointer/transmute.rs +++ b/src/pointer/transmute.rs @@ -12,116 +12,207 @@ use core::{ num::Wrapping, }; -use crate::{ - pointer::invariant::{self, Invariants}, - Unalign, -}; +use crate::{pointer::invariant::*, Unalign}; -/// A type which has the same layout as the type it wraps. +/// A type which supports pointer casting from another type, `T`. /// /// # Safety /// -/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`]. -/// Further, `T: TransparentWrapper` implies that: -/// - If `T::UnsafeCellVariance = Covariant`, then `T` has `UnsafeCell`s -/// covering the same byte ranges as `T::Inner`. -/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then -/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant -/// `>::Applied`. -/// - If a `T` pointer satisfies the validity invariant `I::Validity`, then that -/// same pointer, cast to `T::Inner`, satisfies the validity invariant -/// `>::Applied`. +/// If `U: TransmuteFromPtr`, then given `t: *const T` which satisfies +/// aliasing `A`, alignment `AA`, and validity `V`, it is sound to treat `t as +/// *const U` as a pointer with aliasing `A`, alignment `MappedAlignment>::AlignmentMapping>`, and validity `MappedValidity>::ValidityMapping>`. /// -/// [`T::Inner`]: TransparentWrapper::Inner -/// [`UnsafeCell`]: core::cell::UnsafeCell -/// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance -/// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance -#[doc(hidden)] -pub unsafe trait TransparentWrapper { - type Inner: ?Sized; - - type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; - - /// Casts a wrapper pointer to an inner pointer. - /// - /// # Safety - /// - /// The resulting pointer has the same address and provenance as `ptr`, and - /// addresses the same number of bytes. - fn cast_into_inner(ptr: *mut Self) -> *mut Self::Inner; - - /// Casts an inner pointer to a wrapper pointer. - /// - /// # Safety - /// - /// The resulting pointer has the same address and provenance as `ptr`, and - /// addresses the same number of bytes. - fn cast_from_inner(ptr: *mut Self::Inner) -> *mut Self; +/// If `A` is `Shared`, then this implies that, in the region referred to by +/// both `t` and `u`, `*t` and `*u` contain `UnsafeCell`s at the same byte +/// ranges. Thus, for `Shared` aliasing, it is not possible for `t` to perform +/// interior mutation which violates `u`'s `Shared` aliasing invariant, or +/// vice-versa. +#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, marker)] +pub(crate) unsafe trait TransmuteFromPtr: + TransmuteFrom +{ } -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; +// SAFETY: Let `t: *const T` satisfying `Shared` aliasing, alignment `A`, and +// validity `V`. Let `u = t as *const U`. By safety invariant on `U: +// TransmuteFrom`, `u` satisfies alignment `MappedAlignment>::AlignmentMapping>`. +/// +/// Because `U: Immutable`, `u` with aliasing `Shared` will not be permitted to +/// write to its referent. Thus, if `t` already satisfies validity `V`, that +/// will continue to hold even though we don't require that `T: +/// TransmuteFrom`. +/// +/// By safety invariant on `U: TransmuteFrom`, `u` satisfies validity +/// `MappedValidity>::ValidityMapping>`. +/// +/// By safety invariant on `T: UnsafeCellsAgree`, `t` and `u` reference +/// `UnsafeCell`s at the same byte ranges (at least within the region of memory +/// which they both address). By `U: Immutable`, that range contains no +/// `UnsafeCell`s. Thus, it is not possible for `u` to be used to perform +/// interior mutation which violate's `t`'s `Shared` aliasing invariant, and +/// vice-versa. +// NOTE: We could equivalently implement this for `T: Immutable, U: Immutable` +// and drop the `UnsafeCellsAgree` bounds. However, this permits us to support +// `T: !Immutable`. Perhaps we should eventually add a second impl with `T: +// Immutable, U: Immutable` instead. +unsafe impl TransmuteFromPtr for U +where + T: ?Sized + UnsafeCellsAgree, + U: ?Sized + TransmuteFrom + UnsafeCellsAgree + crate::Immutable, +{ } -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; +define_because!(pub(crate) BecauseBidirectional); + +// SAFETY: Let `t: *const T` satisfying `Shared` aliasing, alignment `A`, and +// validity `V`. Let `u = t as *const U`. By safety invariant on `U: +// TransmuteFrom`, `u` satisfies alignment `MappedAlignment>::AlignmentMapping>`. +/// +/// TODO: How do we prove that anything written to `*u` won't violate `t`'s +/// validity invariant `V`? We need to reason about every possible `V` *and* +/// every possible `TransmuteFrom::ValidityMapping`. +/// +/// By safety invariant on `U: TransmuteFrom`, `u` satisfies validity +/// `MappedValidity>::ValidityMapping>`. +/// +/// By safety invariant on `T: UnsafeCellsAgree`, `t` and `u` reference +/// `UnsafeCell`s at the same byte ranges (at least within the region of memory +/// which they both address). Thus, if `A` is `Shared`, it is not possible for +/// `u` to be used to perform interior mutation which violate's `t` `Shared` +/// aliasing invariant, and vice-versa. +unsafe impl TransmuteFromPtr for U +where + A: Aliasing, + T: ?Sized + TransmuteFrom + UnsafeCellsAgree, + U: ?Sized + TransmuteFrom + UnsafeCellsAgree, +{ } -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Covariant {} +define_because!(BecauseExclusive); -impl AlignmentVariance for Covariant { - type Applied = I; +// SAFETY: Let `t: *const T` satisfying `Shared` aliasing, alignment `A`, and +// validity `V`. Let `u = t as *const U`. By safety invariant on `U: +// TransmuteFrom`, `u` satisfies alignment `MappedAlignment>::AlignmentMapping>`. +/// +/// Because `U: Immutable`, `u` with aliasing `Shared` will not be permitted to +/// write to its referent. Thus, if `t` already satisfies validity `V`, that +/// will continue to hold even though we don't require that `T: +/// TransmuteFrom`. +/// +/// By safety invariant on `U: TransmuteFrom`, `u` satisfies validity +/// `MappedValidity>::ValidityMapping>`. +/// +/// Because this is only implemented for `Exclusive` aliasing, `UnsafeCell`s are +/// not a concern. +unsafe impl TransmuteFromPtr for U +where + T: ?Sized + TransmuteFrom, + U: ?Sized + TransmuteFrom, +{ } -impl ValidityVariance for Covariant { - type Applied = I; +/// Pairs of types which have `UnsafeCells` covering the same byte ranges. +/// +/// # Safety +/// +/// Let `t: &T` and `u: &U`. Let `len = min(size_of_val(t), size_of_val(u))`. If +/// `U: UnsafeCellsAgree`, then the first `len` bytes of `t` and the first +/// `len` bytes of `u` have `UnsafeCell`s covering the same byte ranges. This +/// condition must hold for all `t: &T` and for all `u: &U`. +/// +/// Note that this safety invariant supports either or both of `T` and `U` being +/// unsized. +pub(crate) unsafe trait UnsafeCellsAgree +where + T: UnsafeCellsAgree, +{ } -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Invariant {} +// SAFETY: `T` has `UnsafeCell`s covering the same byte ranges as itself by +// definition. +unsafe impl UnsafeCellsAgree for T {} -impl AlignmentVariance for Invariant { - type Applied = invariant::Unknown; +/// A type which can be transmuted from another type, `T`. +/// +/// # Safety +/// +/// If `U: TransmuteFrom`, then the following must hold: +/// - Given `t: *const T`, `t as *const U` must produce a pointer which +/// references the same number of bytes as `t` +/// - If `t: *const T` satisfies the alignment invariant `A`, then `t as *const +/// U` satisfies the alignment invariant `MappedAlignment` +/// - If `t: *const T` satisfies the validity invariant `V`, then `t as *const +/// U` satisfies the validity invariant `MappedValidity` +// TODO(#1940): Relax the safety invariant to support size mismatch and pairs of +// types which require a metadata fix-up. +pub(crate) unsafe trait TransmuteFrom { + type AlignmentMapping: AlignmentMapping; + type ValidityMapping: ValidityMapping; + + /// Casts a `*mut T` to a `*mut Self`. + /// + /// # Safety + /// + /// The resulting pointer has the same address and provenance as `ptr`, and + /// addresses the same number of bytes. + fn cast_from(ptr: *mut T) -> *mut Self; } -impl ValidityVariance for Invariant { - type Applied = invariant::Unknown; +// SAFETY: +// - Given `t: *const T`, `t as *const T` is a no-op, and so trivially produces +// a pointer which references the same number of bytes as `t` +// - Alignment: See inline safety comment. +// - Validity: See inline safety comment. +unsafe impl TransmuteFrom for T { + // Given a `t: *const T` with alignment `A`, `t as *const T` is a no-op, and + // so trivially satisfies the alignment invariant `MappedAlignment = A`. + type AlignmentMapping = Preserved; + // Given a `t: *const T` with validity `V`, `t as *const T` is a no-op, and + // so trivially satisfies the validity invariant `MappedValidity = V`. + type ValidityMapping = Preserved; + + fn cast_from(ptr: *mut T) -> *mut T { + // SAFETY: `ptr` trivially preserves address, referent size, and + // provenance. + ptr + } } +// SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges as +// `T`. This is not explicitly documented, but it can be inferred. Per [1] in +// the following safety comment, `MaybeUninit` has the same size as `T`. +// Further, note the signature of `MaybeUninit::assume_init_ref` [1]: +// +// pub unsafe fn assume_init_ref(&self) -> &T +// +// If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s at +// different offsets, this would be unsound. Its existence is proof that this is +// not the case. +// +// [1] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref +unsafe impl UnsafeCellsAgree for MaybeUninit {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + // SAFETY: // - Per [1], `MaybeUninit` has the same size as `T`. -// - See inline comments for other safety justifications. +// - Alignment: See inline safety comment. +// - Validity: See inline safety comment. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` -unsafe impl TransparentWrapper for MaybeUninit { - type Inner = T; - - // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges - // as `Inner = T`. This is not explicitly documented, but it can be - // inferred. Per [1] in the preceding safety comment, `MaybeUninit` has - // the same size as `T`. Further, note the signature of - // `MaybeUninit::assume_init_ref` [2]: - // - // pub unsafe fn assume_init_ref(&self) -> &T - // - // If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s - // at different offsets, this would be unsound. Its existence is proof that - // this is not the case. - // - // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref - type UnsafeCellVariance = Covariant; +unsafe impl TransmuteFrom for MaybeUninit { // SAFETY: Per [1], `MaybeUninit` has the same layout as `T`, and thus // has the same alignment as `T`. // @@ -129,30 +220,60 @@ unsafe impl TransparentWrapper for MaybeUninit { // // `MaybeUninit` is guaranteed to have the same size, alignment, and // ABI as `T`. - type AlignmentVariance = Covariant; - // SAFETY: `MaybeUninit` has no validity invariants. Thus, a valid - // `MaybeUninit` is not necessarily a valid `T`. - type ValidityVariance = Invariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut MaybeUninit) -> *mut T { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() + type AlignmentMapping = Preserved; + // SAFETY: `MaybeUninit` has no validity invariants. Thus, any `m: *const + // MaybeUninit` always satisfies the validity invariant `Valid`. + type ValidityMapping = Valid; + + fn cast_from(ptr: *mut T) -> *mut MaybeUninit { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `T`, it also preserves size. + ptr.cast() } +} - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut MaybeUninit { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() +// SAFETY: +// - Per [1], `MaybeUninit` has the same size as `T`. +// - Alignment: See inline safety comment. +// - Validity: See inline safety comment. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: +// +// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as +// `T` +unsafe impl TransmuteFrom> for T { + // SAFETY: Per [1], `MaybeUninit` has the same layout as `T`, and thus + // has the same alignment as `T`. + // + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: + // + // `MaybeUninit` is guaranteed to have the same size, alignment, and + // ABI as `T`. + type AlignmentMapping = Preserved; + // SAFETY: Any `t: *const T` trivially conforms to the validity invariant + // `Unknown`. + type ValidityMapping = Unknown; + + fn cast_from(ptr: *mut MaybeUninit) -> *mut T { + // SAFETY: `.cast()` preserves address and provenance. Since + // `MaybeUninit` has the same size as `T`, it also preserves size. + ptr.cast() } } +// SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: +// +// `ManuallyDrop` is guaranteed to have the same layout and bit validity as +// `T`, and is subject to the same layout optimizations as `T`. As a +// consequence, it has no effect on the assumptions that the compiler makes +// about its contents. +unsafe impl UnsafeCellsAgree for ManuallyDrop {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + // SAFETY: // - Per [1], `ManuallyDrop` has the same size as `T`. // - See inline comments for other safety justifications. @@ -161,19 +282,37 @@ unsafe impl TransparentWrapper for MaybeUninit { // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` -unsafe impl TransparentWrapper for ManuallyDrop { - type Inner = T; - - // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. +unsafe impl TransmuteFrom for ManuallyDrop { + // SAFETY: Per [1], `ManuallyDrop` has the same layout as `T`, and thus + // has the same alignment as `T`. // - // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit - // validity as `T`, and is subject to the same layout optimizations as - // `T`. As a consequence, it has no effect on the assumptions that the - // compiler makes about its contents. - type UnsafeCellVariance = Covariant; + // validity as `T` + type AlignmentMapping = Preserved; + + // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same bit + // validity as `T`. + type ValidityMapping = Preserved; + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut T) -> *mut ManuallyDrop { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `T`, it also preserves size. + ptr as *mut ManuallyDrop + } +} + +// SAFETY: +// - Per [1], `ManuallyDrop` has the same size as `T`. +// - See inline comments for other safety justifications. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: +// +// `ManuallyDrop` is guaranteed to have the same layout and bit validity as +// `T` +unsafe impl TransmuteFrom> for T { // SAFETY: Per [1], `ManuallyDrop` has the same layout as `T`, and thus // has the same alignment as `T`. // @@ -181,33 +320,34 @@ unsafe impl TransparentWrapper for ManuallyDrop // // `ManuallyDrop` is guaranteed to have the same layout and bit // validity as `T` - type AlignmentVariance = Covariant; + type AlignmentMapping = Preserved; // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same bit // validity as `T`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut ManuallyDrop) -> *mut T { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } + type ValidityMapping = Preserved; - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut ManuallyDrop { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut ManuallyDrop; + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut ManuallyDrop) -> *mut T { + // SAFETY: An `as` cast preserves address and provenance. Since + // `ManuallyDrop` has the same size as `T`, it also preserves size. + ptr as *mut T } } +// SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its single +// field (of type `T`) is public, it would be a breaking change to add or remove +// fields. Thus, we know that `Wrapping` contains a `T` (as opposed to just +// having the same size and alignment as `T`) with no pre- or post-padding. +// Thus, `Wrapping` must have `UnsafeCell`s covering the same byte ranges as +// `Inner = T`. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: +// +// `Wrapping` is guaranteed to have the same layout and ABI as `T`. +unsafe impl UnsafeCellsAgree for Wrapping {} +// SAFETY: See previous safety comment. +unsafe impl UnsafeCellsAgree> for T {} + // SAFETY: // - Per [1], `Wrapping` has the same size as `T`. // - See inline comments for other safety justifications. @@ -215,27 +355,51 @@ unsafe impl TransparentWrapper for ManuallyDrop // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. -unsafe impl TransparentWrapper for Wrapping { - type Inner = T; - - // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its - // single field (of type `T`) is public, it would be a breaking change to - // add or remove fields. Thus, we know that `Wrapping` contains a `T` (as - // opposed to just having the same size and alignment as `T`) with no pre- - // or post-padding. Thus, `Wrapping` must have `UnsafeCell`s covering the - // same byte ranges as `Inner = T`. +unsafe impl TransmuteFrom for Wrapping { + // SAFETY: Per [1], `Wrapping` has the same layout as `T`, and thus has + // the same alignment as `T`. // - // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type UnsafeCellVariance = Covariant; + type AlignmentMapping = Preserved; + + // SAFETY: `Wrapping` has only one field, which is `pub` [2]. We are also + // guaranteed per [1] (from the comment above) that `Wrapping` has the + // same layout as `T`. The only way for both of these to be true + // simultaneously is for `Wrapping` to have the same bit validity as `T`. + // In particular, in order to change the bit validity, one of the following + // would need to happen: + // - `Wrapping` could change its `repr`, but this would violate the layout + // guarantee. + // - `Wrapping` could add or change its fields, but this would be a + // stability-breaking change. + // + // [2] https://doc.rust-lang.org/1.82.0/core/num/struct.Wrapping.html + type ValidityMapping = Preserved; + + fn cast_from(ptr: *mut T) -> *mut Wrapping { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `T`, it also preserves size. + ptr.cast() + } +} + +// SAFETY: +// - Per [1], `Wrapping` has the same size as `T`. +// - See inline comments for other safety justifications. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: +// +// `Wrapping` is guaranteed to have the same layout and ABI as `T`. +unsafe impl TransmuteFrom> for T { // SAFETY: Per [1], `Wrapping` has the same layout as `T`, and thus has // the same alignment as `T`. // // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type AlignmentVariance = Covariant; + type AlignmentMapping = Preserved; // SAFETY: `Wrapping` has only one field, which is `pub` [2]. We are also // guaranteed per [1] (from the comment above) that `Wrapping` has the @@ -248,25 +412,13 @@ unsafe impl TransparentWrapper for Wrapping { // - `Wrapping` could add or change its fields, but this would be a // stability-breaking change. // - // [2] https://doc.rust-lang.org/core/num/struct.Wrapping.html - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Wrapping) -> *mut T { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } + // [2] https://doc.rust-lang.org/1.82.0/core/num/struct.Wrapping.html + type ValidityMapping = Preserved; - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Wrapping { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() + fn cast_from(ptr: *mut Wrapping) -> *mut T { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Wrapping` has the same size as `T`, it also preserves size. + ptr.cast() } } @@ -278,15 +430,43 @@ unsafe impl TransparentWrapper for Wrapping { // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. -unsafe impl TransparentWrapper for UnsafeCell { - type Inner = T; +unsafe impl TransmuteFrom for UnsafeCell { + // SAFETY: Per [1] (from comment on impl), `Unalign` has the same + // representation as `T`, and thus has the same alignment as `T`. + type AlignmentMapping = Preserved; - // SAFETY: Since we set this to `Invariant`, we make no safety claims. - type UnsafeCellVariance = Invariant; + // SAFETY: Per [1], `Unalign` has the same bit validity as `T`. + // Technically the term "representation" doesn't guarantee this, but the + // subsequent sentence in the documentation makes it clear that this is the + // intention. + // + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + // + // `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`. + type ValidityMapping = Preserved; + + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut T) -> *mut UnsafeCell { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `T`, it also preserves size. + ptr as *mut UnsafeCell + } +} +// SAFETY: +// - Per [1], `UnsafeCell` has the same size as `T`. +// - See inline comments for other safety justifications. +// +// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: +// +// `UnsafeCell` has the same in-memory representation as its inner type +// `T`. +unsafe impl TransmuteFrom> for T { // SAFETY: Per [1] (from comment on impl), `Unalign` has the same // representation as `T`, and thus has the same alignment as `T`. - type AlignmentVariance = Covariant; + type AlignmentMapping = Preserved; // SAFETY: Per [1], `Unalign` has the same bit validity as `T`. // Technically the term "representation" doesn't guarantee this, but the @@ -298,62 +478,56 @@ unsafe impl TransparentWrapper for UnsafeCell { // `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`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut UnsafeCell) -> *mut T { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } + type ValidityMapping = Preserved; - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut UnsafeCell { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut UnsafeCell; + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut UnsafeCell) -> *mut T { + // SAFETY: An `as` cast preserves address and provenance. Since + // `UnsafeCell` has the same size as `T`, it also preserves size. + ptr as *mut T } } +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree for Unalign {} +// SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same byte +// ranges as `Inner = T`. +unsafe impl UnsafeCellsAgree> for T {} + // SAFETY: `Unalign` promises to have the same size as `T`. // // See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { - type Inner = T; +unsafe impl TransmuteFrom for Unalign { + // SAFETY: `Unalign` promises to have alignment 1 regardless of `T`'s + // alignment. Thus, any `u: *const Unalign` is always aligned. + type AlignmentMapping = Aligned; - // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. - type UnsafeCellVariance = Covariant; + // SAFETY: `Unalign` promises to have the same validity as `T`. + type ValidityMapping = Preserved; - // SAFETY: Since `Unalign` promises to have alignment 1 regardless of - // `T`'s alignment. Thus, an aligned pointer to `Unalign` is not - // necessarily an aligned pointer to `T`. - type AlignmentVariance = Invariant; + fn cast_from(ptr: *mut T) -> *mut Unalign { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() + } +} + +// SAFETY: `Unalign` promises to have the same size as `T`. +// +// See inline comments for other safety justifications. +unsafe impl TransmuteFrom> for T { + // SAFETY: `Unalign` promises to have alignment 1 regardless of `T`'s + // alignment. Thus, an aligned pointer to `Unalign` is not necessarily an + // aligned pointer to `T`. + type AlignmentMapping = Unknown; // SAFETY: `Unalign` promises to have the same validity as `T`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Unalign) -> *mut T { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } + type ValidityMapping = Preserved; - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Unalign { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() + fn cast_from(ptr: *mut Unalign) -> *mut T { + // SAFETY: `.cast()` preserves address and provenance. Since + // `Unalign` has the same size as `T`, it also preserves size. + ptr.cast() } } diff --git a/src/util/macros.rs b/src/util/macros.rs index 725e75c58d..3a9ecad49a 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -190,160 +190,158 @@ macro_rules! unsafe_impl { }; } -/// Implements `$trait` for a type which implements `TransparentWrapper`. +/// Implements `$trait` for a type which is `TransmuteFrom<$repr>` where `$repr: +/// $trait`. /// /// Calling this macro is safe; the internals of the macro emit appropriate /// trait bounds which ensure that the given impl is sound. -macro_rules! impl_for_transparent_wrapper { +macro_rules! impl_for_transmute_from { ( $(#[$attr:meta])* $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? - => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + => $trait:ident for $ty:ty[$repr:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? ) => { $(#[$attr])* #[allow(non_local_definitions)] // This block implements `$trait` for `$ty` under the following // conditions: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` - // - For some `Xxx`, `$ty::XxxVariance = Covariant` (`Xxx` is determined - // by the `@define_is_transparent_wrapper` macro arms). This bound - // ensures that some layout property is the same between `$ty` and - // `$ty::Inner`. Which layout property this is depends on the trait - // being implemented (for example, `FromBytes` is not concerned with - // alignment, but is concerned with bit validity). + // - `$ty: TransmuteFrom<$repr>` + // - `$repr: $trait` + // - For some invariant `Xxx`, `$ty::Mapping: Mapping` + // (`Xxx` is determined by the `@define_is_transmute_from` macro + // arms). This bound ensures that some layout property is the same + // between `$ty` and `$repr`. Which layout property this is depends on + // the trait being implemented (for example, `FromBytes` is not + // concerned with alignment, but is concerned with bit validity). // // In other words, `$ty` is guaranteed to soundly implement `$trait` - // because some property of its layout is the same as `$ty::Inner`, - // which implements `$trait`. Most of the complexity in this macro is to + // because some property of its layout is the same as `$repr`, which + // implements `$trait`. Most of the complexity in this macro is to // ensure that the above-mentioned conditions are actually met, and that - // the proper variance (ie, the proper layout property) is chosen. + // the proper invariant (ie, the proper layout property) is chosen. // SAFETY: - // - `is_transparent_wrapper` requires: - // - `W: TransparentWrapper` - // - `W::Inner: $trait` - // - `f` is generic over `I: Invariants`, and in its body, calls - // `is_transparent_wrapper::()`. Thus, this code will only - // compile if, for all `I: Invariants`: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` + // - `is_transmute_from` requires: + // - `R: $trait` + // - `T: TransmuteFrom` + // - `T::Mapping: Mapping<$invariant = Preserved>` + // - `is_transmute_from<$repr, $ty>` is called in the body // - // These two facts - that `$ty: TransparentWrapper` and that - // `$ty::Inner: $trait` - are the preconditions to the full safety - // proofs, which are completed below in the - // `@define_is_transparent_wrapper` macro arms. The safety proof is + // This enforces that `$repr: $trait`, `$ty: TransmuteFrom<$repr>`, and + // `$trait::Mapping: Mapping<$invariant = Preserved>`. `$invariant` is + // chosen below in the `@define_is_transmute_from` macro arms, which + // contain the full safety proofs. They use the facts in this safety + // comment as preconditions for their proofs. The safety proof is // slightly different for each trait. unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { - use crate::pointer::{invariant::Invariants, transmute::*}; - - impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); + use crate::pointer::transmute::*; - #[cfg_attr(coverage_nightly, coverage(off))] - const fn f() { - is_transparent_wrapper::(); - } + impl_for_transmute_from!(@define_is_transmute_from $trait); + is_transmute_from::<$repr, $ty>(); } - impl_for_transparent_wrapper!( + impl_for_transmute_from!( @is_bit_valid $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)? - $trait for $ty + $trait for $ty[$repr] ); } }; - (@define_is_transparent_wrapper Immutable) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has `UnsafeCell`s at the same byte offsets as - // `W::Inner`. `W::Inner: Immutable` implies that `W::Inner` does not - // contain any `UnsafeCell`s, and so `W` does not contain any - // `UnsafeCell`s. Since `W = $ty`, `$ty` can soundly implement - // `Immutable`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Immutable, UnsafeCellVariance) - }; - (@define_is_transparent_wrapper FromZeros) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromZeros` implies that the all-zeros bit pattern is a bit-valid - // instance of `W::Inner`, and so the all-zeros bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromZeros`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromZeros, ValidityVariance) - }; - (@define_is_transparent_wrapper FromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromBytes` implies that any initialized bit pattern is a bit-valid - // instance of `W::Inner`, and so any initialized bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper IntoBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // IntoBytes` implies that no bit-valid instance of `W::Inner` contains - // uninitialized bytes, and so no bit-valid instance of `W` contains - // uninitialized bytes. Since `W = $ty`, `$ty` can soundly implement - // `IntoBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper IntoBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper Unaligned) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same alignment as `W::Inner`. `W::Inner: - // Unaligned` implies `W::Inner`'s alignment is 1, and so `W`'s - // alignment is 1. Since `W = $ty`, `W` can soundly implement - // `Unaligned`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Unaligned, AlignmentVariance) - }; - (@define_is_transparent_wrapper TryFromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // TryFromBytes` implies that `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W::Inner`. Thus, ` { + // SAFETY: `T::Mapping: Mapping` ensures that `T` + // and `R` have `UnsafeCell`s at the same byte offsets. If this weren't + // the case, then it would be unsound to map `Shared` to `Shared` when + // transmuting from `R` to `T`. `R: Immutable` implies that `R` has no + // `UnsafeCell`s, and so `T` doesn't either. Since `T = $ty`, `$ty` can + // soundly implement `Immutable`. + #[cfg_attr(coverage_nightly, coverage(off))] + const fn is_transmute_from() + where + R: ?Sized + Immutable + UnsafeCellsAgree, + T: TransmuteFrom + UnsafeCellsAgree + ?Sized, + {} + // impl_for_transmute_from!(@define_is_transmute_from Immutable, AliasingMapping) + }; + (@define_is_transmute_from FromZeros) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: FromZeros` implies that the + // all-zeros bit pattern is a bit-valid instance of `R`, and so the + // all-zeros bit pattern is a bit-valid instance of `T`. Since `T = + // $ty`, `$ty` can soundly implement `FromZeros`. + impl_for_transmute_from!(@define_is_transmute_from FromZeros, ValidityMapping) + }; + (@define_is_transmute_from FromBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: FromBytes` implies that any + // initialized bit pattern is a bit-valid instance of `R`, and so the + // any initialized bit pattern is a bit-valid instance of `T`. Since `T + // = $ty`, `$ty` can soundly implement `FromBytes`. + impl_for_transmute_from!(@define_is_transmute_from FromBytes, ValidityMapping) + }; + (@define_is_transmute_from IntoBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: IntoBytes` implies that no + // bit-valid instance of `R` contains uninitialized bytes, and so no + // bit-valid instance of `T` does either. Since `T = $ty`, `$ty` can + // soundly implement `IntoBytes`. + impl_for_transmute_from!(@define_is_transmute_from IntoBytes, ValidityMapping) + }; + (@define_is_transmute_from Unaligned) => { + // SAFETY: `T::Mapping: Mapping` requires that + // `T` has the same alignment as `R`. `R: Unaligned` implies that + // `align_of::() == 1`, and so `align_of::() == 1`. Since `T = + // $ty`, `$ty` can soundly implement `Unaligned`. + impl_for_transmute_from!(@define_is_transmute_from Unaligned, AlignmentMapping) + }; + (@define_is_transmute_from TryFromBytes) => { + // SAFETY: `T::Mapping: Mapping` requires that `T` + // has the same bit validity as `R`. `R: TryFromBytes` implies that `::is_bit_valid(c)` only returns `true` if `c` + // references a bit-valid instance of `R`. Thus, `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W`. Below, we implement `::is_bit_valid` by deferring to `::is_bit_valid`. Since `W = $ty`, it is sound for `$ty` - // to implement `TryFromBytes` with this implementation of - // `is_bit_valid`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper TryFromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { + // a bit-valid instance of `T`. Below, we implement `::is_bit_valid` by deferring to `::is_bit_valid`. Since `T = $ty`, it is sound for `$ty` + // to implement `TryFromBytes` with this `is_bit_valid` implementation. + impl_for_transmute_from!(@define_is_transmute_from TryFromBytes, ValidityMapping) + }; + (@define_is_transmute_from $trait:ident, $invariant:ident) => { #[cfg_attr(coverage_nightly, coverage(off))] - const fn is_transparent_wrapper + ?Sized>() + const fn is_transmute_from() where - W::Inner: $trait, + R: ?Sized + $trait, + T: TransmuteFrom + ?Sized, + // T::$invariant: crate::pointer::invariant::Mapping<$invariant = crate::pointer::invariant::Preserved> {} }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - TryFromBytes for $ty:ty + TryFromBytes for $ty:ty[$repr:ty] ) => { - // SAFETY: See safety comment in `(@define_is_transparent_wrapper + // SAFETY: See safety comment in `(@define_is_transmute_from // TryFromBytes)` macro arm for an explanation of why this is a sound // implementation of `is_bit_valid`. #[inline] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { - TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) + <$repr as TryFromBytes>::is_bit_valid(candidate.transmute::<$repr, _>()) } }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - $trait:ident for $ty:ty + $trait:ident for $ty:ty[$repr:ty] ) => { // Trait other than `TryFromBytes`; no `is_bit_valid` impl. }; } -/// Implements `TransparentWrapper` for an atomic type. +/// Implements `TransmuteFrom>` for an atomic type and +/// vice-versa. /// /// # Safety /// @@ -356,33 +354,69 @@ macro_rules! impl_for_transparent_wrapper { target_has_atomic = "64", target_has_atomic = "ptr" ))] -macro_rules! unsafe_impl_transparent_wrapper_for_atomic { +macro_rules! unsafe_impl_transmute_from_for_atomic { ($(#[$attr:meta])* $(,)?) => {}; ($(#[$attr:meta])* $atomic:ty [$native:ty], $($atomics:ty [$natives:ty]),* $(,)?) => { $(#[$attr])* // SAFETY: See safety comment in next match arm. - unsafe impl crate::pointer::transmute::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); + unsafe impl crate::pointer::transmute::TransmuteFrom> for $atomic { + // SAFETY: See safety comment in next match arm. + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic | Unknown); + } + // SAFETY: See safety comment in next match arm. + unsafe impl crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + // SAFETY: See safety comment in next match arm. + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native> | Preserved); } - unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); + + // SAFETY: See safety comment in next match arm. + unsafe impl crate::pointer::transmute::UnsafeCellsAgree<$atomic> for UnsafeCell<$native> {} + // SAFETY: See safety comment in next match arm. + unsafe impl crate::pointer::transmute::UnsafeCellsAgree> for $atomic {} + + unsafe_impl_transmute_from_for_atomic!($(#[$attr])* $($atomics [$natives],)*); }; ($(#[$attr:meta])* $tyvar:ident => $atomic:ty [$native:ty]) => { - // We implement for `$atomic` and set `Inner = $native`. The caller has + // We implement `TransmuteFrom<$native>` for `$atomic`. The caller has // promised that `$atomic` and `$native` are an atomic type and its // native counterpart, respectively. Per [1], `$atomic` and `$native` - // have the same size. + // have the same size. Per [1], `$native` and `UnsafeCell<$native>` have + // the same size. // // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: // // This type has the same size and bit validity as the underlying // integer type + // + // [2] Per https://doc.rust-lang.org/1.81.0/std/cell/struct.UnsafeCell.html#memory-layout: + // + // `UnsafeCell` has the same in-memory representation as its inner + // type `T`. $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::pointer::transmute::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom> for $atomic { + // SAFETY: It is always trivially sound to produce a `Ptr` with + // `Unknown` alignment. + unsafe_impl_transmute_from_for_atomic!(@inner UnsafeCell<$native> => $atomic | Unknown); + } + + unsafe impl<$tyvar> crate::pointer::transmute::TransmuteFrom<$atomic> for UnsafeCell<$native> { + // SAFETY: Per [1], an atomic's alignment is equal to its size. This + // is the maximum possible alignment for any non-zero-sized type + // since size must be a multiple of alignment [2]. Thus, if + // `UnsafeCell<$native>` (which has the same size as `$atomic` as + // proven above) is well-aligned, then so is an `$atomic` at the + // same memory address. + // + // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: + // + // However, the alignment of this type is always equal to its + // size, even on targets where `u64`` has a lesser alignment. + // + // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: + // + // The size of a value is always a multiple of its alignment. + unsafe_impl_transmute_from_for_atomic!(@inner $atomic => UnsafeCell<$native> | Preserved); } - }; - (@inner $atomic:ty [$native:ty]) => { - type Inner = UnsafeCell<$native>; // SAFETY: It is "obvious" that each atomic type contains a single // `UnsafeCell` that covers all bytes of the type, but we can also prove @@ -401,47 +435,70 @@ macro_rules! unsafe_impl_transparent_wrapper_for_atomic { // Thus, we can conclude that every byte of `$atomic` must be covered // by an `UnsafeCell`. // - // Thus, every byte of `$atomic` is covered by an `UnsafeCell`, and we - // set `type Inner = UnsafeCell<$native>`. Thus, `Self` and - // `Self::Inner` have `UnsafeCell`s covering the same byte ranges. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - type UnsafeCellVariance = crate::pointer::transmute::Covariant; - - // SAFETY: No safety justification is required for an invariant - // variance. - type AlignmentVariance = crate::pointer::transmute::Invariant; - - // SAFETY: Per [1], all atomic types have the same bit validity as their - // native counterparts. The caller has promised that `$atomic` and - // `$native` are an atomic type and its native counterpart, - // respectively. + // Thus, every byte of `$atomic` is covered by an `UnsafeCell`, and so + // `$atomic` and `UnsafeCell<$native>` have `UnsafeCell`s covering the + // same byte ranges. That is required in order for `Preserved` to be the + // correct aliasing mapping. // // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: // // This type has the same size and bit validity as the underlying // integer type - type ValidityVariance = crate::pointer::transmute::Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut $atomic) -> *mut UnsafeCell<$native> { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. + unsafe impl<$tyvar> crate::pointer::transmute::UnsafeCellsAgree<$atomic> for UnsafeCell<$native> {} + // SAFETY: See above. + unsafe impl<$tyvar> crate::pointer::transmute::UnsafeCellsAgree> for $atomic {} + }; + // # Safety + // + // The caller promises that `$alignment_mapping` is sound. + (@inner $from:ty => $to:ty | $alignment_mapping:ident) => { + // type Mapping = ( + // SAFETY: It is "obvious" that each atomic type contains a single + // `UnsafeCell` that covers all bytes of the type, but we can also + // prove it: + // - Since `$atomic` provides an API which permits loading and + // storing values of type `$native` via a `&self` (shared) + // reference, *some* interior mutation must be happening, and + // interior mutation can only happen via `UnsafeCell`. Further, + // there must be enough bytes in `$atomic` covered by an + // `UnsafeCell` to hold every possible value of `$native`. + // - Per [1], `$atomic` has the same size as `$native`. This on its + // own isn't enough: it would still be possible for `$atomic` to + // store `$native` using a compact representation (for `$native` + // types for which some bit patterns are illegal). However, this + // is ruled out by the fact that `$atomic` has the same bit + // validity as `$native` [1]. Thus, we can conclude that every + // byte of `$atomic` must be covered by an `UnsafeCell`. // - // This cast trivially preserves provenance. - ptr.cast::>() - } + // Thus, every byte of `$atomic` is covered by an `UnsafeCell`, and + // so `$atomic` and `UnsafeCell<$native>` have `UnsafeCell`s + // covering the same byte ranges. That is required in order for + // `Preserved` to be the correct aliasing mapping. + // + // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: + // + // This type has the same size and bit validity as the underlying + // integer type + // type UnsafeCellAgreement = crate::pointer::transmute::UnsafeCellsAgree; + + // The caller guarantees the safety of this mapping. + type AlignmentMapping = crate::pointer::invariant::$alignment_mapping; + // SAFETY: Per [1], all atomic types have the same bit validity as + // their native counterparts. The caller has promised that `$atomic` + // and `$native` are an atomic type and its native counterpart, + // respectively. + // + // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: + // + // This type has the same size and bit validity as the underlying + // integer type + type ValidityMapping = crate::pointer::invariant::Preserved; + // ); #[inline(always)] - fn cast_from_inner(ptr: *mut UnsafeCell<$native>) -> *mut $atomic { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::<$atomic>() + #[allow(clippy::as_conversions)] + fn cast_from(ptr: *mut $from) -> *mut $to { + ptr as *mut $to } }; } diff --git a/src/wrappers.rs b/src/wrappers.rs index ac2442486e..b871c63156 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -9,6 +9,7 @@ use core::hash::Hash; use super::*; +use crate::pointer::transmute::BecauseBidirectional; /// A type with no alignment requirement. /// @@ -200,7 +201,7 @@ impl Unalign { /// may prefer [`Deref::deref`], which is infallible. #[inline(always)] pub fn try_deref(&self) -> Result<&T, AlignmentError<&Self, T>> { - let inner = Ptr::from_ref(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_ref(self).transmute(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_ref()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_ref())), @@ -217,7 +218,7 @@ impl Unalign { /// callers may prefer [`DerefMut::deref_mut`], which is infallible. #[inline(always)] pub fn try_deref_mut(&mut self) -> Result<&mut T, AlignmentError<&mut Self, T>> { - let inner = Ptr::from_mut(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_mut(self).transmute::<_, BecauseBidirectional>(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_mut()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_mut())), @@ -401,14 +402,17 @@ impl Deref for Unalign { #[inline(always)] fn deref(&self) -> &T { - Ptr::from_ref(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_ref() + Ptr::from_ref(self).transmute().bikeshed_recall_aligned().as_ref() } } impl DerefMut for Unalign { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - Ptr::from_mut(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_mut() + Ptr::from_mut(self) + .transmute::<_, BecauseBidirectional>() + .bikeshed_recall_aligned() + .as_mut() } }