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