diff --git a/src/lib.rs b/src/lib.rs index aa98023077..43f009f0cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1503,7 +1503,7 @@ pub unsafe trait TryFromBytes { doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html#analysis"), )] -pub unsafe trait FromZeros { +pub unsafe trait FromZeros: TryFromBytes { // The `Self: Sized` bound makes it so that `FromZeros` is still object // safe. #[doc(hidden)] @@ -3774,8 +3774,10 @@ safety_comment! { /// /// `UnsafeCell`` has the same in-memory representation as its inner /// type `T`. - unsafe_impl!(T: ?Sized + FromZeros => FromZeros for UnsafeCell); - unsafe_impl!(T: ?Sized + FromBytes => FromBytes for UnsafeCell); + /// + /// TODO(#5): Implement `FromZeros` and `FromBytes` when `T: ?Sized`. + unsafe_impl!(T: FromZeros => FromZeros for UnsafeCell); + unsafe_impl!(T: FromBytes => FromBytes for UnsafeCell); unsafe_impl!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell); unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell); assert_unaligned!(UnsafeCell<()>, UnsafeCell); @@ -7001,7 +7003,6 @@ mod tests { #[test] fn test_object_safety() { fn _takes_no_cell(_: &dyn NoCell) {} - fn _takes_from_zeros(_: &dyn FromZeros) {} fn _takes_unaligned(_: &dyn Unaligned) {} } diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 6bce135351..3b2c0cf1e0 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -395,10 +395,12 @@ fn derive_try_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_m } // A union is `TryFromBytes` if: -// - any of its fields are `TryFromBytes` +// - all of its fields are `TryFromBytes` and `NoCell` fn derive_try_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { - let self_type_trait_bounds = SelfBounds::All(&[Trait::NoCell]); + // TODO(#5): Remove the `NoCell` bound. + let field_type_trait_bounds = + FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]); let extras = Some({ let fields = unn.fields(); let field_names = fields.iter().map(|(name, _ty)| name); @@ -434,8 +436,8 @@ fn derive_try_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro ast, unn, Trait::TryFromBytes, - FieldBounds::ALL_SELF, - self_type_trait_bounds, + field_type_trait_bounds, + SelfBounds::None, None, extras, ) @@ -606,11 +608,15 @@ fn derive_from_zeros_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::Tok impl_block(ast, enm, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None) } -// Like structs, unions are `FromZeros` if -// - all fields are `FromZeros` +// Unions are `FromZeros` if +// - all fields are `FromZeros` and `NoCell` fn derive_from_zeros_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { - impl_block(ast, unn, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + // TODO(#5): Remove the `NoCell` bound. It's only necessary for + // compatibility with `derive(TryFromBytes)` on unions; not for soundness. + let field_type_trait_bounds = + FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]); + impl_block(ast, unn, Trait::FromZeros, field_type_trait_bounds, SelfBounds::None, None, None) } // A struct is `FromBytes` if: @@ -692,11 +698,15 @@ const ENUM_FROM_BYTES_CFG: Config = { } }; -// Like structs, unions are `FromBytes` if -// - all fields are `FromBytes` +// Unions are `FromBytes` if +// - all fields are `FromBytes` and `NoCell` fn derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream { - impl_block(ast, unn, Trait::FromBytes, FieldBounds::ALL_SELF, SelfBounds::None, None, None) + // TODO(#5): Remove the `NoCell` bound. It's only necessary for + // compatibility with `derive(TryFromBytes)` on unions; not for soundness. + let field_type_trait_bounds = + FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]); + impl_block(ast, unn, Trait::FromBytes, field_type_trait_bounds, SelfBounds::None, None, None) } fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {