xref: /linux/rust/zerocopy-derive/derive/try_from_bytes.rs (revision 5f85604cf0877b0369dfd68cd50cf61c0f134819)
1 // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
2 
3 use proc_macro2::TokenStream;
4 use quote::quote;
5 use syn::{
6     parse_quote, spanned::Spanned as _, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error,
7     Expr, Fields, Ident, Index, Type,
8 };
9 
10 use crate::{
11     repr::{EnumRepr, StructUnionRepr},
12     util::{
13         const_block, enum_size_from_repr, generate_tag_enum, Ctx, DataExt, FieldBounds,
14         ImplBlockBuilder, Trait, TraitBound,
15     },
16 };
17 fn tag_ident(variant_ident: &Ident) -> Ident {
18     ident!(("___ZEROCOPY_TAG_{}", variant_ident), variant_ident.span())
19 }
20 
21 /// Generates a constant for the tag associated with each variant of the enum.
22 /// When we match on the enum's tag, each arm matches one of these constants. We
23 /// have to use constants here because:
24 ///
25 /// - The type that we're matching on is not the type of the tag, it's an
26 ///   integer of the same size as the tag type and with the same bit patterns.
27 /// - We can't read the enum tag as an enum because the bytes may not represent
28 ///   a valid variant.
29 /// - Patterns do not currently support const expressions, so we have to assign
30 ///   these constants to names rather than use them inline in the `match`
31 ///   statement.
32 fn generate_tag_consts(data: &DataEnum) -> TokenStream {
33     let tags = data.variants.iter().map(|v| {
34         let variant_ident = &v.ident;
35         let tag_ident = tag_ident(variant_ident);
36 
37         quote! {
38             // This casts the enum variant to its discriminant, and then
39             // converts the discriminant to the target integral type via a
40             // numeric cast [1].
41             //
42             // Because these are the same size, this is defined to be a no-op
43             // and therefore is a lossless conversion [2].
44             //
45             // [1] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#enum-cast:
46             //
47             //   Casts an enum to its discriminant.
48             //
49             // [2] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#numeric-cast:
50             //
51             //   Casting between two integers of the same size (e.g. i32 -> u32)
52             //   is a no-op.
53             const #tag_ident: ___ZerocopyTagPrimitive =
54                 ___ZerocopyTag::#variant_ident as ___ZerocopyTagPrimitive;
55         }
56     });
57 
58     quote! {
59         #(#tags)*
60     }
61 }
62 
63 fn variant_struct_ident(variant_ident: &Ident) -> Ident {
64     ident!(("___ZerocopyVariantStruct_{}", variant_ident), variant_ident.span())
65 }
66 
67 /// Generates variant structs for the given enum variant.
68 ///
69 /// These are structs associated with each variant of an enum. They are
70 /// `repr(C)` tuple structs with the same fields as the variant after a
71 /// `MaybeUninit<___ZerocopyInnerTag>`.
72 ///
73 /// In order to unify the generated types for `repr(C)` and `repr(int)` enums,
74 /// we use a "fused" representation with fields for both an inner tag and an
75 /// outer tag. Depending on the repr, we will set one of these tags to the tag
76 /// type and the other to `()`. This lets us generate the same code but put the
77 /// tags in different locations.
78 fn generate_variant_structs(ctx: &Ctx, data: &DataEnum) -> TokenStream {
79     let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
80 
81     let enum_name = &ctx.ast.ident;
82 
83     // All variant structs have a `PhantomData<MyEnum<...>>` field because we
84     // don't know which generic parameters each variant will use, and unused
85     // generic parameters are a compile error.
86     let core = ctx.core_path();
87     let phantom_ty = quote! {
88         #core::marker::PhantomData<#enum_name #ty_generics>
89     };
90 
91     let variant_structs = data.variants.iter().filter_map(|variant| {
92         // We don't generate variant structs for unit variants because we only
93         // need to check the tag. This helps cut down our generated code a bit.
94         if matches!(variant.fields, Fields::Unit) {
95             return None;
96         }
97 
98         let variant_struct_ident = variant_struct_ident(&variant.ident);
99         let field_types = variant.fields.iter().map(|f| &f.ty);
100 
101         let variant_struct = parse_quote! {
102             #[repr(C)]
103             struct #variant_struct_ident #impl_generics (
104                 #core::mem::MaybeUninit<___ZerocopyInnerTag>,
105                 #(#field_types,)*
106                 #phantom_ty,
107             ) #where_clause;
108         };
109 
110         // We do this rather than emitting `#[derive(::zerocopy::TryFromBytes)]`
111         // because that is not hygienic, and this is also more performant.
112         let try_from_bytes_impl =
113             derive_try_from_bytes(&ctx.with_input(&variant_struct), Trait::TryFromBytes)
114                 .expect("derive_try_from_bytes should not fail on synthesized type");
115 
116         Some(quote! {
117             #variant_struct
118             #try_from_bytes_impl
119         })
120     });
121 
122     quote! {
123         #(#variant_structs)*
124     }
125 }
126 
127 fn variants_union_field_ident(ident: &Ident) -> Ident {
128     // Field names are prefixed with `__field_` to prevent name collision
129     // with the `__nonempty` field.
130     ident!(("__field_{}", ident), ident.span())
131 }
132 
133 fn generate_variants_union(ctx: &Ctx, data: &DataEnum) -> TokenStream {
134     let generics = &ctx.ast.generics;
135     let (_, ty_generics, _) = generics.split_for_impl();
136 
137     let fields = data.variants.iter().filter_map(|variant| {
138         // We don't generate variant structs for unit variants because we only
139         // need to check the tag. This helps cut down our generated code a bit.
140         if matches!(variant.fields, Fields::Unit) {
141             return None;
142         }
143 
144         let field_name = variants_union_field_ident(&variant.ident);
145         let variant_struct_ident = variant_struct_ident(&variant.ident);
146 
147         let core = ctx.core_path();
148         Some(quote! {
149             #field_name: #core::mem::ManuallyDrop<#variant_struct_ident #ty_generics>,
150         })
151     });
152 
153     let variants_union = parse_quote! {
154         #[repr(C)]
155         union ___ZerocopyVariants #generics {
156             #(#fields)*
157             // Enums can have variants with no fields, but unions must
158             // have at least one field. So we just add a trailing unit
159             // to ensure that this union always has at least one field.
160             // Because this union is `repr(C)`, this unit type does not
161             // affect the layout.
162             __nonempty: (),
163         }
164     };
165 
166     let has_field =
167         derive_has_field_struct_union(&ctx.with_input(&variants_union), &variants_union.data);
168 
169     quote! {
170         #variants_union
171         #has_field
172     }
173 }
174 
175 /// Generates an implementation of `is_bit_valid` for an arbitrary enum.
176 ///
177 /// The general process is:
178 ///
179 /// 1. Generate a tag enum. This is an enum with the same repr, variants, and
180 ///    corresponding discriminants as the original enum, but without any fields
181 ///    on the variants. This gives us access to an enum where the variants have
182 ///    the same discriminants as the one we're writing `is_bit_valid` for.
183 /// 2. Make constants from the variants of the tag enum. We need these because
184 ///    we can't put const exprs in match arms.
185 /// 3. Generate variant structs. These are structs which have the same fields as
186 ///    each variant of the enum, and are `#[repr(C)]` with an optional "inner
187 ///    tag".
188 /// 4. Generate a variants union, with one field for each variant struct type.
189 /// 5. And finally, our raw enum is a `#[repr(C)]` struct of an "outer tag" and
190 ///    the variants union.
191 ///
192 /// See these reference links for fully-worked example decompositions.
193 ///
194 /// - `repr(C)`: <https://doc.rust-lang.org/reference/type-layout.html#reprc-enums-with-fields>
195 /// - `repr(int)`: <https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-enums-with-fields>
196 /// - `repr(C, int)`: <https://doc.rust-lang.org/reference/type-layout.html#combining-primitive-representations-of-enums-with-fields-and-reprc>
197 pub(crate) fn derive_is_bit_valid(
198     ctx: &Ctx,
199     data: &DataEnum,
200     repr: &EnumRepr,
201 ) -> Result<TokenStream, Error> {
202     let trait_path = Trait::TryFromBytes.crate_path(ctx);
203     let tag_enum = generate_tag_enum(ctx, repr, data);
204     let tag_consts = generate_tag_consts(data);
205 
206     let (outer_tag_type, inner_tag_type) = if repr.is_c() {
207         (quote! { ___ZerocopyTag }, quote! { () })
208     } else if repr.is_primitive() {
209         (quote! { () }, quote! { ___ZerocopyTag })
210     } else {
211         return Err(Error::new(
212             ctx.ast.span(),
213             "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout",
214         ));
215     };
216 
217     let variant_structs = generate_variant_structs(ctx, data);
218     let variants_union = generate_variants_union(ctx, data);
219 
220     let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
221 
222     let zerocopy_crate = &ctx.zerocopy_crate;
223     let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None)
224         .inner_extras(quote! {
225             type Tag = ___ZerocopyTag;
226             type ProjectToTag = #zerocopy_crate::pointer::cast::CastSized;
227         })
228         .build();
229     let has_fields = data.variants().into_iter().flat_map(|(variant, fields)| {
230         let variant_ident = &variant.unwrap().ident;
231         let variants_union_field_ident = variants_union_field_ident(variant_ident);
232         let field: Box<syn::Type> = parse_quote!(());
233         fields.into_iter().enumerate().map(move |(idx, (vis, ident, ty))| {
234             // Rust does not presently support explicit visibility modifiers on
235             // enum fields, but we guard against the possibility to ensure this
236             // derive remains sound.
237             assert!(matches!(vis, syn::Visibility::Inherited));
238             let variant_struct_field_index = Index::from(idx + 1);
239             let (_, ty_generics, _) = ctx.ast.generics.split_for_impl();
240             let has_field_trait = Trait::HasField {
241                 variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }),
242                 // Since Rust does not presently support explicit visibility
243                 // modifiers on enum fields, any public type is suitable here;
244                 // we use `()`.
245                 field: field.clone(),
246                 field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }),
247             };
248             let has_field_path = has_field_trait.crate_path(ctx);
249             let has_field = ImplBlockBuilder::new(
250                 ctx,
251                 data,
252                 has_field_trait,
253                 FieldBounds::None,
254             )
255             .inner_extras(quote! {
256                 type Type = #ty;
257 
258                 #[inline(always)]
259                 fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut <Self as #has_field_path>::Type {
260                     use #zerocopy_crate::pointer::cast::{CastSized, Projection};
261 
262                     slf.project::<___ZerocopyRawEnum #ty_generics, CastSized>()
263                         .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(variants) }>>()
264                         .project::<_, Projection<_, { #zerocopy_crate::REPR_C_UNION_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variants_union_field_ident) }>>()
265                         .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(value) }>>()
266                         .project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variant_struct_field_index) }>>()
267                         .as_ptr()
268                 }
269             })
270             .build();
271 
272             let project = ImplBlockBuilder::new(
273                 ctx,
274                 data,
275                 Trait::ProjectField {
276                     variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }),
277                     // Since Rust does not presently support explicit visibility
278                     // modifiers on enum fields, any public type is suitable
279                     // here; we use `()`.
280                     field: field.clone(),
281                     field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }),
282                     invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)),
283                 },
284                 FieldBounds::None,
285             )
286             .param_extras(vec![
287                 parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing),
288                 parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment),
289             ])
290             .inner_extras(quote! {
291                 type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible;
292                 type Invariants = (Aliasing, Alignment, #zerocopy_crate::invariant::Initialized);
293             })
294             .build();
295 
296             quote! {
297                 #has_field
298                 #project
299             }
300         })
301     });
302 
303     let core = ctx.core_path();
304     let match_arms = data.variants.iter().map(|variant| {
305         let tag_ident = tag_ident(&variant.ident);
306         let variant_struct_ident = variant_struct_ident(&variant.ident);
307         let variants_union_field_ident = variants_union_field_ident(&variant.ident);
308 
309         if matches!(variant.fields, Fields::Unit) {
310             // Unit variants don't need any further validation beyond checking
311             // the tag.
312             quote! {
313                 #tag_ident => true
314             }
315         } else {
316             quote! {
317                 #tag_ident => {
318                     // SAFETY: Since we know that the tag is `#tag_ident`, we
319                     // know that no other `&`s exist which refer to this enum
320                     // as any other variant.
321                     let variant_md = variants.cast::<
322                         _,
323                         #zerocopy_crate::pointer::cast::Projection<
324                             // #zerocopy_crate::ReadOnly<_>,
325                             _,
326                             { #zerocopy_crate::REPR_C_UNION_VARIANT_ID },
327                             { #zerocopy_crate::ident_id!(#variants_union_field_ident) }
328                         >,
329                         _
330                     >();
331                     let variant = variant_md.cast::<
332                         #zerocopy_crate::ReadOnly<#variant_struct_ident #ty_generics>,
333                         #zerocopy_crate::pointer::cast::CastSized,
334                         (#zerocopy_crate::pointer::BecauseRead, _)
335                     >();
336                     <
337                         #variant_struct_ident #ty_generics as #trait_path
338                     >::is_bit_valid(variant)
339                 }
340             }
341         }
342     });
343 
344     let generics = &ctx.ast.generics;
345     let raw_enum: DeriveInput = parse_quote! {
346         #[repr(C)]
347         struct ___ZerocopyRawEnum #generics {
348             tag: ___ZerocopyOuterTag,
349             variants: ___ZerocopyVariants #ty_generics,
350         }
351     };
352 
353     let self_ident = &ctx.ast.ident;
354     let invariants_eq_impl = quote! {
355         // SAFETY: `___ZerocopyRawEnum` is designed to have the same layout,
356         // validity, and invariants as `Self`.
357         unsafe impl #impl_generics #zerocopy_crate::pointer::InvariantsEq<___ZerocopyRawEnum #ty_generics> for #self_ident #ty_generics #where_clause {}
358     };
359 
360     let raw_enum_projections =
361         derive_has_field_struct_union(&ctx.with_input(&raw_enum), &raw_enum.data);
362 
363     let raw_enum = quote! {
364         #raw_enum
365         #invariants_eq_impl
366         #raw_enum_projections
367     };
368 
369     Ok(quote! {
370         // SAFETY: We use `is_bit_valid` to validate that the bit pattern of the
371         // enum's tag corresponds to one of the enum's discriminants. Then, we
372         // check the bit validity of each field of the corresponding variant.
373         // Thus, this is a sound implementation of `is_bit_valid`.
374         #[inline]
375         fn is_bit_valid<___ZcAlignment>(
376             mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
377         ) -> #core::primitive::bool
378         where
379             ___ZcAlignment: #zerocopy_crate::invariant::Alignment,
380         {
381             #tag_enum
382 
383             type ___ZerocopyTagPrimitive = #zerocopy_crate::util::macro_util::SizeToTag<
384                 { #core::mem::size_of::<___ZerocopyTag>() },
385             >;
386 
387             #tag_consts
388 
389             type ___ZerocopyOuterTag = #outer_tag_type;
390             type ___ZerocopyInnerTag = #inner_tag_type;
391 
392             #variant_structs
393 
394             #variants_union
395 
396             #raw_enum
397 
398             #has_tag
399 
400             #(#has_fields)*
401 
402             let tag = {
403                 // SAFETY:
404                 // - The provided cast addresses a subset of the bytes addressed
405                 //   by `candidate` because it addresses the starting tag of the
406                 //   enum.
407                 // - Because the pointer is cast from `candidate`, it has the
408                 //   same provenance as it.
409                 // - There are no `UnsafeCell`s in the tag because it is a
410                 //   primitive integer.
411                 // - `tag_ptr` is casted from `candidate`, whose referent is
412                 //   `Initialized`. Since we have not written uninitialized
413                 //   bytes into the referent, `tag_ptr` is also `Initialized`.
414                 //
415                 // FIXME(#2874): Revise this to a `cast` once `candidate`
416                 // references a `ReadOnly<Self>`.
417                 let tag_ptr = unsafe {
418                     candidate.reborrow().project_transmute_unchecked::<
419                         _,
420                         #zerocopy_crate::invariant::Initialized,
421                         #zerocopy_crate::pointer::cast::CastSized
422                     >()
423                 };
424                 tag_ptr.recall_validity::<_, (_, (_, _))>().read::<#zerocopy_crate::BecauseImmutable>()
425             };
426 
427             let mut raw_enum = candidate.cast::<
428                 #zerocopy_crate::ReadOnly<___ZerocopyRawEnum #ty_generics>,
429                 #zerocopy_crate::pointer::cast::CastSized,
430                 (#zerocopy_crate::pointer::BecauseRead, _)
431             >();
432 
433             let variants = #zerocopy_crate::into_inner!(raw_enum.project::<
434                 _,
435                 { #zerocopy_crate::STRUCT_VARIANT_ID },
436                 { #zerocopy_crate::ident_id!(variants) }
437             >());
438 
439             match tag {
440                 #(#match_arms,)*
441                 _ => false,
442             }
443         }
444     })
445 }
446 pub(crate) fn derive_try_from_bytes(ctx: &Ctx, top_level: Trait) -> Result<TokenStream, Error> {
447     match &ctx.ast.data {
448         Data::Struct(strct) => derive_try_from_bytes_struct(ctx, strct, top_level),
449         Data::Enum(enm) => derive_try_from_bytes_enum(ctx, enm, top_level),
450         Data::Union(unn) => Ok(derive_try_from_bytes_union(ctx, unn, top_level)),
451     }
452 }
453 fn derive_has_field_struct_union(ctx: &Ctx, data: &dyn DataExt) -> TokenStream {
454     let fields = ctx.ast.data.fields();
455     if fields.is_empty() {
456         return quote! {};
457     }
458 
459     let field_tokens = fields.iter().map(|(vis, ident, _)| {
460         let ident = ident!(("ẕ{}", ident), ident.span());
461         quote!(
462             #vis enum #ident {}
463         )
464     });
465 
466     let zerocopy_crate = &ctx.zerocopy_crate;
467     let variant_id: Box<Expr> = match &ctx.ast.data {
468         Data::Struct(_) => parse_quote!({ #zerocopy_crate::STRUCT_VARIANT_ID }),
469         Data::Union(_) => {
470             let is_repr_c = StructUnionRepr::from_attrs(&ctx.ast.attrs)
471                 .map(|repr| repr.is_c())
472                 .unwrap_or(false);
473             if is_repr_c {
474                 parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID })
475             } else {
476                 parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID })
477             }
478         }
479         _ => unreachable!(),
480     };
481 
482     let core = ctx.core_path();
483     let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None)
484         .inner_extras(quote! {
485             type Tag = ();
486             type ProjectToTag = #zerocopy_crate::pointer::cast::CastToUnit;
487         })
488         .build();
489     let has_fields = fields.iter().map(move |(_, ident, ty)| {
490         let field_token = ident!(("ẕ{}", ident), ident.span());
491         let field: Box<Type> = parse_quote!(#field_token);
492         let field_id: Box<Expr> = parse_quote!({ #zerocopy_crate::ident_id!(#ident) });
493         let has_field_trait = Trait::HasField {
494                 variant_id: variant_id.clone(),
495                 field: field.clone(),
496                 field_id: field_id.clone(),
497             };
498             let has_field_path = has_field_trait.crate_path(ctx);
499             ImplBlockBuilder::new(
500                 ctx,
501                 data,
502                 has_field_trait,
503                 FieldBounds::None,
504             )
505             .inner_extras(quote! {
506                 type Type = #ty;
507 
508                 #[inline(always)]
509                 fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut <Self as #has_field_path>::Type {
510                     let slf = slf.as_ptr();
511                     // SAFETY: By invariant on `PtrInner`, `slf` is a non-null
512                     // pointer whose referent is zero-sized or lives in a valid
513                     // allocation. Since `#ident` is a struct or union field of
514                     // `Self`, this projection preserves or shrinks the referent
515                     // size, and so the resulting referent also fits in the same
516                     // allocation.
517                     unsafe { #core::ptr::addr_of_mut!((*slf).#ident) }
518                 }
519             }).outer_extras(if matches!(&ctx.ast.data, Data::Struct(..)) {
520             let fields_preserve_alignment = StructUnionRepr::from_attrs(&ctx.ast.attrs)
521                 .map(|repr| repr.get_packed().is_none())
522                 .unwrap();
523             let alignment = if fields_preserve_alignment {
524                 quote! { Alignment }
525             } else {
526                 quote! { #zerocopy_crate::invariant::Unaligned }
527             };
528             // SAFETY: See comments on items.
529             ImplBlockBuilder::new(
530                 ctx,
531                 data,
532                 Trait::ProjectField {
533                     variant_id: variant_id.clone(),
534                     field: field.clone(),
535                     field_id: field_id.clone(),
536                     invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)),
537                 },
538                 FieldBounds::None,
539             )
540             .param_extras(vec![
541                 parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing),
542                 parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment),
543             ])
544             .inner_extras(quote! {
545                 // SAFETY: Projection into structs is always infallible.
546                 type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible;
547                 // SAFETY: The alignment of the projected `Ptr` is `Unaligned`
548                 // if the structure is packed; otherwise inherited from the
549                 // outer `Ptr`. If the validity of the outer pointer is
550                 // `Initialized`, so too is the validity of its fields.
551                 type Invariants = (Aliasing, #alignment, #zerocopy_crate::invariant::Initialized);
552             })
553             .build()
554         } else {
555             quote! {}
556         })
557         .build()
558     });
559 
560     const_block(field_tokens.into_iter().chain(Some(has_tag)).chain(has_fields).map(Some))
561 }
562 fn derive_try_from_bytes_struct(
563     ctx: &Ctx,
564     strct: &DataStruct,
565     top_level: Trait,
566 ) -> Result<TokenStream, Error> {
567     let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| {
568         let zerocopy_crate = &ctx.zerocopy_crate;
569         let fields = strct.fields();
570         let field_names = fields.iter().map(|(_vis, name, _ty)| name);
571         let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
572         let core = ctx.core_path();
573         quote!(
574             // SAFETY: We use `is_bit_valid` to validate that each field is
575             // bit-valid, and only return `true` if all of them are. The bit
576             // validity of a struct is just the composition of the bit
577             // validities of its fields, so this is a sound implementation
578             // of `is_bit_valid`.
579             #[inline]
580             fn is_bit_valid<___ZcAlignment>(
581                 mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
582             ) -> #core::primitive::bool
583             where
584                 ___ZcAlignment: #zerocopy_crate::invariant::Alignment,
585             {
586                 true #(&& {
587                     let field_candidate =   #zerocopy_crate::into_inner!(candidate.reborrow().project::<
588                         _,
589                         { #zerocopy_crate::STRUCT_VARIANT_ID },
590                         { #zerocopy_crate::ident_id!(#field_names) }
591                     >());
592                     <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
593                 })*
594             }
595         )
596     });
597     Ok(ImplBlockBuilder::new(ctx, strct, Trait::TryFromBytes, FieldBounds::ALL_SELF)
598         .inner_extras(extras)
599         .outer_extras(derive_has_field_struct_union(ctx, strct))
600         .build())
601 }
602 fn derive_try_from_bytes_union(ctx: &Ctx, unn: &DataUnion, top_level: Trait) -> TokenStream {
603     let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
604 
605     let zerocopy_crate = &ctx.zerocopy_crate;
606     let variant_id: Box<Expr> = {
607         let is_repr_c =
608             StructUnionRepr::from_attrs(&ctx.ast.attrs).map(|repr| repr.is_c()).unwrap_or(false);
609         if is_repr_c {
610             parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID })
611         } else {
612             parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID })
613         }
614     };
615 
616     let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| {
617         let fields = unn.fields();
618         let field_names = fields.iter().map(|(_vis, name, _ty)| name);
619         let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
620         let core = ctx.core_path();
621         quote!(
622             // SAFETY: We use `is_bit_valid` to validate that any field is
623             // bit-valid; we only return `true` if at least one of them is.
624             // The bit validity of a union is not yet well defined in Rust,
625             // but it is guaranteed to be no more strict than this
626             // definition. See #696 for a more in-depth discussion.
627             #[inline]
628             fn is_bit_valid<___ZcAlignment>(
629                 mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
630             ) -> #core::primitive::bool
631             where
632                 ___ZcAlignment: #zerocopy_crate::invariant::Alignment,
633             {
634                 false #(|| {
635                     // SAFETY:
636                     // - Since `ReadOnly<Self>: Immutable` unconditionally,
637                     //   neither `*slf` nor the returned pointer's referent
638                     //   permit interior mutation.
639                     // - Both source and destination validity are
640                     //   `Initialized`, which is always a sound
641                     //   transmutation.
642                     let field_candidate = unsafe {
643                         candidate.reborrow().project_transmute_unchecked::<
644                             _,
645                             _,
646                             #zerocopy_crate::pointer::cast::Projection<
647                                 _,
648                                 #variant_id,
649                                 { #zerocopy_crate::ident_id!(#field_names) }
650                             >
651                         >()
652                     };
653 
654                     <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
655                 })*
656             }
657         )
658     });
659     ImplBlockBuilder::new(ctx, unn, Trait::TryFromBytes, field_type_trait_bounds)
660         .inner_extras(extras)
661         .outer_extras(derive_has_field_struct_union(ctx, unn))
662         .build()
663 }
664 fn derive_try_from_bytes_enum(
665     ctx: &Ctx,
666     enm: &DataEnum,
667     top_level: Trait,
668 ) -> Result<TokenStream, Error> {
669     let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
670 
671     // If an enum has no fields, it has a well-defined integer representation,
672     // and every possible bit pattern corresponds to a valid discriminant tag,
673     // then it *could* be `FromBytes` (even if the user hasn't derived
674     // `FromBytes`). This holds if, for `repr(uN)` or `repr(iN)`, there are 2^N
675     // variants.
676     let could_be_from_bytes = enum_size_from_repr(&repr)
677         .map(|size| enm.fields().is_empty() && enm.variants.len() == 1usize << size)
678         .unwrap_or(false);
679 
680     let trivial_is_bit_valid = try_gen_trivial_is_bit_valid(ctx, top_level);
681     let extra = match (trivial_is_bit_valid, could_be_from_bytes) {
682         (Some(is_bit_valid), _) => is_bit_valid,
683         // SAFETY: It would be sound for the enum to implement `FromBytes`, as
684         // required by `gen_trivial_is_bit_valid_unchecked`.
685         (None, true) => unsafe { gen_trivial_is_bit_valid_unchecked(ctx) },
686         (None, false) => match derive_is_bit_valid(ctx, enm, &repr) {
687             Ok(extra) => extra,
688             Err(_) if ctx.skip_on_error => return Ok(TokenStream::new()),
689             Err(e) => return Err(e),
690         },
691     };
692 
693     Ok(ImplBlockBuilder::new(ctx, enm, Trait::TryFromBytes, FieldBounds::ALL_SELF)
694         .inner_extras(extra)
695         .build())
696 }
697 fn try_gen_trivial_is_bit_valid(ctx: &Ctx, top_level: Trait) -> Option<proc_macro2::TokenStream> {
698     // If the top-level trait is `FromBytes` and `Self` has no type parameters,
699     // then the `FromBytes` derive will fail compilation if `Self` is not
700     // actually soundly `FromBytes`, and so we can rely on that for our
701     // `is_bit_valid` impl. It's plausible that we could make changes - or Rust
702     // could make changes (such as the "trivial bounds" language feature) - that
703     // make this no longer true. To hedge against these, we include an explicit
704     // `Self: FromBytes` check in the generated `is_bit_valid`, which is
705     // bulletproof.
706     //
707     // If `ctx.skip_on_error` is true, we can't rely on the `FromBytes` derive
708     // to fail compilation if `Self` is not actually soundly `FromBytes`.
709     if matches!(top_level, Trait::FromBytes)
710         && ctx.ast.generics.params.is_empty()
711         && !ctx.skip_on_error
712     {
713         let zerocopy_crate = &ctx.zerocopy_crate;
714         let core = ctx.core_path();
715         Some(quote!(
716             // SAFETY: See inline.
717             #[inline(always)]
718             fn is_bit_valid<___ZcAlignment>(
719                 _candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
720             ) -> #core::primitive::bool
721             where
722                 ___ZcAlignment: #zerocopy_crate::invariant::Alignment,
723             {
724                 if false {
725                     fn assert_is_from_bytes<T>()
726                     where
727                         T: #zerocopy_crate::FromBytes,
728                         T: ?#core::marker::Sized,
729                     {
730                     }
731 
732                     assert_is_from_bytes::<Self>();
733                 }
734 
735                 // SAFETY: The preceding code only compiles if `Self:
736                 // FromBytes`. Thus, this code only compiles if all initialized
737                 // byte sequences represent valid instances of `Self`.
738                 true
739             }
740         ))
741     } else {
742         None
743     }
744 }
745 
746 /// # Safety
747 ///
748 /// All initialized bit patterns must be valid for `Self`.
749 unsafe fn gen_trivial_is_bit_valid_unchecked(ctx: &Ctx) -> proc_macro2::TokenStream {
750     let zerocopy_crate = &ctx.zerocopy_crate;
751     let core = ctx.core_path();
752     quote!(
753         // SAFETY: The caller of `gen_trivial_is_bit_valid_unchecked` has
754         // promised that all initialized bit patterns are valid for `Self`.
755         #[inline(always)]
756         fn is_bit_valid<___ZcAlignment>(
757             _candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
758         ) -> #core::primitive::bool
759         where
760             ___ZcAlignment: #zerocopy_crate::invariant::Alignment,
761         {
762             true
763         }
764     )
765 }
766