// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT use proc_macro2::TokenStream; use quote::quote; use syn::{ parse_quote, spanned::Spanned as _, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Expr, Fields, Ident, Index, Type, }; use crate::{ repr::{EnumRepr, StructUnionRepr}, util::{ const_block, enum_size_from_repr, generate_tag_enum, Ctx, DataExt, FieldBounds, ImplBlockBuilder, Trait, TraitBound, }, }; fn tag_ident(variant_ident: &Ident) -> Ident { ident!(("___ZEROCOPY_TAG_{}", variant_ident), variant_ident.span()) } /// Generates a constant for the tag associated with each variant of the enum. /// When we match on the enum's tag, each arm matches one of these constants. We /// have to use constants here because: /// /// - The type that we're matching on is not the type of the tag, it's an /// integer of the same size as the tag type and with the same bit patterns. /// - We can't read the enum tag as an enum because the bytes may not represent /// a valid variant. /// - Patterns do not currently support const expressions, so we have to assign /// these constants to names rather than use them inline in the `match` /// statement. fn generate_tag_consts(data: &DataEnum) -> TokenStream { let tags = data.variants.iter().map(|v| { let variant_ident = &v.ident; let tag_ident = tag_ident(variant_ident); quote! { // This casts the enum variant to its discriminant, and then // converts the discriminant to the target integral type via a // numeric cast [1]. // // Because these are the same size, this is defined to be a no-op // and therefore is a lossless conversion [2]. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#enum-cast: // // Casts an enum to its discriminant. // // [2] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#numeric-cast: // // Casting between two integers of the same size (e.g. i32 -> u32) // is a no-op. const #tag_ident: ___ZerocopyTagPrimitive = ___ZerocopyTag::#variant_ident as ___ZerocopyTagPrimitive; } }); quote! { #(#tags)* } } fn variant_struct_ident(variant_ident: &Ident) -> Ident { ident!(("___ZerocopyVariantStruct_{}", variant_ident), variant_ident.span()) } /// Generates variant structs for the given enum variant. /// /// These are structs associated with each variant of an enum. They are /// `repr(C)` tuple structs with the same fields as the variant after a /// `MaybeUninit<___ZerocopyInnerTag>`. /// /// In order to unify the generated types for `repr(C)` and `repr(int)` enums, /// we use a "fused" representation with fields for both an inner tag and an /// outer tag. Depending on the repr, we will set one of these tags to the tag /// type and the other to `()`. This lets us generate the same code but put the /// tags in different locations. fn generate_variant_structs(ctx: &Ctx, data: &DataEnum) -> TokenStream { let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl(); let enum_name = &ctx.ast.ident; // All variant structs have a `PhantomData>` field because we // don't know which generic parameters each variant will use, and unused // generic parameters are a compile error. let core = ctx.core_path(); let phantom_ty = quote! { #core::marker::PhantomData<#enum_name #ty_generics> }; let variant_structs = data.variants.iter().filter_map(|variant| { // We don't generate variant structs for unit variants because we only // need to check the tag. This helps cut down our generated code a bit. if matches!(variant.fields, Fields::Unit) { return None; } let variant_struct_ident = variant_struct_ident(&variant.ident); let field_types = variant.fields.iter().map(|f| &f.ty); let variant_struct = parse_quote! { #[repr(C)] struct #variant_struct_ident #impl_generics ( #core::mem::MaybeUninit<___ZerocopyInnerTag>, #(#field_types,)* #phantom_ty, ) #where_clause; }; // We do this rather than emitting `#[derive(::zerocopy::TryFromBytes)]` // because that is not hygienic, and this is also more performant. let try_from_bytes_impl = derive_try_from_bytes(&ctx.with_input(&variant_struct), Trait::TryFromBytes) .expect("derive_try_from_bytes should not fail on synthesized type"); Some(quote! { #variant_struct #try_from_bytes_impl }) }); quote! { #(#variant_structs)* } } fn variants_union_field_ident(ident: &Ident) -> Ident { // Field names are prefixed with `__field_` to prevent name collision // with the `__nonempty` field. ident!(("__field_{}", ident), ident.span()) } fn generate_variants_union(ctx: &Ctx, data: &DataEnum) -> TokenStream { let generics = &ctx.ast.generics; let (_, ty_generics, _) = generics.split_for_impl(); let fields = data.variants.iter().filter_map(|variant| { // We don't generate variant structs for unit variants because we only // need to check the tag. This helps cut down our generated code a bit. if matches!(variant.fields, Fields::Unit) { return None; } let field_name = variants_union_field_ident(&variant.ident); let variant_struct_ident = variant_struct_ident(&variant.ident); let core = ctx.core_path(); Some(quote! { #field_name: #core::mem::ManuallyDrop<#variant_struct_ident #ty_generics>, }) }); let variants_union = parse_quote! { #[repr(C)] union ___ZerocopyVariants #generics { #(#fields)* // Enums can have variants with no fields, but unions must // have at least one field. So we just add a trailing unit // to ensure that this union always has at least one field. // Because this union is `repr(C)`, this unit type does not // affect the layout. __nonempty: (), } }; let has_field = derive_has_field_struct_union(&ctx.with_input(&variants_union), &variants_union.data); quote! { #variants_union #has_field } } /// Generates an implementation of `is_bit_valid` for an arbitrary enum. /// /// The general process is: /// /// 1. Generate a tag enum. This is an enum with the same repr, variants, and /// corresponding discriminants as the original enum, but without any fields /// on the variants. This gives us access to an enum where the variants have /// the same discriminants as the one we're writing `is_bit_valid` for. /// 2. Make constants from the variants of the tag enum. We need these because /// we can't put const exprs in match arms. /// 3. Generate variant structs. These are structs which have the same fields as /// each variant of the enum, and are `#[repr(C)]` with an optional "inner /// tag". /// 4. Generate a variants union, with one field for each variant struct type. /// 5. And finally, our raw enum is a `#[repr(C)]` struct of an "outer tag" and /// the variants union. /// /// See these reference links for fully-worked example decompositions. /// /// - `repr(C)`: /// - `repr(int)`: /// - `repr(C, int)`: pub(crate) fn derive_is_bit_valid( ctx: &Ctx, data: &DataEnum, repr: &EnumRepr, ) -> Result { let trait_path = Trait::TryFromBytes.crate_path(ctx); let tag_enum = generate_tag_enum(ctx, repr, data); let tag_consts = generate_tag_consts(data); let (outer_tag_type, inner_tag_type) = if repr.is_c() { (quote! { ___ZerocopyTag }, quote! { () }) } else if repr.is_primitive() { (quote! { () }, quote! { ___ZerocopyTag }) } else { return Err(Error::new( ctx.ast.span(), "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout", )); }; let variant_structs = generate_variant_structs(ctx, data); let variants_union = generate_variants_union(ctx, data); let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl(); let zerocopy_crate = &ctx.zerocopy_crate; let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None) .inner_extras(quote! { type Tag = ___ZerocopyTag; type ProjectToTag = #zerocopy_crate::pointer::cast::CastSized; }) .build(); let has_fields = data.variants().into_iter().flat_map(|(variant, fields)| { let variant_ident = &variant.unwrap().ident; let variants_union_field_ident = variants_union_field_ident(variant_ident); let field: Box = parse_quote!(()); fields.into_iter().enumerate().map(move |(idx, (vis, ident, ty))| { // Rust does not presently support explicit visibility modifiers on // enum fields, but we guard against the possibility to ensure this // derive remains sound. assert!(matches!(vis, syn::Visibility::Inherited)); let variant_struct_field_index = Index::from(idx + 1); let (_, ty_generics, _) = ctx.ast.generics.split_for_impl(); let has_field_trait = Trait::HasField { variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }), // Since Rust does not presently support explicit visibility // modifiers on enum fields, any public type is suitable here; // we use `()`. field: field.clone(), field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }), }; let has_field_path = has_field_trait.crate_path(ctx); let has_field = ImplBlockBuilder::new( ctx, data, has_field_trait, FieldBounds::None, ) .inner_extras(quote! { type Type = #ty; #[inline(always)] fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut ::Type { use #zerocopy_crate::pointer::cast::{CastSized, Projection}; slf.project::<___ZerocopyRawEnum #ty_generics, CastSized>() .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(variants) }>>() .project::<_, Projection<_, { #zerocopy_crate::REPR_C_UNION_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variants_union_field_ident) }>>() .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(value) }>>() .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variant_struct_field_index) }>>() .as_ptr() } }) .build(); let project = ImplBlockBuilder::new( ctx, data, Trait::ProjectField { variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }), // Since Rust does not presently support explicit visibility // modifiers on enum fields, any public type is suitable // here; we use `()`. field: field.clone(), field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }), invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)), }, FieldBounds::None, ) .param_extras(vec![ parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing), parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment), ]) .inner_extras(quote! { type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible; type Invariants = (Aliasing, Alignment, #zerocopy_crate::invariant::Initialized); }) .build(); quote! { #has_field #project } }) }); let core = ctx.core_path(); let match_arms = data.variants.iter().map(|variant| { let tag_ident = tag_ident(&variant.ident); let variant_struct_ident = variant_struct_ident(&variant.ident); let variants_union_field_ident = variants_union_field_ident(&variant.ident); if matches!(variant.fields, Fields::Unit) { // Unit variants don't need any further validation beyond checking // the tag. quote! { #tag_ident => true } } else { quote! { #tag_ident => { // SAFETY: Since we know that the tag is `#tag_ident`, we // know that no other `&`s exist which refer to this enum // as any other variant. let variant_md = variants.cast::< _, #zerocopy_crate::pointer::cast::Projection< // #zerocopy_crate::ReadOnly<_>, _, { #zerocopy_crate::REPR_C_UNION_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variants_union_field_ident) } >, _ >(); let variant = variant_md.cast::< #zerocopy_crate::ReadOnly<#variant_struct_ident #ty_generics>, #zerocopy_crate::pointer::cast::CastSized, (#zerocopy_crate::pointer::BecauseRead, _) >(); < #variant_struct_ident #ty_generics as #trait_path >::is_bit_valid(variant) } } } }); let generics = &ctx.ast.generics; let raw_enum: DeriveInput = parse_quote! { #[repr(C)] struct ___ZerocopyRawEnum #generics { tag: ___ZerocopyOuterTag, variants: ___ZerocopyVariants #ty_generics, } }; let self_ident = &ctx.ast.ident; let invariants_eq_impl = quote! { // SAFETY: `___ZerocopyRawEnum` is designed to have the same layout, // validity, and invariants as `Self`. unsafe impl #impl_generics #zerocopy_crate::pointer::InvariantsEq<___ZerocopyRawEnum #ty_generics> for #self_ident #ty_generics #where_clause {} }; let raw_enum_projections = derive_has_field_struct_union(&ctx.with_input(&raw_enum), &raw_enum.data); let raw_enum = quote! { #raw_enum #invariants_eq_impl #raw_enum_projections }; Ok(quote! { // SAFETY: We use `is_bit_valid` to validate that the bit pattern of the // enum's tag corresponds to one of the enum's discriminants. Then, we // check the bit validity of each field of the corresponding variant. // Thus, this is a sound implementation of `is_bit_valid`. #[inline] fn is_bit_valid<___ZcAlignment>( mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>, ) -> #core::primitive::bool where ___ZcAlignment: #zerocopy_crate::invariant::Alignment, { #tag_enum type ___ZerocopyTagPrimitive = #zerocopy_crate::util::macro_util::SizeToTag< { #core::mem::size_of::<___ZerocopyTag>() }, >; #tag_consts type ___ZerocopyOuterTag = #outer_tag_type; type ___ZerocopyInnerTag = #inner_tag_type; #variant_structs #variants_union #raw_enum #has_tag #(#has_fields)* let tag = { // SAFETY: // - The provided cast addresses a subset of the bytes addressed // by `candidate` because it addresses the starting tag of the // enum. // - Because the pointer is cast from `candidate`, it has the // same provenance as it. // - There are no `UnsafeCell`s in the tag because it is a // primitive integer. // - `tag_ptr` is casted from `candidate`, whose referent is // `Initialized`. Since we have not written uninitialized // bytes into the referent, `tag_ptr` is also `Initialized`. // // FIXME(#2874): Revise this to a `cast` once `candidate` // references a `ReadOnly`. let tag_ptr = unsafe { candidate.reborrow().project_transmute_unchecked::< _, #zerocopy_crate::invariant::Initialized, #zerocopy_crate::pointer::cast::CastSized >() }; tag_ptr.recall_validity::<_, (_, (_, _))>().read::<#zerocopy_crate::BecauseImmutable>() }; let mut raw_enum = candidate.cast::< #zerocopy_crate::ReadOnly<___ZerocopyRawEnum #ty_generics>, #zerocopy_crate::pointer::cast::CastSized, (#zerocopy_crate::pointer::BecauseRead, _) >(); let variants = #zerocopy_crate::into_inner!(raw_enum.project::< _, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(variants) } >()); match tag { #(#match_arms,)* _ => false, } } }) } pub(crate) fn derive_try_from_bytes(ctx: &Ctx, top_level: Trait) -> Result { match &ctx.ast.data { Data::Struct(strct) => derive_try_from_bytes_struct(ctx, strct, top_level), Data::Enum(enm) => derive_try_from_bytes_enum(ctx, enm, top_level), Data::Union(unn) => Ok(derive_try_from_bytes_union(ctx, unn, top_level)), } } fn derive_has_field_struct_union(ctx: &Ctx, data: &dyn DataExt) -> TokenStream { let fields = ctx.ast.data.fields(); if fields.is_empty() { return quote! {}; } let field_tokens = fields.iter().map(|(vis, ident, _)| { let ident = ident!(("__z{}", ident), ident.span()); quote!( #vis enum #ident {} ) }); let zerocopy_crate = &ctx.zerocopy_crate; let variant_id: Box = match &ctx.ast.data { Data::Struct(_) => parse_quote!({ #zerocopy_crate::STRUCT_VARIANT_ID }), Data::Union(_) => { let is_repr_c = StructUnionRepr::from_attrs(&ctx.ast.attrs) .map(|repr| repr.is_c()) .unwrap_or(false); if is_repr_c { parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID }) } else { parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID }) } } _ => unreachable!(), }; let core = ctx.core_path(); let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None) .inner_extras(quote! { type Tag = (); type ProjectToTag = #zerocopy_crate::pointer::cast::CastToUnit; }) .build(); let has_fields = fields.iter().map(move |(_, ident, ty)| { let field_token = ident!(("__z{}", ident), ident.span()); let field: Box = parse_quote!(#field_token); let field_id: Box = parse_quote!({ #zerocopy_crate::ident_id!(#ident) }); let has_field_trait = Trait::HasField { variant_id: variant_id.clone(), field: field.clone(), field_id: field_id.clone(), }; let has_field_path = has_field_trait.crate_path(ctx); ImplBlockBuilder::new( ctx, data, has_field_trait, FieldBounds::None, ) .inner_extras(quote! { type Type = #ty; #[inline(always)] fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut ::Type { let slf = slf.as_ptr(); // SAFETY: By invariant on `PtrInner`, `slf` is a non-null // pointer whose referent is zero-sized or lives in a valid // allocation. Since `#ident` is a struct or union field of // `Self`, this projection preserves or shrinks the referent // size, and so the resulting referent also fits in the same // allocation. unsafe { #core::ptr::addr_of_mut!((*slf).#ident) } } }).outer_extras(if matches!(&ctx.ast.data, Data::Struct(..)) { let fields_preserve_alignment = StructUnionRepr::from_attrs(&ctx.ast.attrs) .map(|repr| repr.get_packed().is_none()) .unwrap(); let alignment = if fields_preserve_alignment { quote! { Alignment } } else { quote! { #zerocopy_crate::invariant::Unaligned } }; // SAFETY: See comments on items. ImplBlockBuilder::new( ctx, data, Trait::ProjectField { variant_id: variant_id.clone(), field: field.clone(), field_id: field_id.clone(), invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)), }, FieldBounds::None, ) .param_extras(vec![ parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing), parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment), ]) .inner_extras(quote! { // SAFETY: Projection into structs is always infallible. type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible; // SAFETY: The alignment of the projected `Ptr` is `Unaligned` // if the structure is packed; otherwise inherited from the // outer `Ptr`. If the validity of the outer pointer is // `Initialized`, so too is the validity of its fields. type Invariants = (Aliasing, #alignment, #zerocopy_crate::invariant::Initialized); }) .build() } else { quote! {} }) .build() }); const_block(field_tokens.into_iter().chain(Some(has_tag)).chain(has_fields).map(Some)) } fn derive_try_from_bytes_struct( ctx: &Ctx, strct: &DataStruct, top_level: Trait, ) -> Result { let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| { let zerocopy_crate = &ctx.zerocopy_crate; let fields = strct.fields(); let field_names = fields.iter().map(|(_vis, name, _ty)| name); let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); let core = ctx.core_path(); quote!( // SAFETY: We use `is_bit_valid` to validate that each field is // bit-valid, and only return `true` if all of them are. The bit // validity of a struct is just the composition of the bit // validities of its fields, so this is a sound implementation // of `is_bit_valid`. #[inline] fn is_bit_valid<___ZcAlignment>( mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>, ) -> #core::primitive::bool where ___ZcAlignment: #zerocopy_crate::invariant::Alignment, { true #(&& { let field_candidate = #zerocopy_crate::into_inner!(candidate.reborrow().project::< _, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(#field_names) } >()); <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate) })* } ) }); Ok(ImplBlockBuilder::new(ctx, strct, Trait::TryFromBytes, FieldBounds::ALL_SELF) .inner_extras(extras) .outer_extras(derive_has_field_struct_union(ctx, strct)) .build()) } fn derive_try_from_bytes_union(ctx: &Ctx, unn: &DataUnion, top_level: Trait) -> TokenStream { let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]); let zerocopy_crate = &ctx.zerocopy_crate; let variant_id: Box = { let is_repr_c = StructUnionRepr::from_attrs(&ctx.ast.attrs).map(|repr| repr.is_c()).unwrap_or(false); if is_repr_c { parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID }) } else { parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID }) } }; let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| { let fields = unn.fields(); let field_names = fields.iter().map(|(_vis, name, _ty)| name); let field_tys = fields.iter().map(|(_vis, _name, ty)| ty); let core = ctx.core_path(); quote!( // SAFETY: We use `is_bit_valid` to validate that any field is // bit-valid; we only return `true` if at least one of them is. // The bit validity of a union is not yet well defined in Rust, // but it is guaranteed to be no more strict than this // definition. See #696 for a more in-depth discussion. #[inline] fn is_bit_valid<___ZcAlignment>( mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>, ) -> #core::primitive::bool where ___ZcAlignment: #zerocopy_crate::invariant::Alignment, { false #(|| { // SAFETY: // - Since `ReadOnly: Immutable` unconditionally, // neither `*slf` nor the returned pointer's referent // permit interior mutation. // - Both source and destination validity are // `Initialized`, which is always a sound // transmutation. let field_candidate = unsafe { candidate.reborrow().project_transmute_unchecked::< _, _, #zerocopy_crate::pointer::cast::Projection< _, #variant_id, { #zerocopy_crate::ident_id!(#field_names) } > >() }; <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate) })* } ) }); ImplBlockBuilder::new(ctx, unn, Trait::TryFromBytes, field_type_trait_bounds) .inner_extras(extras) .outer_extras(derive_has_field_struct_union(ctx, unn)) .build() } fn derive_try_from_bytes_enum( ctx: &Ctx, enm: &DataEnum, top_level: Trait, ) -> Result { let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?; // If an enum has no fields, it has a well-defined integer representation, // and every possible bit pattern corresponds to a valid discriminant tag, // then it *could* be `FromBytes` (even if the user hasn't derived // `FromBytes`). This holds if, for `repr(uN)` or `repr(iN)`, there are 2^N // variants. let could_be_from_bytes = enum_size_from_repr(&repr) .map(|size| enm.fields().is_empty() && enm.variants.len() == 1usize << size) .unwrap_or(false); let trivial_is_bit_valid = try_gen_trivial_is_bit_valid(ctx, top_level); let extra = match (trivial_is_bit_valid, could_be_from_bytes) { (Some(is_bit_valid), _) => is_bit_valid, // SAFETY: It would be sound for the enum to implement `FromBytes`, as // required by `gen_trivial_is_bit_valid_unchecked`. (None, true) => unsafe { gen_trivial_is_bit_valid_unchecked(ctx) }, (None, false) => match derive_is_bit_valid(ctx, enm, &repr) { Ok(extra) => extra, Err(_) if ctx.skip_on_error => return Ok(TokenStream::new()), Err(e) => return Err(e), }, }; Ok(ImplBlockBuilder::new(ctx, enm, Trait::TryFromBytes, FieldBounds::ALL_SELF) .inner_extras(extra) .build()) } fn try_gen_trivial_is_bit_valid(ctx: &Ctx, top_level: Trait) -> Option { // If the top-level trait is `FromBytes` and `Self` has no type parameters, // then the `FromBytes` derive will fail compilation if `Self` is not // actually soundly `FromBytes`, and so we can rely on that for our // `is_bit_valid` impl. It's plausible that we could make changes - or Rust // could make changes (such as the "trivial bounds" language feature) - that // make this no longer true. To hedge against these, we include an explicit // `Self: FromBytes` check in the generated `is_bit_valid`, which is // bulletproof. // // If `ctx.skip_on_error` is true, we can't rely on the `FromBytes` derive // to fail compilation if `Self` is not actually soundly `FromBytes`. if matches!(top_level, Trait::FromBytes) && ctx.ast.generics.params.is_empty() && !ctx.skip_on_error { let zerocopy_crate = &ctx.zerocopy_crate; let core = ctx.core_path(); Some(quote!( // SAFETY: See inline. #[inline(always)] fn is_bit_valid<___ZcAlignment>( _candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>, ) -> #core::primitive::bool where ___ZcAlignment: #zerocopy_crate::invariant::Alignment, { if false { fn assert_is_from_bytes() where T: #zerocopy_crate::FromBytes, T: ?#core::marker::Sized, { } assert_is_from_bytes::(); } // SAFETY: The preceding code only compiles if `Self: // FromBytes`. Thus, this code only compiles if all initialized // byte sequences represent valid instances of `Self`. true } )) } else { None } } /// # Safety /// /// All initialized bit patterns must be valid for `Self`. unsafe fn gen_trivial_is_bit_valid_unchecked(ctx: &Ctx) -> proc_macro2::TokenStream { let zerocopy_crate = &ctx.zerocopy_crate; let core = ctx.core_path(); quote!( // SAFETY: The caller of `gen_trivial_is_bit_valid_unchecked` has // promised that all initialized bit patterns are valid for `Self`. #[inline(always)] fn is_bit_valid<___ZcAlignment>( _candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>, ) -> #core::primitive::bool where ___ZcAlignment: #zerocopy_crate::invariant::Alignment, { true } ) }