From e24c8d39513cee1ac226ee05a2bee3632a5b004a Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 14 Oct 2024 21:14:56 -0700 Subject: [PATCH] [pointer] Support Box and Arc gherrit-pr-id: I7fe90063e148d89e2f75b6fa63a960ad8b1dd432 --- src/impls.rs | 8 +-- src/lib.rs | 28 +++++--- src/pointer/inner.rs | 3 +- src/pointer/invariant.rs | 138 ++++++++++++++++++++++++++---------- src/pointer/mod.rs | 93 +++++++++++++++++++++++- src/pointer/ptr.rs | 42 ++++++++--- src/util/macro_util.rs | 2 +- src/util/macros.rs | 8 +-- zerocopy-derive/src/enum.rs | 2 +- zerocopy-derive/src/lib.rs | 8 +-- 10 files changed, 261 insertions(+), 71 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 4cf7360852..ee55b6bd1e 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -648,7 +648,7 @@ unsafe impl TryFromBytes for UnsafeCell { } #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { // The only way to implement this function is using an exclusive-aliased // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers // (other than by using `unsafe` code, which we can't use since we can't @@ -1124,7 +1124,7 @@ mod tests { pub(super) trait TestIsBitValidShared { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( + fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option; @@ -1132,7 +1132,7 @@ mod tests { impl TestIsBitValidShared for AutorefWrapper { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( + fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option { @@ -1222,7 +1222,7 @@ mod tests { #[allow(unused, non_local_definitions)] impl AutorefWrapper<$ty> { #[allow(clippy::needless_lifetimes)] - fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( + fn test_is_bit_valid_shared<'ptr, A: invariant::ReadFoo>( &mut self, candidate: Maybe<'ptr, $ty, A>, ) -> Option { diff --git a/src/lib.rs b/src/lib.rs index d743557e2c..83cc388d42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1320,7 +1320,7 @@ pub unsafe trait TryFromBytes { /// [`UnsafeCell`]: core::cell::UnsafeCell /// [`Shared`]: invariant::Shared #[doc(hidden)] - fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; /// Attempts to interpret the given `source` as a `&Self`. /// @@ -3458,10 +3458,22 @@ pub unsafe trait FromBytes: FromZeros { where Self: KnownLayout + Immutable, { - static_assert_dst_is_not_zst!(Self); - match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()), - Err(err) => Err(err.map_src(|src| src.as_ref())), + Self::from_bytes(source) + } + + #[must_use = "has no side effects"] + #[inline] + fn from_bytes<'a, P: pointer::Pointer<'a, Self>, R>( + source: P::To<'a, [u8]>, + ) -> Result, Self>> + where + Self: 'a + KnownLayout + invariant::Read, + { + match Ptr::<'_, _, (P::Aliasing, _, _)>::from_pointer(source) + .try_cast_into_no_leftover::<_, R>(None) + { + Ok(ptr) => Ok(ptr.bikeshed_recall_valid().into_pointer()), + Err(err) => Err(err.map_src(|src| src.into_pointer())), } } @@ -3694,11 +3706,7 @@ pub unsafe trait FromBytes: FromZeros { where Self: IntoBytes + KnownLayout, { - static_assert_dst_is_not_zst!(Self); - match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { - Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()), - Err(err) => Err(err.map_src(|src| src.as_mut())), - } + Self::from_bytes(source) } /// Interprets the prefix of the given `source` as a `&mut Self` without diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs index 48d4e8f113..0ddc189534 100644 --- a/src/pointer/inner.rs +++ b/src/pointer/inner.rs @@ -25,7 +25,8 @@ mod _def { /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html - pub(crate) struct PtrInner<'a, T> + #[allow(missing_debug_implementations)] + pub struct PtrInner<'a, T> where T: ?Sized, { diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index 25d67ee61e..e3382b3447 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -13,8 +13,6 @@ //! 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; @@ -82,6 +80,15 @@ pub trait Aliasing: /// Aliasing>::Variance<'a, T>` to inherit this variance. #[doc(hidden)] type Variance<'a, T: 'a + ?Sized>; + + // #[doc(hidden)] + // type Applied<'a, T: 'a + ?Sized>; + + // #[doc(hidden)] + // fn into_ptr<'a, T: 'a + ?Sized>(ptr: Self::Applied<'a, T>) -> PtrInner<'a, T>; + + // #[doc(hidden)] + // unsafe fn from_ptr<'a, T: 'a + ?Sized>(ptr: PtrInner<'a, T>) -> Self::Applied<'a, T>; } #[doc(hidden)] @@ -136,14 +143,7 @@ impl< /// /// Given `A: Reference`, callers may assume that either `A = Shared` or `A = /// Exclusive`. -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; -} +pub trait Reference: ReadFoo + Sealed {} /// It is unknown whether any invariant holds. pub enum Unknown {} @@ -189,18 +189,7 @@ impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; type Variance<'a, T: 'a + ?Sized> = &'a T; } -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()) - } -} +impl Reference for Shared {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. /// @@ -215,16 +204,41 @@ impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; type Variance<'a, T: 'a + ?Sized> = &'a mut T; } -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()) +impl Reference for Exclusive {} + +#[cfg(feature = "alloc")] +pub use _alloc::*; +#[cfg(feature = "alloc")] +mod _alloc { + use alloc::boxed::Box as Bx; + + use super::*; + + pub enum Box {} + impl AliasingInner for Box { + // type MappedTo = M::FromBox; + } + impl Aliasing for Box { + const IS_EXCLUSIVE: bool = true; + type Variance<'a, T: 'a + ?Sized> = Bx; + } +} + +#[cfg(feature = "std")] +pub use _std::*; +#[cfg(feature = "std")] +mod _std { + use std::sync::Arc as Ac; + + use super::*; + + pub enum Arc {} + impl AliasingInner for Arc { + // type MappedTo = M::FromArc; + } + impl Aliasing for Arc { + const IS_EXCLUSIVE: bool = true; + type Variance<'a, T: 'a + ?Sized> = Ac; } } @@ -279,6 +293,27 @@ impl ValidityInner for Valid { type MappedTo = M::FromValid; } +// Aliasing modes that permit reading at all (ie, everything but Inaccessible). +pub trait ReadFoo: Aliasing {} +impl ReadFoo for Shared {} +impl ReadFoo for Exclusive {} +#[cfg(feature = "alloc")] +impl ReadFoo for Box {} +#[cfg(feature = "std")] +impl ReadFoo for Arc {} + +// Shared, Arc, etc +pub trait SharedFoo: Aliasing {} +impl SharedFoo for Shared {} +#[cfg(feature = "std")] +impl SharedFoo for Arc {} + +// Exclusive, Box, etc +pub trait ExclusiveFoo: Aliasing {} +impl ExclusiveFoo for Exclusive {} +#[cfg(feature = "alloc")] +impl ExclusiveFoo for Box {} + /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. /// /// `T: Read` implies that a pointer to `T` with aliasing `A` permits @@ -303,8 +338,7 @@ define_because!( #[doc(hidden)] pub BecauseExclusive ); -// SAFETY: The aliasing parameter is `Exclusive`. -unsafe impl Read for T {} +unsafe impl Read for T {} define_because!( /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s @@ -313,7 +347,7 @@ define_because!( pub BecauseImmutable ); // SAFETY: `T: Immutable`. -unsafe impl Read for T {} +unsafe impl Read for T {} use sealed::Sealed; mod sealed { @@ -326,6 +360,10 @@ mod sealed { // impl Sealed for Inaccessible {} impl Sealed for Shared {} impl Sealed for Exclusive {} + #[cfg(feature = "alloc")] + impl Sealed for Box {} + #[cfg(feature = "std")] + impl Sealed for Arc {} impl Sealed for Aligned {} @@ -386,6 +424,10 @@ mod mapping { // type FromInaccessible: Aliasing; type FromShared: Aliasing; type FromExclusive: Aliasing; + #[cfg(feature = "alloc")] + type FromBox: Aliasing; + #[cfg(feature = "std")] + type FromArc: Aliasing; } /// A mapping from one [`Alignment`] type to another. @@ -454,38 +496,62 @@ mod mapping { // // type FromInaccessible = FromInaccessible; // type FromShared = FromShared; // type FromExclusive = FromExclusive; + // #[cfg(feature = "alloc")] + // type FromBox = Inaccessible; + // #[cfg(feature = "std")] + // type FromArc = Inaccessible; // } // impl AliasingMapping for Inaccessible { // type FromInaccessible = Inaccessible; // type FromShared = Inaccessible; // type FromExclusive = Inaccessible; + // #[cfg(feature = "alloc")] + // type FromBox = Inaccessible; + // #[cfg(feature = "std")] + // type FromArc = Inaccessible; // } // pub enum UnsafeCellMismatch {} // impl AliasingMapping for UnsafeCellMismatch { - // // type FromInaccessible = Inaccessible; + // type FromInaccessible = Inaccessible; // type FromShared = Inaccessible; // type FromExclusive = Exclusive; + // #[cfg(feature = "alloc")] + // type FromBox = Box; + // #[cfg(feature = "std")] + // type FromArc = Inaccessible; // } // impl AliasingMapping for Preserved { // // type FromInaccessible = Inaccessible; // type FromShared = Shared; // type FromExclusive = Exclusive; + // #[cfg(feature = "alloc")] + // type FromBox = Box; + // #[cfg(feature = "std")] + // type FromArc = Arc; // } // impl AliasingMapping for Shared { // // type FromInaccessible = Shared; // type FromShared = Shared; // type FromExclusive = Shared; + // #[cfg(feature = "alloc")] + // type FromBox = Shared; + // #[cfg(feature = "std")] + // type FromArc = Shared; // } // impl AliasingMapping for Exclusive { // // type FromInaccessible = Exclusive; // type FromShared = Exclusive; // type FromExclusive = Exclusive; + // #[cfg(feature = "alloc")] + // type FromBox = Exclusive; + // #[cfg(feature = "std")] + // type FromArc = Exclusive; // } impl AlignmentMapping diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 944a959da7..c154ab732c 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -61,7 +61,7 @@ where impl<'a, T, Aliasing, Alignment> MaybeAligned<'a, T, Aliasing, Alignment> where T: 'a + ?Sized, - Aliasing: invariant::Reference, + Aliasing: invariant::ReadFoo, Alignment: invariant::Alignment, { /// Views the value as an aligned reference. @@ -82,7 +82,96 @@ pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool where T: crate::Immutable + crate::KnownLayout, I: invariant::Invariants, - I::Aliasing: invariant::Reference, + I::Aliasing: invariant::ReadFoo, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) } + +pub use _pointer::*; +mod _pointer { + #[cfg(feature = "alloc")] + use alloc::boxed::Box; + #[cfg(feature = "std")] + use std::sync::Arc; + + use super::{inner::PtrInner, invariant::*}; + + pub unsafe trait Pointer<'t, T: ?Sized> { + type To<'u, U: 'u + ?Sized>: Pointer<'u, U, Aliasing = Self::Aliasing>; + + #[doc(hidden)] + type Aliasing: ReadFoo + Aliasing; + + #[doc(hidden)] + fn into_ptr(self) -> PtrInner<'t, T>; + + #[doc(hidden)] + unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self; + } + + unsafe impl<'t, T: ?Sized> Pointer<'t, T> for &'t T { + type To<'u, U: 'u + ?Sized> = &'u U; + + type Aliasing = Shared; + + #[inline(always)] + fn into_ptr(self) -> PtrInner<'t, T> { + PtrInner::from_ref(self) + } + + #[inline(always)] + unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self { + unsafe { ptr.as_non_null().as_ref() } + } + } + + unsafe impl<'t, T: ?Sized> Pointer<'t, T> for &'t mut T { + type To<'u, U: 'u + ?Sized> = &'u mut U; + + type Aliasing = Exclusive; + + #[inline(always)] + fn into_ptr(self) -> PtrInner<'t, T> { + PtrInner::from_ref(self) + } + + #[inline(always)] + unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Self { + unsafe { ptr.as_non_null().as_mut() } + } + } + + #[cfg(feature = "alloc")] + unsafe impl<'t, T: ?Sized> Pointer<'t, T> for Box { + type To<'u, U: 'u + ?Sized> = Box; + + type Aliasing = super::invariant::Box; + + #[inline(always)] + fn into_ptr(self) -> PtrInner<'t, T> { + PtrInner::from_box(self) + } + + #[inline(always)] + unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Box { + unsafe { Box::from_raw(ptr.as_non_null().as_ptr()) } + } + } + + #[cfg(feature = "std")] + unsafe impl<'t, T: ?Sized> Pointer<'t, T> for Arc { + type To<'u, U: 'u + ?Sized> = Arc; + + type Aliasing = super::invariant::Arc; + + #[inline(always)] + fn into_ptr(self) -> PtrInner<'t, T> { + PtrInner::from_arc(self) + } + + #[inline(always)] + unsafe fn from_ptr(ptr: PtrInner<'t, T>) -> Arc { + unsafe { Arc::from_raw(ptr.as_non_null().as_ptr()) } + } + } +} diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index e627d2d489..82b6c4ca5e 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -172,7 +172,30 @@ mod _external { /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; - use crate::pointer::transmute::TransmuteFromPtr; + use crate::pointer::{transmute::TransmuteFromPtr, Pointer}; + + // TODO: How to make this a `From` impl without blanket impl conflicts? + impl<'a, T, A> Ptr<'a, T, (A, Aligned, Valid)> + where + T: 'a + ?Sized, + A: Aliasing, + { + /// Constructs a `Ptr` from an existing smart pointer or reference type. + #[doc(hidden)] + #[inline] + pub fn from_pointer>(ptr: P) -> Self { + let ptr = P::into_ptr(ptr); + unsafe { Self::from_inner(ptr) } + } + + /// Constructs `self` to a smart pointer or reference type. + #[doc(hidden)] + #[inline] + #[must_use] + pub fn into_pointer>(self) -> P { + unsafe { P::from_ptr(self.as_inner()) } + } + } /// `&'a T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> @@ -220,7 +243,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: Reference, + I::Aliasing: ReadFoo, { /// Converts `self` to a shared reference. // This consumes `self`, not `&self`, because `self` is, logically, a @@ -266,7 +289,7 @@ mod _conversions { where T: 'a + ?Sized, I: Invariants, - I::Aliasing: Reference, + I::Aliasing: ReadFoo, { /// Reborrows `self`, producing another `Ptr`. /// @@ -646,7 +669,7 @@ mod _transitions { ) -> Result>, ValidityError> where T: TryFromBytes + Read, - I::Aliasing: Reference, + I::Aliasing: ReadFoo, I: Invariants, { // This call may panic. If that happens, it doesn't cause any soundness @@ -817,7 +840,7 @@ mod _casts { pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where T: Read, - I::Aliasing: Reference, + I::Aliasing: ReadFoo, { let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { Some(bytes) => bytes, @@ -896,6 +919,9 @@ mod _casts { /// - If this is a prefix cast, `ptr` has the same address as `self`. /// - If this is a suffix cast, `remainder` has the same address as /// `self`. + // TODO: This is currently unsound - need to bound with `I::Aliasing: + // Reference` in order to prove that splitting is okay (it isn't for + // e.g. Box and Arc). pub(crate) fn try_cast_into( self, cast_type: CastType, @@ -905,7 +931,7 @@ mod _casts { CastError, > where - I::Aliasing: Reference, + I::Aliasing: ReadFoo, U: 'a + ?Sized + KnownLayout + Read, { let (inner, remainder) = @@ -966,7 +992,7 @@ mod _casts { meta: Option, ) -> Result, CastError> where - I::Aliasing: Reference, + I::Aliasing: ReadFoo, U: 'a + ?Sized + KnownLayout + Read, { match self.try_cast_into(CastType::Prefix, meta) { @@ -1095,7 +1121,7 @@ mod _project { where T: 'a, I: Invariants, - I::Aliasing: Reference, + I::Aliasing: ReadFoo, { /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. pub(crate) fn iter(&self) -> impl Iterator> { diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 9d3f6ed77c..65e5ce87ac 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -527,7 +527,7 @@ where Src: IntoBytes + invariant::Read, Dst: TryFromBytes + invariant::Read, I: Invariants, - I::Aliasing: invariant::Reference, + I::Aliasing: invariant::ReadFoo, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); diff --git a/src/util/macros.rs b/src/util/macros.rs index 3a9ecad49a..c0ab413336 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -137,7 +137,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -159,7 +159,7 @@ macro_rules! unsafe_impl { fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] - fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { + fn is_bit_valid(candidate: Maybe<'_, Self, AA>) -> bool { // SAFETY: // - The cast preserves address. The caller has promised that the // cast results in an object of equal or lesser size, and so the @@ -178,7 +178,7 @@ macro_rules! unsafe_impl { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(coverage_nightly, coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} - #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } + #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } }; (@method $trait:ident) => { #[allow(clippy::missing_inline_in_public_items)] @@ -327,7 +327,7 @@ macro_rules! impl_for_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 { + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { <$repr as TryFromBytes>::is_bit_valid(candidate.transmute::<$repr, _>()) } }; diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 2392919441..8d5966fdda 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -282,7 +282,7 @@ pub(crate) fn derive_is_bit_valid( mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing>, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::ReadFoo, { use ::zerocopy::util::macro_util::core_reexport; diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 5d2f3ef43f..81ab1d41a2 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -422,7 +422,7 @@ fn derive_try_from_bytes_struct( mut candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::ReadFoo, { true #(&& { // SAFETY: @@ -479,7 +479,7 @@ fn derive_try_from_bytes_union( mut candidate: ::zerocopy::Maybe<'_, Self,___ZerocopyAliasing> ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::ReadFoo, { false #(|| { // SAFETY: @@ -588,7 +588,7 @@ fn try_gen_trivial_is_bit_valid( _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::ReadFoo, { if false { fn assert_is_from_bytes() @@ -631,7 +631,7 @@ unsafe fn gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream { _candidate: ::zerocopy::Maybe, ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where - ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, + ___ZerocopyAliasing: ::zerocopy::pointer::invariant::ReadFoo, { true }