@@ -745,7 +745,11 @@ fn derive_try_from_bytes_struct(
745745 let fields = strct. fields ( ) ;
746746 let field_names = fields. iter ( ) . map ( |( _vis, name, _ty) | name) ;
747747 let field_tys = fields. iter ( ) . map ( |( _vis, _name, ty) | ty) ;
748+
749+ let is_immutable = gen_is_immutable ( ast, zerocopy_crate) ;
748750 quote ! (
751+ #is_immutable
752+
749753 // SAFETY: We use `is_bit_valid` to validate that each field is
750754 // bit-valid, and only return `true` if all of them are. The bit
751755 // validity of a struct is just the composition of the bit
@@ -808,15 +812,15 @@ fn derive_try_from_bytes_union(
808812 top_level : Trait ,
809813 zerocopy_crate : & Path ,
810814) -> TokenStream {
811- // FIXME(#5): Remove the `Immutable` bound.
812- let field_type_trait_bounds =
813- FieldBounds :: All ( & [ TraitBound :: Slf , TraitBound :: Other ( Trait :: Immutable ) ] ) ;
814815 let extras =
815816 try_gen_trivial_is_bit_valid ( ast, top_level, zerocopy_crate) . unwrap_or_else ( || {
816817 let fields = unn. fields ( ) ;
817818 let field_names = fields. iter ( ) . map ( |( _vis, name, _ty) | name) ;
818819 let field_tys = fields. iter ( ) . map ( |( _vis, _name, ty) | ty) ;
820+ let is_immutable = gen_is_immutable ( ast, zerocopy_crate) ;
819821 quote ! (
822+ #is_immutable
823+
820824 // SAFETY: We use `is_bit_valid` to validate that any field is
821825 // bit-valid; we only return `true` if at least one of them is. The
822826 // bit validity of a union is not yet well defined in Rust, but it
@@ -828,16 +832,35 @@ fn derive_try_from_bytes_union(
828832 where
829833 ___ZerocopyAliasing: #zerocopy_crate:: pointer:: invariant:: Reference ,
830834 {
831- use #zerocopy_crate:: util:: macro_util:: core_reexport;
835+ use #zerocopy_crate:: {
836+ util:: macro_util:: core_reexport,
837+ pointer:: invariant:: Aliasing
838+ } ;
839+
840+ trait ConstAssert {
841+ const IS_READ : bool ;
842+ }
843+
844+ // TODO: What do we name `TryFromBytes`?
845+ impl <T : #zerocopy_crate:: TryFromBytes , A : #zerocopy_crate:: pointer:: invariant:: Aliasing > ConstAssert for ( T , A ) {
846+ const IS_READ : bool = {
847+ assert!( T :: IS_IMMUTABLE || A :: IS_EXCLUSIVE ) ;
848+ true
849+ } ;
850+ }
851+
852+ assert!( <( Self , ___ZerocopyAliasing) as ConstAssert >:: IS_READ ) ;
832853
833854 false #( || {
834855 // SAFETY:
835856 // - `project` is a field projection, and so it addresses a
836857 // subset of the bytes addressed by `slf`
837858 // - ..., and so it preserves provenance
838- // - Since `Self: Immutable` is enforced by
839- // `self_type_trait_bounds`, neither `*slf` nor the
840- // returned pointer's referent contain any `UnsafeCell`s
859+ // - By the preceding assert, it is either the case that
860+ // `Self: Immutable` or that `___ZerocopyAliasing` is
861+ // `Exclusive`. In the former case, `Self: Immutable`
862+ // ensures that `*slf` nor the returned pointer's
863+ // referent contain any `UnsafeCell`s.
841864 let field_candidate = unsafe {
842865 let project = |slf: core_reexport:: ptr:: NonNull <Self >| {
843866 let slf = slf. as_ptr( ) ;
@@ -860,7 +883,7 @@ fn derive_try_from_bytes_union(
860883 }
861884 )
862885 } ) ;
863- ImplBlockBuilder :: new ( ast, unn, Trait :: TryFromBytes , field_type_trait_bounds , zerocopy_crate)
886+ ImplBlockBuilder :: new ( ast, unn, Trait :: TryFromBytes , FieldBounds :: ALL_SELF , zerocopy_crate)
864887 . inner_extras ( extras)
865888 . build ( )
866889}
@@ -887,9 +910,9 @@ fn derive_try_from_bytes_enum(
887910 ( Some ( is_bit_valid) , _) => is_bit_valid,
888911 // SAFETY: It would be sound for the enum to implement `FomBytes`, as
889912 // required by `gen_trivial_is_bit_valid_unchecked`.
890- ( None , true ) => unsafe { gen_trivial_is_bit_valid_unchecked ( zerocopy_crate) } ,
913+ ( None , true ) => unsafe { gen_trivial_is_bit_valid_unchecked ( ast , zerocopy_crate) } ,
891914 ( None , false ) => {
892- r#enum:: derive_is_bit_valid ( & ast. ident , & repr, & ast. generics , enm, zerocopy_crate) ?
915+ r#enum:: derive_is_bit_valid ( ast , & ast. ident , & repr, & ast. generics , enm, zerocopy_crate) ?
893916 }
894917 } ;
895918
@@ -932,8 +955,12 @@ fn try_gen_trivial_is_bit_valid(
932955 // make this no longer true. To hedge against these, we include an explicit
933956 // `Self: FromBytes` check in the generated `is_bit_valid`, which is
934957 // bulletproof.
958+
959+ let is_immutable = gen_is_immutable ( ast, zerocopy_crate) ;
935960 if top_level == Trait :: FromBytes && ast. generics . params . is_empty ( ) {
936961 Some ( quote ! (
962+ #is_immutable
963+
937964 // SAFETY: See inline.
938965 fn is_bit_valid<___ZerocopyAliasing>(
939966 _candidate: #zerocopy_crate:: Maybe <Self , ___ZerocopyAliasing>,
@@ -963,6 +990,21 @@ fn try_gen_trivial_is_bit_valid(
963990 }
964991}
965992
993+ fn gen_is_immutable ( ast : & DeriveInput , zerocopy_crate : & Path ) -> proc_macro2:: TokenStream {
994+ let fields = match & ast. data {
995+ Data :: Struct ( strct) => strct. fields ( ) ,
996+ Data :: Enum ( enm) => enm. fields ( ) ,
997+ Data :: Union ( unn) => unn. fields ( ) ,
998+ } ;
999+ let field_tys = fields. iter ( ) . map ( |( _vis, _name, ty) | ty) ;
1000+
1001+ quote ! (
1002+ const IS_IMMUTABLE : bool = true #(
1003+ && <#field_tys as #zerocopy_crate:: TryFromBytes >:: IS_IMMUTABLE
1004+ ) * ;
1005+ )
1006+ }
1007+
9661008/// Generates a `TryFromBytes::is_bit_valid` instance that unconditionally
9671009/// returns true.
9681010///
@@ -974,8 +1016,14 @@ fn try_gen_trivial_is_bit_valid(
9741016///
9751017/// The caller must ensure that all initialized bit patterns are valid for
9761018/// `Self`.
977- unsafe fn gen_trivial_is_bit_valid_unchecked ( zerocopy_crate : & Path ) -> proc_macro2:: TokenStream {
1019+ unsafe fn gen_trivial_is_bit_valid_unchecked (
1020+ ast : & DeriveInput ,
1021+ zerocopy_crate : & Path ,
1022+ ) -> proc_macro2:: TokenStream {
1023+ let is_immutable = gen_is_immutable ( ast, zerocopy_crate) ;
9781024 quote ! (
1025+ #is_immutable
1026+
9791027 // SAFETY: The caller of `gen_trivial_is_bit_valid_unchecked` has
9801028 // promised that all initialized bit patterns are valid for `Self`.
9811029 fn is_bit_valid<___ZerocopyAliasing>(
@@ -1146,12 +1194,7 @@ fn derive_from_zeros_union(
11461194 unn : & DataUnion ,
11471195 zerocopy_crate : & Path ,
11481196) -> TokenStream {
1149- // FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1150- // compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1151- let field_type_trait_bounds =
1152- FieldBounds :: All ( & [ TraitBound :: Slf , TraitBound :: Other ( Trait :: Immutable ) ] ) ;
1153- ImplBlockBuilder :: new ( ast, unn, Trait :: FromZeros , field_type_trait_bounds, zerocopy_crate)
1154- . build ( )
1197+ ImplBlockBuilder :: new ( ast, unn, Trait :: FromZeros , FieldBounds :: ALL_SELF , zerocopy_crate) . build ( )
11551198}
11561199
11571200/// A struct is `FromBytes` if:
@@ -1223,12 +1266,7 @@ fn derive_from_bytes_union(
12231266 unn : & DataUnion ,
12241267 zerocopy_crate : & Path ,
12251268) -> TokenStream {
1226- // FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1227- // compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1228- let field_type_trait_bounds =
1229- FieldBounds :: All ( & [ TraitBound :: Slf , TraitBound :: Other ( Trait :: Immutable ) ] ) ;
1230- ImplBlockBuilder :: new ( ast, unn, Trait :: FromBytes , field_type_trait_bounds, zerocopy_crate)
1231- . build ( )
1269+ ImplBlockBuilder :: new ( ast, unn, Trait :: FromBytes , FieldBounds :: ALL_SELF , zerocopy_crate) . build ( )
12321270}
12331271
12341272fn derive_into_bytes_struct (
0 commit comments