zerocopy_derive/
lib.rs

1// Copyright 2019 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9//! Derive macros for [zerocopy]'s traits.
10//!
11//! [zerocopy]: https://docs.rs/zerocopy
12
13// Sometimes we want to use lints which were added after our MSRV.
14// `unknown_lints` is `warn` by default and we deny warnings in CI, so without
15// this attribute, any unknown lint would cause a CI failure when testing with
16// our MSRV.
17#![allow(unknown_lints)]
18#![deny(renamed_and_removed_lints)]
19#![deny(
20    clippy::all,
21    clippy::missing_safety_doc,
22    clippy::multiple_unsafe_ops_per_block,
23    clippy::undocumented_unsafe_blocks
24)]
25// Inlining format args isn't supported on our MSRV.
26#![allow(clippy::uninlined_format_args)]
27#![deny(
28    rustdoc::bare_urls,
29    rustdoc::broken_intra_doc_links,
30    rustdoc::invalid_codeblock_attributes,
31    rustdoc::invalid_html_tags,
32    rustdoc::invalid_rust_codeblocks,
33    rustdoc::missing_crate_level_docs,
34    rustdoc::private_intra_doc_links
35)]
36#![recursion_limit = "128"]
37
38mod r#enum;
39mod ext;
40#[cfg(test)]
41mod output_tests;
42mod repr;
43
44use proc_macro2::{Span, TokenStream, TokenTree};
45use quote::{quote, ToTokens};
46use syn::{
47    parse_quote, Attribute, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Expr,
48    ExprLit, ExprUnary, GenericParam, Ident, Lit, Meta, Path, Type, UnOp, WherePredicate,
49};
50
51use crate::{ext::*, repr::*};
52
53// FIXME(https://github.com/rust-lang/rust/issues/54140): Some errors could be
54// made better if we could add multiple lines of error output like this:
55//
56// error: unsupported representation
57//   --> enum.rs:28:8
58//    |
59// 28 | #[repr(transparent)]
60//    |
61// help: required by the derive of FromBytes
62//
63// Instead, we have more verbose error messages like "unsupported representation
64// for deriving FromZeros, FromBytes, IntoBytes, or Unaligned on an enum"
65//
66// This will probably require Span::error
67// (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error),
68// which is currently unstable. Revisit this once it's stable.
69
70/// Defines a derive function named `$outer` which parses its input
71/// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function.
72///
73/// Note that the separate `$outer` parameter is required - proc macro functions
74/// are currently required to live at the crate root, and so the caller must
75/// specify the name in order to avoid name collisions.
76macro_rules! derive {
77    ($trait:ident => $outer:ident => $inner:ident) => {
78        #[proc_macro_derive($trait, attributes(zerocopy))]
79        pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
80            let ast = syn::parse_macro_input!(ts as DeriveInput);
81            let zerocopy_crate = match extract_zerocopy_crate(&ast.attrs) {
82                Ok(zerocopy_crate) => zerocopy_crate,
83                Err(e) => return e.into_compile_error().into(),
84            };
85            $inner(&ast, Trait::$trait, &zerocopy_crate).into_ts().into()
86        }
87    };
88}
89
90trait IntoTokenStream {
91    fn into_ts(self) -> TokenStream;
92}
93
94impl IntoTokenStream for TokenStream {
95    fn into_ts(self) -> TokenStream {
96        self
97    }
98}
99
100impl IntoTokenStream for Result<TokenStream, Error> {
101    fn into_ts(self) -> TokenStream {
102        match self {
103            Ok(ts) => ts,
104            Err(err) => err.to_compile_error(),
105        }
106    }
107}
108
109/// Attempt to extract a crate path from the provided attributes. Defaults to
110/// `::zerocopy` if not found.
111fn extract_zerocopy_crate(attrs: &[Attribute]) -> Result<Path, Error> {
112    let mut path = parse_quote!(::zerocopy);
113
114    for attr in attrs {
115        if let Meta::List(ref meta_list) = attr.meta {
116            if meta_list.path.is_ident("zerocopy") {
117                attr.parse_nested_meta(|meta| {
118                    if meta.path.is_ident("crate") {
119                        let expr = meta.value().and_then(|value| value.parse());
120                        if let Ok(Expr::Lit(ExprLit { lit: Lit::Str(lit), .. })) = expr {
121                            if let Ok(path_lit) = lit.parse() {
122                                path = path_lit;
123                                return Ok(());
124                            }
125                        }
126
127                        return Err(Error::new(
128                            Span::call_site(),
129                            "`crate` attribute requires a path as the value",
130                        ));
131                    }
132
133                    Err(Error::new(
134                        Span::call_site(),
135                        format!("unknown attribute encountered: {}", meta.path.into_token_stream()),
136                    ))
137                })?;
138            }
139        }
140    }
141
142    Ok(path)
143}
144
145derive!(KnownLayout => derive_known_layout => derive_known_layout_inner);
146derive!(Immutable => derive_no_cell => derive_no_cell_inner);
147derive!(TryFromBytes => derive_try_from_bytes => derive_try_from_bytes_inner);
148derive!(FromZeros => derive_from_zeros => derive_from_zeros_inner);
149derive!(FromBytes => derive_from_bytes => derive_from_bytes_inner);
150derive!(IntoBytes => derive_into_bytes => derive_into_bytes_inner);
151derive!(Unaligned => derive_unaligned => derive_unaligned_inner);
152derive!(ByteHash => derive_hash => derive_hash_inner);
153derive!(ByteEq => derive_eq => derive_eq_inner);
154derive!(SplitAt => derive_split_at => derive_split_at_inner);
155
156/// Deprecated: prefer [`FromZeros`] instead.
157#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
158#[doc(hidden)]
159#[proc_macro_derive(FromZeroes)]
160pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
161    derive_from_zeros(ts)
162}
163
164/// Deprecated: prefer [`IntoBytes`] instead.
165#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")]
166#[doc(hidden)]
167#[proc_macro_derive(AsBytes)]
168pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
169    derive_into_bytes(ts)
170}
171
172fn derive_known_layout_inner(
173    ast: &DeriveInput,
174    _top_level: Trait,
175    zerocopy_crate: &Path,
176) -> Result<TokenStream, Error> {
177    let is_repr_c_struct = match &ast.data {
178        Data::Struct(..) => {
179            let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
180            if repr.is_c() {
181                Some(repr)
182            } else {
183                None
184            }
185        }
186        Data::Enum(..) | Data::Union(..) => None,
187    };
188
189    let fields = ast.data.fields();
190
191    let (self_bounds, inner_extras, outer_extras) = if let (
192        Some(repr),
193        Some((trailing_field, leading_fields)),
194    ) = (is_repr_c_struct, fields.split_last())
195    {
196        let (_vis, trailing_field_name, trailing_field_ty) = trailing_field;
197        let leading_fields_tys = leading_fields.iter().map(|(_vis, _name, ty)| ty);
198
199        let core_path = quote!(#zerocopy_crate::util::macro_util::core_reexport);
200        let repr_align = repr
201            .get_align()
202            .map(|align| {
203                let align = align.t.get();
204                quote!(#core_path::num::NonZeroUsize::new(#align as usize))
205            })
206            .unwrap_or_else(|| quote!(#core_path::option::Option::None));
207        let repr_packed = repr
208            .get_packed()
209            .map(|packed| {
210                let packed = packed.get();
211                quote!(#core_path::num::NonZeroUsize::new(#packed as usize))
212            })
213            .unwrap_or_else(|| quote!(#core_path::option::Option::None));
214
215        let make_methods = |trailing_field_ty| {
216            quote! {
217                // SAFETY:
218                // - The returned pointer has the same address and provenance as
219                //   `bytes`:
220                //   - The recursive call to `raw_from_ptr_len` preserves both
221                //     address and provenance.
222                //   - The `as` cast preserves both address and provenance.
223                //   - `NonNull::new_unchecked` preserves both address and
224                //     provenance.
225                // - If `Self` is a slice DST, the returned pointer encodes
226                //   `elems` elements in the trailing slice:
227                //   - This is true of the recursive call to `raw_from_ptr_len`.
228                //   - `trailing.as_ptr() as *mut Self` preserves trailing slice
229                //     element count [1].
230                //   - `NonNull::new_unchecked` preserves trailing slice element
231                //     count.
232                //
233                // [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast:
234                //
235                //   `*const T`` / `*mut T` can be cast to `*const U` / `*mut U`
236                //   with the following behavior:
237                //     ...
238                //     - If `T` and `U` are both unsized, the pointer is also
239                //       returned unchanged. In particular, the metadata is
240                //       preserved exactly.
241                //
242                //       For instance, a cast from `*const [T]` to `*const [U]`
243                //       preserves the number of elements. ... The same holds
244                //       for str and any compound type whose unsized tail is a
245                //       slice type, such as struct `Foo(i32, [u8])` or
246                //       `(u64, Foo)`.
247                #[inline(always)]
248                fn raw_from_ptr_len(
249                    bytes: #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<u8>,
250                    meta: Self::PointerMetadata,
251                ) -> #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<Self> {
252                    use #zerocopy_crate::KnownLayout;
253                    let trailing = <#trailing_field_ty as KnownLayout>::raw_from_ptr_len(bytes, meta);
254                    let slf = trailing.as_ptr() as *mut Self;
255                    // SAFETY: Constructed from `trailing`, which is non-null.
256                    unsafe { #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(slf) }
257                }
258
259                #[inline(always)]
260                fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
261                    <#trailing_field_ty>::pointer_to_metadata(ptr as *mut _)
262                }
263            }
264        };
265
266        let inner_extras = {
267            let leading_fields_tys = leading_fields_tys.clone();
268            let methods = make_methods(*trailing_field_ty);
269            let (_, ty_generics, _) = ast.generics.split_for_impl();
270
271            quote!(
272                type PointerMetadata = <#trailing_field_ty as #zerocopy_crate::KnownLayout>::PointerMetadata;
273
274                type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit #ty_generics;
275
276                // SAFETY: `LAYOUT` accurately describes the layout of `Self`.
277                // The documentation of `DstLayout::for_repr_c_struct` vows that
278                // invocations in this manner will accurately describe a type,
279                // so long as:
280                //
281                //  - that type is `repr(C)`,
282                //  - its fields are enumerated in the order they appear,
283                //  - the presence of `repr_align` and `repr_packed` are
284                //    correctly accounted for.
285                //
286                // We respect all three of these preconditions here. This
287                // expansion is only used if `is_repr_c_struct`, we enumerate
288                // the fields in order, and we extract the values of `align(N)`
289                // and `packed(N)`.
290                const LAYOUT: #zerocopy_crate::DstLayout = {
291                    use #zerocopy_crate::util::macro_util::core_reexport::num::NonZeroUsize;
292                    use #zerocopy_crate::{DstLayout, KnownLayout};
293
294                    DstLayout::for_repr_c_struct(
295                        #repr_align,
296                        #repr_packed,
297                        &[
298                            #(DstLayout::for_type::<#leading_fields_tys>(),)*
299                            <#trailing_field_ty as KnownLayout>::LAYOUT
300                        ],
301                    )
302                };
303
304                #methods
305            )
306        };
307
308        let outer_extras = {
309            let ident = &ast.ident;
310            let vis = &ast.vis;
311            let params = &ast.generics.params;
312            let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
313
314            let predicates = if let Some(where_clause) = where_clause {
315                where_clause.predicates.clone()
316            } else {
317                Default::default()
318            };
319
320            // Generate a valid ident for a type-level handle to a field of a
321            // given `name`.
322            let field_index = |name: &TokenStream| {
323                let name = to_ident_str(name);
324                Ident::new(&format!("__Zerocopy_Field_{}", name), ident.span())
325            };
326
327            let field_indices: Vec<_> =
328                fields.iter().map(|(_vis, name, _ty)| field_index(name)).collect();
329
330            // Define the collection of type-level field handles.
331            let field_defs = field_indices.iter().zip(&fields).map(|(idx, (vis, _, _))| {
332                quote! {
333                    #[allow(non_camel_case_types)]
334                    #vis struct #idx;
335                }
336            });
337
338            let field_impls = field_indices.iter().zip(&fields).map(|(idx, (_, _, ty))| quote! {
339                // SAFETY: `#ty` is the type of `#ident`'s field at `#idx`.
340                #[allow(deprecated)]
341                unsafe impl #impl_generics #zerocopy_crate::util::macro_util::Field<#idx> for #ident #ty_generics
342                where
343                    #predicates
344                {
345                    type Type = #ty;
346                }
347            });
348
349            let trailing_field_index = field_index(trailing_field_name);
350            let leading_field_indices =
351                leading_fields.iter().map(|(_vis, name, _ty)| field_index(name));
352
353            let trailing_field_ty = quote! {
354                <#ident #ty_generics as
355                    #zerocopy_crate::util::macro_util::Field<#trailing_field_index>
356                >::Type
357            };
358
359            let methods = make_methods(&parse_quote! {
360                <#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
361            });
362
363            quote! {
364                #(#field_defs)*
365
366                #(#field_impls)*
367
368                // SAFETY: This has the same layout as the derive target type,
369                // except that it admits uninit bytes. This is ensured by using
370                // the same repr as the target type, and by using field types
371                // which have the same layout as the target type's fields,
372                // except that they admit uninit bytes. We indirect through
373                // `Field` to ensure that occurrences of `Self` resolve to
374                // `#ty`, not `__ZerocopyKnownLayoutMaybeUninit` (see #2116).
375                #repr
376                #[doc(hidden)]
377                // Required on some rustc versions due to a lint that is only
378                // triggered when `derive(KnownLayout)` is applied to `repr(C)`
379                // structs that are generated by macros. See #2177 for details.
380                #[allow(private_bounds)]
381                #[allow(deprecated)]
382                #vis struct __ZerocopyKnownLayoutMaybeUninit<#params> (
383                    #(#zerocopy_crate::util::macro_util::core_reexport::mem::MaybeUninit<
384                        <#ident #ty_generics as
385                            #zerocopy_crate::util::macro_util::Field<#leading_field_indices>
386                        >::Type
387                    >,)*
388                    // NOTE(#2302): We wrap in `ManuallyDrop` here in case the
389                    // type we're operating on is both generic and
390                    // `repr(packed)`. In that case, Rust needs to know that the
391                    // type is *either* `Sized` or has a trivial `Drop`.
392                    // `ManuallyDrop` has a trivial `Drop`, and so satisfies
393                    // this requirement.
394                    #zerocopy_crate::util::macro_util::core_reexport::mem::ManuallyDrop<
395                        <#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
396                    >
397                )
398                where
399                    #trailing_field_ty: #zerocopy_crate::KnownLayout,
400                    #predicates;
401
402                // SAFETY: We largely defer to the `KnownLayout` implementation
403                // on the derive target type (both by using the same tokens, and
404                // by deferring to impl via type-level indirection). This is
405                // sound, since `__ZerocopyKnownLayoutMaybeUninit` is guaranteed
406                // to have the same layout as the derive target type, except
407                // that `__ZerocopyKnownLayoutMaybeUninit` admits uninit bytes.
408                #[allow(deprecated)]
409                unsafe impl #impl_generics #zerocopy_crate::KnownLayout for __ZerocopyKnownLayoutMaybeUninit #ty_generics
410                where
411                    #trailing_field_ty: #zerocopy_crate::KnownLayout,
412                    #predicates
413                {
414                    #[allow(clippy::missing_inline_in_public_items)]
415                    fn only_derive_is_allowed_to_implement_this_trait() {}
416
417                    type PointerMetadata = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::PointerMetadata;
418
419                    type MaybeUninit = Self;
420
421                    const LAYOUT: #zerocopy_crate::DstLayout = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::LAYOUT;
422
423                    #methods
424                }
425            }
426        };
427
428        (SelfBounds::None, inner_extras, Some(outer_extras))
429    } else {
430        // For enums, unions, and non-`repr(C)` structs, we require that
431        // `Self` is sized, and as a result don't need to reason about the
432        // internals of the type.
433        (
434            SelfBounds::SIZED,
435            quote!(
436                type PointerMetadata = ();
437                type MaybeUninit =
438                    #zerocopy_crate::util::macro_util::core_reexport::mem::MaybeUninit<Self>;
439
440                // SAFETY: `LAYOUT` is guaranteed to accurately describe the
441                // layout of `Self`, because that is the documented safety
442                // contract of `DstLayout::for_type`.
443                const LAYOUT: #zerocopy_crate::DstLayout = #zerocopy_crate::DstLayout::for_type::<Self>();
444
445                // SAFETY: `.cast` preserves address and provenance.
446                //
447                // FIXME(#429): Add documentation to `.cast` that promises that
448                // it preserves provenance.
449                #[inline(always)]
450                fn raw_from_ptr_len(
451                    bytes: #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<u8>,
452                    _meta: (),
453                ) -> #zerocopy_crate::util::macro_util::core_reexport::ptr::NonNull<Self>
454                {
455                    bytes.cast::<Self>()
456                }
457
458                #[inline(always)]
459                fn pointer_to_metadata(_ptr: *mut Self) -> () {}
460            ),
461            None,
462        )
463    };
464
465    Ok(match &ast.data {
466        Data::Struct(strct) => {
467            let require_trait_bound_on_field_types = if self_bounds == SelfBounds::SIZED {
468                FieldBounds::None
469            } else {
470                FieldBounds::TRAILING_SELF
471            };
472
473            // A bound on the trailing field is required, since structs are
474            // unsized if their trailing field is unsized. Reflecting the layout
475            // of an usized trailing field requires that the field is
476            // `KnownLayout`.
477            ImplBlockBuilder::new(
478                ast,
479                strct,
480                Trait::KnownLayout,
481                require_trait_bound_on_field_types,
482                zerocopy_crate,
483            )
484            .self_type_trait_bounds(self_bounds)
485            .inner_extras(inner_extras)
486            .outer_extras(outer_extras)
487            .build()
488        }
489        Data::Enum(enm) => {
490            // A bound on the trailing field is not required, since enums cannot
491            // currently be unsized.
492            ImplBlockBuilder::new(ast, enm, Trait::KnownLayout, FieldBounds::None, zerocopy_crate)
493                .self_type_trait_bounds(SelfBounds::SIZED)
494                .inner_extras(inner_extras)
495                .outer_extras(outer_extras)
496                .build()
497        }
498        Data::Union(unn) => {
499            // A bound on the trailing field is not required, since unions
500            // cannot currently be unsized.
501            ImplBlockBuilder::new(ast, unn, Trait::KnownLayout, FieldBounds::None, zerocopy_crate)
502                .self_type_trait_bounds(SelfBounds::SIZED)
503                .inner_extras(inner_extras)
504                .outer_extras(outer_extras)
505                .build()
506        }
507    })
508}
509
510fn derive_no_cell_inner(
511    ast: &DeriveInput,
512    _top_level: Trait,
513    zerocopy_crate: &Path,
514) -> TokenStream {
515    match &ast.data {
516        Data::Struct(strct) => ImplBlockBuilder::new(
517            ast,
518            strct,
519            Trait::Immutable,
520            FieldBounds::ALL_SELF,
521            zerocopy_crate,
522        )
523        .build(),
524        Data::Enum(enm) => {
525            ImplBlockBuilder::new(ast, enm, Trait::Immutable, FieldBounds::ALL_SELF, zerocopy_crate)
526                .build()
527        }
528        Data::Union(unn) => {
529            ImplBlockBuilder::new(ast, unn, Trait::Immutable, FieldBounds::ALL_SELF, zerocopy_crate)
530                .build()
531        }
532    }
533}
534
535fn derive_try_from_bytes_inner(
536    ast: &DeriveInput,
537    top_level: Trait,
538    zerocopy_crate: &Path,
539) -> Result<TokenStream, Error> {
540    match &ast.data {
541        Data::Struct(strct) => derive_try_from_bytes_struct(ast, strct, top_level, zerocopy_crate),
542        Data::Enum(enm) => derive_try_from_bytes_enum(ast, enm, top_level, zerocopy_crate),
543        Data::Union(unn) => Ok(derive_try_from_bytes_union(ast, unn, top_level, zerocopy_crate)),
544    }
545}
546
547fn derive_from_zeros_inner(
548    ast: &DeriveInput,
549    top_level: Trait,
550    zerocopy_crate: &Path,
551) -> Result<TokenStream, Error> {
552    let try_from_bytes = derive_try_from_bytes_inner(ast, top_level, zerocopy_crate)?;
553    let from_zeros = match &ast.data {
554        Data::Struct(strct) => derive_from_zeros_struct(ast, strct, zerocopy_crate),
555        Data::Enum(enm) => derive_from_zeros_enum(ast, enm, zerocopy_crate)?,
556        Data::Union(unn) => derive_from_zeros_union(ast, unn, zerocopy_crate),
557    };
558    Ok(IntoIterator::into_iter([try_from_bytes, from_zeros]).collect())
559}
560
561fn derive_from_bytes_inner(
562    ast: &DeriveInput,
563    top_level: Trait,
564    zerocopy_crate: &Path,
565) -> Result<TokenStream, Error> {
566    let from_zeros = derive_from_zeros_inner(ast, top_level, zerocopy_crate)?;
567    let from_bytes = match &ast.data {
568        Data::Struct(strct) => derive_from_bytes_struct(ast, strct, zerocopy_crate),
569        Data::Enum(enm) => derive_from_bytes_enum(ast, enm, zerocopy_crate)?,
570        Data::Union(unn) => derive_from_bytes_union(ast, unn, zerocopy_crate),
571    };
572
573    Ok(IntoIterator::into_iter([from_zeros, from_bytes]).collect())
574}
575
576fn derive_into_bytes_inner(
577    ast: &DeriveInput,
578    _top_level: Trait,
579    zerocopy_crate: &Path,
580) -> Result<TokenStream, Error> {
581    match &ast.data {
582        Data::Struct(strct) => derive_into_bytes_struct(ast, strct, zerocopy_crate),
583        Data::Enum(enm) => derive_into_bytes_enum(ast, enm, zerocopy_crate),
584        Data::Union(unn) => derive_into_bytes_union(ast, unn, zerocopy_crate),
585    }
586}
587
588fn derive_unaligned_inner(
589    ast: &DeriveInput,
590    _top_level: Trait,
591    zerocopy_crate: &Path,
592) -> Result<TokenStream, Error> {
593    match &ast.data {
594        Data::Struct(strct) => derive_unaligned_struct(ast, strct, zerocopy_crate),
595        Data::Enum(enm) => derive_unaligned_enum(ast, enm, zerocopy_crate),
596        Data::Union(unn) => derive_unaligned_union(ast, unn, zerocopy_crate),
597    }
598}
599
600fn derive_hash_inner(
601    ast: &DeriveInput,
602    _top_level: Trait,
603    zerocopy_crate: &Path,
604) -> Result<TokenStream, Error> {
605    // This doesn't delegate to `impl_block` because `impl_block` assumes it is
606    // deriving a `zerocopy`-defined trait, and these trait impls share a common
607    // shape that `Hash` does not. In particular, `zerocopy` traits contain a
608    // method that only `zerocopy_derive` macros are supposed to implement, and
609    // `impl_block` generating this trait method is incompatible with `Hash`.
610    let type_ident = &ast.ident;
611    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
612    let where_predicates = where_clause.map(|clause| &clause.predicates);
613    Ok(quote! {
614        #[allow(deprecated)]
615        // While there are not currently any warnings that this suppresses (that
616        // we're aware of), it's good future-proofing hygiene.
617        #[automatically_derived]
618        impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::hash::Hash for #type_ident #ty_generics
619        where
620            Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
621            #where_predicates
622        {
623            fn hash<H>(&self, state: &mut H)
624            where
625                H: #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher,
626            {
627                #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher::write(
628                    state,
629                    #zerocopy_crate::IntoBytes::as_bytes(self)
630                )
631            }
632
633            fn hash_slice<H>(data: &[Self], state: &mut H)
634            where
635                H: #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher,
636            {
637                #zerocopy_crate::util::macro_util::core_reexport::hash::Hasher::write(
638                    state,
639                    #zerocopy_crate::IntoBytes::as_bytes(data)
640                )
641            }
642        }
643    })
644}
645
646fn derive_eq_inner(
647    ast: &DeriveInput,
648    _top_level: Trait,
649    zerocopy_crate: &Path,
650) -> Result<TokenStream, Error> {
651    // This doesn't delegate to `impl_block` because `impl_block` assumes it is
652    // deriving a `zerocopy`-defined trait, and these trait impls share a common
653    // shape that `Eq` does not. In particular, `zerocopy` traits contain a
654    // method that only `zerocopy_derive` macros are supposed to implement, and
655    // `impl_block` generating this trait method is incompatible with `Eq`.
656    let type_ident = &ast.ident;
657    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
658    let where_predicates = where_clause.map(|clause| &clause.predicates);
659    Ok(quote! {
660        // FIXME(#553): Add a test that generates a warning when
661        // `#[allow(deprecated)]` isn't present.
662        #[allow(deprecated)]
663        // While there are not currently any warnings that this suppresses (that
664        // we're aware of), it's good future-proofing hygiene.
665        #[automatically_derived]
666        impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::cmp::PartialEq for #type_ident #ty_generics
667        where
668            Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
669            #where_predicates
670        {
671            fn eq(&self, other: &Self) -> bool {
672                #zerocopy_crate::util::macro_util::core_reexport::cmp::PartialEq::eq(
673                    #zerocopy_crate::IntoBytes::as_bytes(self),
674                    #zerocopy_crate::IntoBytes::as_bytes(other),
675                )
676            }
677        }
678
679        // FIXME(#553): Add a test that generates a warning when
680        // `#[allow(deprecated)]` isn't present.
681        #[allow(deprecated)]
682        // While there are not currently any warnings that this suppresses (that
683        // we're aware of), it's good future-proofing hygiene.
684        #[automatically_derived]
685        impl #impl_generics #zerocopy_crate::util::macro_util::core_reexport::cmp::Eq for #type_ident #ty_generics
686        where
687            Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
688            #where_predicates
689        {
690        }
691    })
692}
693
694fn derive_split_at_inner(
695    ast: &DeriveInput,
696    _top_level: Trait,
697    zerocopy_crate: &Path,
698) -> Result<TokenStream, Error> {
699    let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
700
701    match &ast.data {
702        Data::Struct(_) => {}
703        Data::Enum(_) | Data::Union(_) => {
704            return Err(Error::new(Span::call_site(), "can only be applied to structs"));
705        }
706    };
707
708    if repr.get_packed().is_some() {
709        return Err(Error::new(Span::call_site(), "must not have #[repr(packed)] attribute"));
710    }
711
712    if !(repr.is_c() || repr.is_transparent()) {
713        return Err(Error::new(Span::call_site(), "must have #[repr(C)] or #[repr(transparent)] in order to guarantee this type's layout is splitable"));
714    }
715
716    let fields = ast.data.fields();
717    let trailing_field = if let Some(((_, _, trailing_field), _)) = fields.split_last() {
718        trailing_field
719    } else {
720        return Err(Error::new(Span::call_site(), "must at least one field"));
721    };
722
723    // SAFETY: `#ty`, per the above checks, is `repr(C)` or `repr(transparent)`
724    // and is not packed; its trailing field is guaranteed to be well-aligned
725    // for its type. By invariant on `FieldBounds::TRAILING_SELF`, the trailing
726    // slice of the trailing field is also well-aligned for its type.
727    Ok(ImplBlockBuilder::new(
728        ast,
729        &ast.data,
730        Trait::SplitAt,
731        FieldBounds::TRAILING_SELF,
732        zerocopy_crate,
733    )
734    .inner_extras(quote! {
735        type Elem = <#trailing_field as ::zerocopy::SplitAt>::Elem;
736    })
737    .build())
738}
739
740/// A struct is `TryFromBytes` if:
741/// - all fields are `TryFromBytes`
742fn derive_try_from_bytes_struct(
743    ast: &DeriveInput,
744    strct: &DataStruct,
745    top_level: Trait,
746    zerocopy_crate: &Path,
747) -> Result<TokenStream, Error> {
748    let extras =
749        try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate).unwrap_or_else(|| {
750            let fields = strct.fields();
751            let field_names = fields.iter().map(|(_vis, name, _ty)| name);
752            let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
753            quote!(
754                // SAFETY: We use `is_bit_valid` to validate that each field is
755                // bit-valid, and only return `true` if all of them are. The bit
756                // validity of a struct is just the composition of the bit
757                // validities of its fields, so this is a sound implementation
758                // of `is_bit_valid`.
759                fn is_bit_valid<___ZerocopyAliasing>(
760                    mut candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
761                ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
762                where
763                    ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
764                {
765                    use #zerocopy_crate::util::macro_util::core_reexport;
766                    use #zerocopy_crate::pointer::PtrInner;
767
768                    true #(&& {
769                        // SAFETY:
770                        // - `project` is a field projection, and so it
771                        //   addresses a subset of the bytes addressed by `slf`
772                        // - ..., and so it preserves provenance
773                        // - ..., and `*slf` is a struct, so `UnsafeCell`s exist
774                        //   at the same byte ranges in the returned pointer's
775                        //   referent as they do in `*slf`
776                        let field_candidate = unsafe {
777                            let project = |slf: PtrInner<'_, Self>| {
778                                let slf = slf.as_non_null().as_ptr();
779                                let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names);
780                                // SAFETY: `cast_unsized_unchecked` promises
781                                // that `slf` will either reference a zero-sized
782                                // byte range, or else will reference a byte
783                                // range that is entirely contained within an
784                                // allocated object. In either case, this
785                                // guarantees that field projection will not
786                                // wrap around the address space, and so `field`
787                                // will be non-null.
788                                let ptr = unsafe { core_reexport::ptr::NonNull::new_unchecked(field) };
789                                // SAFETY:
790                                // 0. `ptr` addresses a subset of the bytes of
791                                //    `slf`, so by invariant on `slf: PtrInner`,
792                                //    if `ptr`'s referent is not zero sized,
793                                //    then `ptr` has valid provenance for its
794                                //    referent, which is entirely contained in
795                                //    some Rust allocation, `A`.
796                                // 1. By invariant on `slf: PtrInner`, if
797                                //    `ptr`'s referent is not zero sized, `A` is
798                                //    guaranteed to live for at least `'a`.
799                                unsafe { PtrInner::new(ptr) }
800                            };
801
802                            candidate.reborrow().cast_unsized_unchecked(project)
803                        };
804
805                        <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
806                    })*
807                }
808            )
809        });
810    Ok(ImplBlockBuilder::new(
811        ast,
812        strct,
813        Trait::TryFromBytes,
814        FieldBounds::ALL_SELF,
815        zerocopy_crate,
816    )
817    .inner_extras(extras)
818    .build())
819}
820
821/// A union is `TryFromBytes` if:
822/// - all of its fields are `TryFromBytes` and `Immutable`
823fn derive_try_from_bytes_union(
824    ast: &DeriveInput,
825    unn: &DataUnion,
826    top_level: Trait,
827    zerocopy_crate: &Path,
828) -> TokenStream {
829    // FIXME(#5): Remove the `Immutable` bound.
830    let field_type_trait_bounds =
831        FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
832    let extras =
833        try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate).unwrap_or_else(|| {
834            let fields = unn.fields();
835            let field_names = fields.iter().map(|(_vis, name, _ty)| name);
836            let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
837            quote!(
838                // SAFETY: We use `is_bit_valid` to validate that any field is
839                // bit-valid; we only return `true` if at least one of them is.
840                // The bit validity of a union is not yet well defined in Rust,
841                // but it is guaranteed to be no more strict than this
842                // definition. See #696 for a more in-depth discussion.
843                fn is_bit_valid<___ZerocopyAliasing>(
844                    mut candidate: #zerocopy_crate::Maybe<'_, Self,___ZerocopyAliasing>
845                ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
846                where
847                    ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
848                {
849                    use #zerocopy_crate::util::macro_util::core_reexport;
850                    use #zerocopy_crate::pointer::PtrInner;
851
852                    false #(|| {
853                        // SAFETY:
854                        // - `project` is a field projection, and so it
855                        //   addresses a subset of the bytes addressed by `slf`
856                        // - ..., and so it preserves provenance
857                        // - Since `Self: Immutable` is enforced by
858                        //   `self_type_trait_bounds`, neither `*slf` nor the
859                        //   returned pointer's referent contain any
860                        //   `UnsafeCell`s
861                        let field_candidate = unsafe {
862                            let project = |slf: PtrInner<'_, Self>| {
863                                let slf = slf.as_non_null().as_ptr();
864                                let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names);
865                                // SAFETY: `cast_unsized_unchecked` promises
866                                // that `slf` will either reference a zero-sized
867                                // byte range, or else will reference a byte
868                                // range that is entirely contained within an
869                                // allocated object. In either case, this
870                                // guarantees that field projection will not
871                                // wrap around the address space, and so `field`
872                                // will be non-null.
873                                let ptr = unsafe { core_reexport::ptr::NonNull::new_unchecked(field) };
874                                // SAFETY:
875                                // 0. `ptr` addresses a subset of the bytes of
876                                //    `slf`, so by invariant on `slf: PtrInner`,
877                                //    if `ptr`'s referent is not zero sized,
878                                //    then `ptr` has valid provenance for its
879                                //    referent, which is entirely contained in
880                                //    some Rust allocation, `A`.
881                                // 1. By invariant on `slf: PtrInner`, if
882                                //    `ptr`'s referent is not zero sized, `A` is
883                                //    guaranteed to live for at least `'a`.
884                                unsafe { PtrInner::new(ptr) }
885                            };
886
887                            candidate.reborrow().cast_unsized_unchecked(project)
888                        };
889
890                        <#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
891                    })*
892                }
893            )
894        });
895    ImplBlockBuilder::new(ast, unn, Trait::TryFromBytes, field_type_trait_bounds, zerocopy_crate)
896        .inner_extras(extras)
897        .build()
898}
899
900fn derive_try_from_bytes_enum(
901    ast: &DeriveInput,
902    enm: &DataEnum,
903    top_level: Trait,
904    zerocopy_crate: &Path,
905) -> Result<TokenStream, Error> {
906    let repr = EnumRepr::from_attrs(&ast.attrs)?;
907
908    // If an enum has no fields, it has a well-defined integer representation,
909    // and every possible bit pattern corresponds to a valid discriminant tag,
910    // then it *could* be `FromBytes` (even if the user hasn't derived
911    // `FromBytes`). This holds if, for `repr(uN)` or `repr(iN)`, there are 2^N
912    // variants.
913    let could_be_from_bytes = enum_size_from_repr(&repr)
914        .map(|size| enm.fields().is_empty() && enm.variants.len() == 1usize << size)
915        .unwrap_or(false);
916
917    let trivial_is_bit_valid = try_gen_trivial_is_bit_valid(ast, top_level, zerocopy_crate);
918    let extra = match (trivial_is_bit_valid, could_be_from_bytes) {
919        (Some(is_bit_valid), _) => is_bit_valid,
920        // SAFETY: It would be sound for the enum to implement `FromBytes`, as
921        // required by `gen_trivial_is_bit_valid_unchecked`.
922        (None, true) => unsafe { gen_trivial_is_bit_valid_unchecked(zerocopy_crate) },
923        (None, false) => {
924            r#enum::derive_is_bit_valid(&ast.ident, &repr, &ast.generics, enm, zerocopy_crate)?
925        }
926    };
927
928    Ok(ImplBlockBuilder::new(ast, enm, Trait::TryFromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
929        .inner_extras(extra)
930        .build())
931}
932
933/// Attempts to generate a `TryFromBytes::is_bit_valid` instance that
934/// unconditionally returns true.
935///
936/// This is possible when the `top_level` trait is `FromBytes` and there are no
937/// generic type parameters. In this case, we know that compilation will succeed
938/// only if the type is unconditionally `FromBytes`. Type parameters are not
939/// supported because a type with type parameters could be `TryFromBytes` but
940/// not `FromBytes` depending on its type parameters, and so deriving a trivial
941/// `is_bit_valid` would be either unsound or, assuming we add a defensive
942/// `Self: FromBytes` bound (as we currently do), overly restrictive. Consider,
943/// for example, that `Foo<bool>` ought to be `TryFromBytes` but not `FromBytes`
944/// in this example:
945///
946/// ```rust,ignore
947/// #[derive(FromBytes)]
948/// #[repr(transparent)]
949/// struct Foo<T>(T);
950/// ```
951///
952/// This should be used where possible. Using this impl is faster to codegen,
953/// faster to compile, and is friendlier on the optimizer.
954fn try_gen_trivial_is_bit_valid(
955    ast: &DeriveInput,
956    top_level: Trait,
957    zerocopy_crate: &Path,
958) -> Option<proc_macro2::TokenStream> {
959    // If the top-level trait is `FromBytes` and `Self` has no type parameters,
960    // then the `FromBytes` derive will fail compilation if `Self` is not
961    // actually soundly `FromBytes`, and so we can rely on that for our
962    // `is_bit_valid` impl. It's plausible that we could make changes - or Rust
963    // could make changes (such as the "trivial bounds" language feature) - that
964    // make this no longer true. To hedge against these, we include an explicit
965    // `Self: FromBytes` check in the generated `is_bit_valid`, which is
966    // bulletproof.
967    if top_level == Trait::FromBytes && ast.generics.params.is_empty() {
968        Some(quote!(
969            // SAFETY: See inline.
970            fn is_bit_valid<___ZerocopyAliasing>(
971                _candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
972            ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
973            where
974                ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
975            {
976                if false {
977                    fn assert_is_from_bytes<T>()
978                    where
979                        T: #zerocopy_crate::FromBytes,
980                        T: ?#zerocopy_crate::util::macro_util::core_reexport::marker::Sized,
981                    {
982                    }
983
984                    assert_is_from_bytes::<Self>();
985                }
986
987                // SAFETY: The preceding code only compiles if `Self:
988                // FromBytes`. Thus, this code only compiles if all initialized
989                // byte sequences represent valid instances of `Self`.
990                true
991            }
992        ))
993    } else {
994        None
995    }
996}
997
998/// Generates a `TryFromBytes::is_bit_valid` instance that unconditionally
999/// returns true.
1000///
1001/// This should be used where possible, (although `try_gen_trivial_is_bit_valid`
1002/// should be preferred over this for safety reasons). Using this impl is faster
1003/// to codegen, faster to compile, and is friendlier on the optimizer.
1004///
1005/// # Safety
1006///
1007/// The caller must ensure that all initialized bit patterns are valid for
1008/// `Self`.
1009unsafe fn gen_trivial_is_bit_valid_unchecked(zerocopy_crate: &Path) -> proc_macro2::TokenStream {
1010    quote!(
1011        // SAFETY: The caller of `gen_trivial_is_bit_valid_unchecked` has
1012        // promised that all initialized bit patterns are valid for `Self`.
1013        fn is_bit_valid<___ZerocopyAliasing>(
1014            _candidate: #zerocopy_crate::Maybe<Self, ___ZerocopyAliasing>,
1015        ) -> #zerocopy_crate::util::macro_util::core_reexport::primitive::bool
1016        where
1017            ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference,
1018        {
1019            true
1020        }
1021    )
1022}
1023
1024/// A struct is `FromZeros` if:
1025/// - all fields are `FromZeros`
1026fn derive_from_zeros_struct(
1027    ast: &DeriveInput,
1028    strct: &DataStruct,
1029    zerocopy_crate: &Path,
1030) -> TokenStream {
1031    ImplBlockBuilder::new(ast, strct, Trait::FromZeros, FieldBounds::ALL_SELF, zerocopy_crate)
1032        .build()
1033}
1034
1035/// Returns `Ok(index)` if variant `index` of the enum has a discriminant of
1036/// zero. If `Err(bool)` is returned, the boolean is true if the enum has
1037/// unknown discriminants (e.g. discriminants set to const expressions which we
1038/// can't evaluate in a proc macro). If the enum has unknown discriminants, then
1039/// it might have a zero variant that we just can't detect.
1040fn find_zero_variant(enm: &DataEnum) -> Result<usize, bool> {
1041    // Discriminants can be anywhere in the range [i128::MIN, u128::MAX] because
1042    // the discriminant type may be signed or unsigned. Since we only care about
1043    // tracking the discriminant when it's less than or equal to zero, we can
1044    // avoid u128 -> i128 conversions and bounds checking by making the "next
1045    // discriminant" value implicitly negative.
1046    // Technically 64 bits is enough, but 128 is better for future compatibility
1047    // with https://github.com/rust-lang/rust/issues/56071
1048    let mut next_negative_discriminant = Some(0);
1049
1050    // Sometimes we encounter explicit discriminants that we can't know the
1051    // value of (e.g. a constant expression that requires evaluation). These
1052    // could evaluate to zero or a negative number, but we can't assume that
1053    // they do (no false positives allowed!). So we treat them like strictly-
1054    // positive values that can't result in any zero variants, and track whether
1055    // we've encountered any unknown discriminants.
1056    let mut has_unknown_discriminants = false;
1057
1058    for (i, v) in enm.variants.iter().enumerate() {
1059        match v.discriminant.as_ref() {
1060            // Implicit discriminant
1061            None => {
1062                match next_negative_discriminant.as_mut() {
1063                    Some(0) => return Ok(i),
1064                    // n is nonzero so subtraction is always safe
1065                    Some(n) => *n -= 1,
1066                    None => (),
1067                }
1068            }
1069            // Explicit positive discriminant
1070            Some((_, Expr::Lit(ExprLit { lit: Lit::Int(int), .. }))) => {
1071                match int.base10_parse::<u128>().ok() {
1072                    Some(0) => return Ok(i),
1073                    Some(_) => next_negative_discriminant = None,
1074                    None => {
1075                        // Numbers should never fail to parse, but just in case:
1076                        has_unknown_discriminants = true;
1077                        next_negative_discriminant = None;
1078                    }
1079                }
1080            }
1081            // Explicit negative discriminant
1082            Some((_, Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }))) => match &**expr {
1083                Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => {
1084                    match int.base10_parse::<u128>().ok() {
1085                        Some(0) => return Ok(i),
1086                        // x is nonzero so subtraction is always safe
1087                        Some(x) => next_negative_discriminant = Some(x - 1),
1088                        None => {
1089                            // Numbers should never fail to parse, but just in
1090                            // case:
1091                            has_unknown_discriminants = true;
1092                            next_negative_discriminant = None;
1093                        }
1094                    }
1095                }
1096                // Unknown negative discriminant (e.g. const repr)
1097                _ => {
1098                    has_unknown_discriminants = true;
1099                    next_negative_discriminant = None;
1100                }
1101            },
1102            // Unknown discriminant (e.g. const expr)
1103            _ => {
1104                has_unknown_discriminants = true;
1105                next_negative_discriminant = None;
1106            }
1107        }
1108    }
1109
1110    Err(has_unknown_discriminants)
1111}
1112
1113/// An enum is `FromZeros` if:
1114/// - one of the variants has a discriminant of `0`
1115/// - that variant's fields are all `FromZeros`
1116fn derive_from_zeros_enum(
1117    ast: &DeriveInput,
1118    enm: &DataEnum,
1119    zerocopy_crate: &Path,
1120) -> Result<TokenStream, Error> {
1121    let repr = EnumRepr::from_attrs(&ast.attrs)?;
1122
1123    // We don't actually care what the repr is; we just care that it's one of
1124    // the allowed ones.
1125    match repr {
1126         Repr::Compound(
1127            Spanned { t: CompoundRepr::C | CompoundRepr::Primitive(_), span: _ },
1128            _,
1129        ) => {}
1130        Repr::Transparent(_)
1131        | Repr::Compound(Spanned { t: CompoundRepr::Rust, span: _ }, _) => return Err(Error::new(Span::call_site(), "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout")),
1132    }
1133
1134    let zero_variant = match find_zero_variant(enm) {
1135        Ok(index) => enm.variants.iter().nth(index).unwrap(),
1136        // Has unknown variants
1137        Err(true) => {
1138            return Err(Error::new_spanned(
1139                ast,
1140                "FromZeros only supported on enums with a variant that has a discriminant of `0`\n\
1141                help: This enum has discriminants which are not literal integers. One of those may \
1142                define or imply which variant has a discriminant of zero. Use a literal integer to \
1143                define or imply the variant with a discriminant of zero.",
1144            ));
1145        }
1146        // Does not have unknown variants
1147        Err(false) => {
1148            return Err(Error::new_spanned(
1149                ast,
1150                "FromZeros only supported on enums with a variant that has a discriminant of `0`",
1151            ));
1152        }
1153    };
1154
1155    let explicit_bounds = zero_variant
1156        .fields
1157        .iter()
1158        .map(|field| {
1159            let ty = &field.ty;
1160            parse_quote! { #ty: #zerocopy_crate::FromZeros }
1161        })
1162        .collect::<Vec<WherePredicate>>();
1163
1164    Ok(ImplBlockBuilder::new(
1165        ast,
1166        enm,
1167        Trait::FromZeros,
1168        FieldBounds::Explicit(explicit_bounds),
1169        zerocopy_crate,
1170    )
1171    .build())
1172}
1173
1174/// Unions are `FromZeros` if
1175/// - all fields are `FromZeros` and `Immutable`
1176fn derive_from_zeros_union(
1177    ast: &DeriveInput,
1178    unn: &DataUnion,
1179    zerocopy_crate: &Path,
1180) -> TokenStream {
1181    // FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1182    // compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1183    let field_type_trait_bounds =
1184        FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1185    ImplBlockBuilder::new(ast, unn, Trait::FromZeros, field_type_trait_bounds, zerocopy_crate)
1186        .build()
1187}
1188
1189/// A struct is `FromBytes` if:
1190/// - all fields are `FromBytes`
1191fn derive_from_bytes_struct(
1192    ast: &DeriveInput,
1193    strct: &DataStruct,
1194    zerocopy_crate: &Path,
1195) -> TokenStream {
1196    ImplBlockBuilder::new(ast, strct, Trait::FromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1197        .build()
1198}
1199
1200/// An enum is `FromBytes` if:
1201/// - Every possible bit pattern must be valid, which means that every bit
1202///   pattern must correspond to a different enum variant. Thus, for an enum
1203///   whose layout takes up N bytes, there must be 2^N variants.
1204/// - Since we must know N, only representations which guarantee the layout's
1205///   size are allowed. These are `repr(uN)` and `repr(iN)` (`repr(C)` implies
1206///   an implementation-defined size). `usize` and `isize` technically guarantee
1207///   the layout's size, but would require us to know how large those are on the
1208///   target platform. This isn't terribly difficult - we could emit a const
1209///   expression that could call `core::mem::size_of` in order to determine the
1210///   size and check against the number of enum variants, but a) this would be
1211///   platform-specific and, b) even on Rust's smallest bit width platform (32),
1212///   this would require ~4 billion enum variants, which obviously isn't a
1213///   thing.
1214/// - All fields of all variants are `FromBytes`.
1215fn derive_from_bytes_enum(
1216    ast: &DeriveInput,
1217    enm: &DataEnum,
1218    zerocopy_crate: &Path,
1219) -> Result<TokenStream, Error> {
1220    let repr = EnumRepr::from_attrs(&ast.attrs)?;
1221
1222    let variants_required = 1usize << enum_size_from_repr(&repr)?;
1223    if enm.variants.len() != variants_required {
1224        return Err(Error::new_spanned(
1225            ast,
1226            format!(
1227                "FromBytes only supported on {} enum with {} variants",
1228                repr.repr_type_name(),
1229                variants_required
1230            ),
1231        ));
1232    }
1233
1234    Ok(ImplBlockBuilder::new(ast, enm, Trait::FromBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1235        .build())
1236}
1237
1238// Returns `None` if the enum's size is not guaranteed by the repr.
1239fn enum_size_from_repr(repr: &EnumRepr) -> Result<usize, Error> {
1240    use CompoundRepr::*;
1241    use PrimitiveRepr::*;
1242    use Repr::*;
1243    match repr {
1244        Transparent(span)
1245        | Compound(
1246            Spanned { t: C | Rust | Primitive(U32 | I32 | U64 | I64 | U128 | I128 | Usize | Isize), span },
1247            _,
1248        ) => Err(Error::new(*span, "`FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`")),
1249        Compound(Spanned { t: Primitive(U8 | I8), span: _ }, _align) => Ok(8),
1250        Compound(Spanned { t: Primitive(U16 | I16), span: _ }, _align) => Ok(16),
1251    }
1252}
1253
1254/// Unions are `FromBytes` if
1255/// - all fields are `FromBytes` and `Immutable`
1256fn derive_from_bytes_union(
1257    ast: &DeriveInput,
1258    unn: &DataUnion,
1259    zerocopy_crate: &Path,
1260) -> TokenStream {
1261    // FIXME(#5): Remove the `Immutable` bound. It's only necessary for
1262    // compatibility with `derive(TryFromBytes)` on unions; not for soundness.
1263    let field_type_trait_bounds =
1264        FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Immutable)]);
1265    ImplBlockBuilder::new(ast, unn, Trait::FromBytes, field_type_trait_bounds, zerocopy_crate)
1266        .build()
1267}
1268
1269fn derive_into_bytes_struct(
1270    ast: &DeriveInput,
1271    strct: &DataStruct,
1272    zerocopy_crate: &Path,
1273) -> Result<TokenStream, Error> {
1274    let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1275
1276    let is_transparent = repr.is_transparent();
1277    let is_c = repr.is_c();
1278    let is_packed_1 = repr.is_packed_1();
1279    let num_fields = strct.fields().len();
1280
1281    let (padding_check, require_unaligned_fields) = if is_transparent || is_packed_1 {
1282        // No padding check needed.
1283        // - repr(transparent): The layout and ABI of the whole struct is the
1284        //   same as its only non-ZST field (meaning there's no padding outside
1285        //   of that field) and we require that field to be `IntoBytes` (meaning
1286        //   there's no padding in that field).
1287        // - repr(packed): Any inter-field padding bytes are removed, meaning
1288        //   that any padding bytes would need to come from the fields, all of
1289        //   which we require to be `IntoBytes` (meaning they don't have any
1290        //   padding). Note that this holds regardless of other `repr`
1291        //   attributes, including `repr(Rust)`. [1]
1292        //
1293        // [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#the-alignment-modifiers:
1294        //
1295        //   An important consequence of these rules is that a type with
1296        //   `#[repr(packed(1))]`` (or `#[repr(packed)]``) will have no
1297        //   inter-field padding.
1298        (None, false)
1299    } else if is_c && !repr.is_align_gt_1() && num_fields <= 1 {
1300        // No padding check needed. A repr(C) struct with zero or one field has
1301        // no padding unless #[repr(align)] explicitly adds padding, which we
1302        // check for in this branch's condition.
1303        (None, false)
1304    } else if ast.generics.params.is_empty() {
1305        // Is the last field a syntactic slice, i.e., `[SomeType]`.
1306        let is_syntactic_dst =
1307            strct.fields().last().map(|(_, _, ty)| matches!(ty, Type::Slice(_))).unwrap_or(false);
1308        // Since there are no generics, we can emit a padding check. All reprs
1309        // guarantee that fields won't overlap [1], so the padding check is
1310        // sound. This is more permissive than the next case, which requires
1311        // that all field types implement `Unaligned`.
1312        //
1313        // [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#the-rust-representation:
1314        //
1315        //   The only data layout guarantees made by [`repr(Rust)`] are those
1316        //   required for soundness. They are:
1317        //   ...
1318        //   2. The fields do not overlap.
1319        //   ...
1320        if is_c && is_syntactic_dst {
1321            (Some(PaddingCheck::ReprCStruct), false)
1322        } else {
1323            (Some(PaddingCheck::Struct), false)
1324        }
1325    } else if is_c && !repr.is_align_gt_1() {
1326        // We can't use a padding check since there are generic type arguments.
1327        // Instead, we require all field types to implement `Unaligned`. This
1328        // ensures that the `repr(C)` layout algorithm will not insert any
1329        // padding unless #[repr(align)] explicitly adds padding, which we check
1330        // for in this branch's condition.
1331        //
1332        // FIXME(#10): Support type parameters for non-transparent, non-packed
1333        // structs without requiring `Unaligned`.
1334        (None, true)
1335    } else {
1336        return Err(Error::new(Span::call_site(), "must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout"));
1337    };
1338
1339    let field_bounds = if require_unaligned_fields {
1340        FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Unaligned)])
1341    } else {
1342        FieldBounds::ALL_SELF
1343    };
1344
1345    Ok(ImplBlockBuilder::new(ast, strct, Trait::IntoBytes, field_bounds, zerocopy_crate)
1346        .padding_check(padding_check)
1347        .build())
1348}
1349
1350/// If the type is an enum:
1351/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`,
1352///   `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`).
1353/// - It must have no padding bytes.
1354/// - Its fields must be `IntoBytes`.
1355fn derive_into_bytes_enum(
1356    ast: &DeriveInput,
1357    enm: &DataEnum,
1358    zerocopy_crate: &Path,
1359) -> Result<TokenStream, Error> {
1360    let repr = EnumRepr::from_attrs(&ast.attrs)?;
1361    if !repr.is_c() && !repr.is_primitive() {
1362        return Err(Error::new(Span::call_site(), "must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout"));
1363    }
1364
1365    let tag_type_definition = r#enum::generate_tag_enum(&repr, enm);
1366    Ok(ImplBlockBuilder::new(ast, enm, Trait::IntoBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1367        .padding_check(PaddingCheck::Enum { tag_type_definition })
1368        .build())
1369}
1370
1371/// A union is `IntoBytes` if:
1372/// - all fields are `IntoBytes`
1373/// - `repr(C)`, `repr(transparent)`, or `repr(packed)`
1374/// - no padding (size of union equals size of each field type)
1375fn derive_into_bytes_union(
1376    ast: &DeriveInput,
1377    unn: &DataUnion,
1378    zerocopy_crate: &Path,
1379) -> Result<TokenStream, Error> {
1380    // See #1792 for more context.
1381    //
1382    // By checking for `zerocopy_derive_union_into_bytes` both here and in the
1383    // generated code, we ensure that `--cfg zerocopy_derive_union_into_bytes`
1384    // need only be passed *either* when compiling this crate *or* when
1385    // compiling the user's crate. The former is preferable, but in some
1386    // situations (such as when cross-compiling using `cargo build --target`),
1387    // it doesn't get propagated to this crate's build by default.
1388    let cfg_compile_error = if cfg!(zerocopy_derive_union_into_bytes) {
1389        quote!()
1390    } else {
1391        let error_message = "requires --cfg zerocopy_derive_union_into_bytes;
1392please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802";
1393        quote!(
1394            const _: () = {
1395                #[cfg(not(zerocopy_derive_union_into_bytes))]
1396                #zerocopy_crate::util::macro_util::core_reexport::compile_error!(#error_message);
1397            };
1398        )
1399    };
1400
1401    // FIXME(#10): Support type parameters.
1402    if !ast.generics.params.is_empty() {
1403        return Err(Error::new(Span::call_site(), "unsupported on types with type parameters"));
1404    }
1405
1406    // Because we don't support generics, we don't need to worry about
1407    // special-casing different reprs. So long as there is *some* repr which
1408    // guarantees the layout, our `PaddingCheck::Union` guarantees that there is
1409    // no padding.
1410    let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1411    if !repr.is_c() && !repr.is_transparent() && !repr.is_packed_1() {
1412        return Err(Error::new(
1413            Span::call_site(),
1414            "must be #[repr(C)], #[repr(packed)], or #[repr(transparent)]",
1415        ));
1416    }
1417
1418    let impl_block =
1419        ImplBlockBuilder::new(ast, unn, Trait::IntoBytes, FieldBounds::ALL_SELF, zerocopy_crate)
1420            .padding_check(PaddingCheck::Union)
1421            .build();
1422    Ok(quote!(#cfg_compile_error #impl_block))
1423}
1424
1425/// A struct is `Unaligned` if:
1426/// - `repr(align)` is no more than 1 and either
1427///   - `repr(C)` or `repr(transparent)` and
1428///     - all fields `Unaligned`
1429///   - `repr(packed)`
1430fn derive_unaligned_struct(
1431    ast: &DeriveInput,
1432    strct: &DataStruct,
1433    zerocopy_crate: &Path,
1434) -> Result<TokenStream, Error> {
1435    let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1436    repr.unaligned_validate_no_align_gt_1()?;
1437
1438    let field_bounds = if repr.is_packed_1() {
1439        FieldBounds::None
1440    } else if repr.is_c() || repr.is_transparent() {
1441        FieldBounds::ALL_SELF
1442    } else {
1443        return Err(Error::new(Span::call_site(), "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment"));
1444    };
1445
1446    Ok(ImplBlockBuilder::new(ast, strct, Trait::Unaligned, field_bounds, zerocopy_crate).build())
1447}
1448
1449/// An enum is `Unaligned` if:
1450/// - No `repr(align(N > 1))`
1451/// - `repr(u8)` or `repr(i8)`
1452fn derive_unaligned_enum(
1453    ast: &DeriveInput,
1454    enm: &DataEnum,
1455    zerocopy_crate: &Path,
1456) -> Result<TokenStream, Error> {
1457    let repr = EnumRepr::from_attrs(&ast.attrs)?;
1458    repr.unaligned_validate_no_align_gt_1()?;
1459
1460    if !repr.is_u8() && !repr.is_i8() {
1461        return Err(Error::new(Span::call_site(), "must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment"));
1462    }
1463
1464    Ok(ImplBlockBuilder::new(ast, enm, Trait::Unaligned, FieldBounds::ALL_SELF, zerocopy_crate)
1465        .build())
1466}
1467
1468/// Like structs, a union is `Unaligned` if:
1469/// - `repr(align)` is no more than 1 and either
1470///   - `repr(C)` or `repr(transparent)` and
1471///     - all fields `Unaligned`
1472///   - `repr(packed)`
1473fn derive_unaligned_union(
1474    ast: &DeriveInput,
1475    unn: &DataUnion,
1476    zerocopy_crate: &Path,
1477) -> Result<TokenStream, Error> {
1478    let repr = StructUnionRepr::from_attrs(&ast.attrs)?;
1479    repr.unaligned_validate_no_align_gt_1()?;
1480
1481    let field_type_trait_bounds = if repr.is_packed_1() {
1482        FieldBounds::None
1483    } else if repr.is_c() || repr.is_transparent() {
1484        FieldBounds::ALL_SELF
1485    } else {
1486        return Err(Error::new(Span::call_site(), "must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment"));
1487    };
1488
1489    Ok(ImplBlockBuilder::new(ast, unn, Trait::Unaligned, field_type_trait_bounds, zerocopy_crate)
1490        .build())
1491}
1492
1493/// This enum describes what kind of padding check needs to be generated for the
1494/// associated impl.
1495enum PaddingCheck {
1496    /// Check that the sum of the fields' sizes exactly equals the struct's
1497    /// size.
1498    Struct,
1499    /// Check that a `repr(C)` struct has no padding.
1500    ReprCStruct,
1501    /// Check that the size of each field exactly equals the union's size.
1502    Union,
1503    /// Check that every variant of the enum contains no padding.
1504    ///
1505    /// Because doing so requires a tag enum, this padding check requires an
1506    /// additional `TokenStream` which defines the tag enum as `___ZerocopyTag`.
1507    Enum { tag_type_definition: TokenStream },
1508}
1509
1510impl PaddingCheck {
1511    /// Returns the idents of the trait to use and the macro to call in order to
1512    /// validate that a type passes the relevant padding check.
1513    fn validator_trait_and_macro_idents(&self) -> (Ident, Ident) {
1514        let (trt, mcro) = match self {
1515            PaddingCheck::Struct => ("PaddingFree", "struct_padding"),
1516            PaddingCheck::ReprCStruct => ("DynamicPaddingFree", "repr_c_struct_has_padding"),
1517            PaddingCheck::Union => ("PaddingFree", "union_padding"),
1518            PaddingCheck::Enum { .. } => ("PaddingFree", "enum_padding"),
1519        };
1520
1521        let trt = Ident::new(trt, Span::call_site());
1522        let mcro = Ident::new(mcro, Span::call_site());
1523        (trt, mcro)
1524    }
1525
1526    /// Sometimes performing the padding check requires some additional
1527    /// "context" code. For enums, this is the definition of the tag enum.
1528    fn validator_macro_context(&self) -> Option<&TokenStream> {
1529        match self {
1530            PaddingCheck::Struct | PaddingCheck::ReprCStruct | PaddingCheck::Union => None,
1531            PaddingCheck::Enum { tag_type_definition } => Some(tag_type_definition),
1532        }
1533    }
1534}
1535
1536#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1537enum Trait {
1538    KnownLayout,
1539    Immutable,
1540    TryFromBytes,
1541    FromZeros,
1542    FromBytes,
1543    IntoBytes,
1544    Unaligned,
1545    Sized,
1546    ByteHash,
1547    ByteEq,
1548    SplitAt,
1549}
1550
1551impl ToTokens for Trait {
1552    fn to_tokens(&self, tokens: &mut TokenStream) {
1553        // According to [1], the format of the derived `Debug`` output is not
1554        // stable and therefore not guaranteed to represent the variant names.
1555        // Indeed with the (unstable) `fmt-debug` compiler flag [2], it can
1556        // return only a minimalized output or empty string. To make sure this
1557        // code will work in the future and independent of the compiler flag, we
1558        // translate the variants to their names manually here.
1559        //
1560        // [1] https://doc.rust-lang.org/1.81.0/std/fmt/trait.Debug.html#stability
1561        // [2] https://doc.rust-lang.org/beta/unstable-book/compiler-flags/fmt-debug.html
1562        let s = match self {
1563            Trait::KnownLayout => "KnownLayout",
1564            Trait::Immutable => "Immutable",
1565            Trait::TryFromBytes => "TryFromBytes",
1566            Trait::FromZeros => "FromZeros",
1567            Trait::FromBytes => "FromBytes",
1568            Trait::IntoBytes => "IntoBytes",
1569            Trait::Unaligned => "Unaligned",
1570            Trait::Sized => "Sized",
1571            Trait::ByteHash => "ByteHash",
1572            Trait::ByteEq => "ByteEq",
1573            Trait::SplitAt => "SplitAt",
1574        };
1575        let ident = Ident::new(s, Span::call_site());
1576        tokens.extend(core::iter::once(TokenTree::Ident(ident)));
1577    }
1578}
1579
1580impl Trait {
1581    fn crate_path(&self, zerocopy_crate: &Path) -> Path {
1582        match self {
1583            Self::Sized => {
1584                parse_quote!(#zerocopy_crate::util::macro_util::core_reexport::marker::#self)
1585            }
1586            _ => parse_quote!(#zerocopy_crate::#self),
1587        }
1588    }
1589}
1590
1591#[derive(Debug, Eq, PartialEq)]
1592enum TraitBound {
1593    Slf,
1594    Other(Trait),
1595}
1596
1597enum FieldBounds<'a> {
1598    None,
1599    All(&'a [TraitBound]),
1600    Trailing(&'a [TraitBound]),
1601    Explicit(Vec<WherePredicate>),
1602}
1603
1604impl<'a> FieldBounds<'a> {
1605    const ALL_SELF: FieldBounds<'a> = FieldBounds::All(&[TraitBound::Slf]);
1606    const TRAILING_SELF: FieldBounds<'a> = FieldBounds::Trailing(&[TraitBound::Slf]);
1607}
1608
1609#[derive(Debug, Eq, PartialEq)]
1610enum SelfBounds<'a> {
1611    None,
1612    All(&'a [Trait]),
1613}
1614
1615// FIXME(https://github.com/rust-lang/rust-clippy/issues/12908): This is a false
1616// positive. Explicit lifetimes are actually necessary here.
1617#[allow(clippy::needless_lifetimes)]
1618impl<'a> SelfBounds<'a> {
1619    const SIZED: Self = Self::All(&[Trait::Sized]);
1620}
1621
1622/// Normalizes a slice of bounds by replacing [`TraitBound::Slf`] with `slf`.
1623fn normalize_bounds(slf: Trait, bounds: &[TraitBound]) -> impl '_ + Iterator<Item = Trait> {
1624    bounds.iter().map(move |bound| match bound {
1625        TraitBound::Slf => slf,
1626        TraitBound::Other(trt) => *trt,
1627    })
1628}
1629
1630struct ImplBlockBuilder<'a, D: DataExt> {
1631    input: &'a DeriveInput,
1632    data: &'a D,
1633    trt: Trait,
1634    field_type_trait_bounds: FieldBounds<'a>,
1635    zerocopy_crate: &'a Path,
1636    self_type_trait_bounds: SelfBounds<'a>,
1637    padding_check: Option<PaddingCheck>,
1638    inner_extras: Option<TokenStream>,
1639    outer_extras: Option<TokenStream>,
1640}
1641
1642impl<'a, D: DataExt> ImplBlockBuilder<'a, D> {
1643    fn new(
1644        input: &'a DeriveInput,
1645        data: &'a D,
1646        trt: Trait,
1647        field_type_trait_bounds: FieldBounds<'a>,
1648        zerocopy_crate: &'a Path,
1649    ) -> Self {
1650        Self {
1651            input,
1652            data,
1653            trt,
1654            field_type_trait_bounds,
1655            zerocopy_crate,
1656            self_type_trait_bounds: SelfBounds::None,
1657            padding_check: None,
1658            inner_extras: None,
1659            outer_extras: None,
1660        }
1661    }
1662
1663    fn self_type_trait_bounds(mut self, self_type_trait_bounds: SelfBounds<'a>) -> Self {
1664        self.self_type_trait_bounds = self_type_trait_bounds;
1665        self
1666    }
1667
1668    fn padding_check<P: Into<Option<PaddingCheck>>>(mut self, padding_check: P) -> Self {
1669        self.padding_check = padding_check.into();
1670        self
1671    }
1672
1673    fn inner_extras(mut self, inner_extras: TokenStream) -> Self {
1674        self.inner_extras = Some(inner_extras);
1675        self
1676    }
1677
1678    fn outer_extras<T: Into<Option<TokenStream>>>(mut self, outer_extras: T) -> Self {
1679        self.outer_extras = outer_extras.into();
1680        self
1681    }
1682
1683    fn build(self) -> TokenStream {
1684        // In this documentation, we will refer to this hypothetical struct:
1685        //
1686        //   #[derive(FromBytes)]
1687        //   struct Foo<T, I: Iterator>
1688        //   where
1689        //       T: Copy,
1690        //       I: Clone,
1691        //       I::Item: Clone,
1692        //   {
1693        //       a: u8,
1694        //       b: T,
1695        //       c: I::Item,
1696        //   }
1697        //
1698        // We extract the field types, which in this case are `u8`, `T`, and
1699        // `I::Item`. We re-use the existing parameters and where clauses. If
1700        // `require_trait_bound == true` (as it is for `FromBytes), we add where
1701        // bounds for each field's type:
1702        //
1703        //   impl<T, I: Iterator> FromBytes for Foo<T, I>
1704        //   where
1705        //       T: Copy,
1706        //       I: Clone,
1707        //       I::Item: Clone,
1708        //       T: FromBytes,
1709        //       I::Item: FromBytes,
1710        //   {
1711        //   }
1712        //
1713        // NOTE: It is standard practice to only emit bounds for the type
1714        // parameters themselves, not for field types based on those parameters
1715        // (e.g., `T` vs `T::Foo`). For a discussion of why this is standard
1716        // practice, see https://github.com/rust-lang/rust/issues/26925.
1717        //
1718        // The reason we diverge from this standard is that doing it that way
1719        // for us would be unsound. E.g., consider a type, `T` where `T:
1720        // FromBytes` but `T::Foo: !FromBytes`. It would not be sound for us to
1721        // accept a type with a `T::Foo` field as `FromBytes` simply because `T:
1722        // FromBytes`.
1723        //
1724        // While there's no getting around this requirement for us, it does have
1725        // the pretty serious downside that, when lifetimes are involved, the
1726        // trait solver ties itself in knots:
1727        //
1728        //     #[derive(Unaligned)]
1729        //     #[repr(C)]
1730        //     struct Dup<'a, 'b> {
1731        //         a: PhantomData<&'a u8>,
1732        //         b: PhantomData<&'b u8>,
1733        //     }
1734        //
1735        //     error[E0283]: type annotations required: cannot resolve `core::marker::PhantomData<&'a u8>: zerocopy::Unaligned`
1736        //      --> src/main.rs:6:10
1737        //       |
1738        //     6 | #[derive(Unaligned)]
1739        //       |          ^^^^^^^^^
1740        //       |
1741        //       = note: required by `zerocopy::Unaligned`
1742
1743        let type_ident = &self.input.ident;
1744        let trait_path = self.trt.crate_path(self.zerocopy_crate);
1745        let fields = self.data.fields();
1746        let variants = self.data.variants();
1747        let tag = self.data.tag();
1748        let zerocopy_crate = self.zerocopy_crate;
1749
1750        fn bound_tt(
1751            ty: &Type,
1752            traits: impl Iterator<Item = Trait>,
1753            zerocopy_crate: &Path,
1754        ) -> WherePredicate {
1755            let traits = traits.map(|t| t.crate_path(zerocopy_crate));
1756            parse_quote!(#ty: #(#traits)+*)
1757        }
1758        let field_type_bounds: Vec<_> = match (self.field_type_trait_bounds, &fields[..]) {
1759            (FieldBounds::All(traits), _) => fields
1760                .iter()
1761                .map(|(_vis, _name, ty)| {
1762                    bound_tt(ty, normalize_bounds(self.trt, traits), zerocopy_crate)
1763                })
1764                .collect(),
1765            (FieldBounds::None, _) | (FieldBounds::Trailing(..), []) => vec![],
1766            (FieldBounds::Trailing(traits), [.., last]) => {
1767                vec![bound_tt(last.2, normalize_bounds(self.trt, traits), zerocopy_crate)]
1768            }
1769            (FieldBounds::Explicit(bounds), _) => bounds,
1770        };
1771
1772        // Don't bother emitting a padding check if there are no fields.
1773        #[allow(unstable_name_collisions)] // See `BoolExt` below
1774        let padding_check_bound = self
1775            .padding_check
1776            .and_then(|check| (!fields.is_empty()).then_some(check))
1777            .map(|check| {
1778                let variant_types = variants.iter().map(|var| {
1779                    let types = var.iter().map(|(_vis, _name, ty)| ty);
1780                    quote!([#((#types)),*])
1781                });
1782                let validator_context = check.validator_macro_context();
1783                let (trt, validator_macro) = check.validator_trait_and_macro_idents();
1784                let t = tag.iter();
1785                parse_quote! {
1786                    (): #zerocopy_crate::util::macro_util::#trt<
1787                        Self,
1788                        {
1789                            #validator_context
1790                            #zerocopy_crate::#validator_macro!(Self, #(#t,)* #(#variant_types),*)
1791                        }
1792                    >
1793                }
1794            });
1795
1796        let self_bounds: Option<WherePredicate> = match self.self_type_trait_bounds {
1797            SelfBounds::None => None,
1798            SelfBounds::All(traits) => {
1799                Some(bound_tt(&parse_quote!(Self), traits.iter().copied(), zerocopy_crate))
1800            }
1801        };
1802
1803        let bounds = self
1804            .input
1805            .generics
1806            .where_clause
1807            .as_ref()
1808            .map(|where_clause| where_clause.predicates.iter())
1809            .into_iter()
1810            .flatten()
1811            .chain(field_type_bounds.iter())
1812            .chain(padding_check_bound.iter())
1813            .chain(self_bounds.iter());
1814
1815        // The parameters with trait bounds, but without type defaults.
1816        let params = self.input.generics.params.clone().into_iter().map(|mut param| {
1817            match &mut param {
1818                GenericParam::Type(ty) => ty.default = None,
1819                GenericParam::Const(cnst) => cnst.default = None,
1820                GenericParam::Lifetime(_) => {}
1821            }
1822            quote!(#param)
1823        });
1824
1825        // The identifiers of the parameters without trait bounds or type
1826        // defaults.
1827        let param_idents = self.input.generics.params.iter().map(|param| match param {
1828            GenericParam::Type(ty) => {
1829                let ident = &ty.ident;
1830                quote!(#ident)
1831            }
1832            GenericParam::Lifetime(l) => {
1833                let ident = &l.lifetime;
1834                quote!(#ident)
1835            }
1836            GenericParam::Const(cnst) => {
1837                let ident = &cnst.ident;
1838                quote!({#ident})
1839            }
1840        });
1841
1842        let inner_extras = self.inner_extras;
1843        let impl_tokens = quote! {
1844            #[allow(deprecated)]
1845            // While there are not currently any warnings that this suppresses
1846            // (that we're aware of), it's good future-proofing hygiene.
1847            #[automatically_derived]
1848            unsafe impl < #(#params),* > #trait_path for #type_ident < #(#param_idents),* >
1849            where
1850                #(#bounds,)*
1851            {
1852                fn only_derive_is_allowed_to_implement_this_trait() {}
1853
1854                #inner_extras
1855            }
1856        };
1857
1858        if let Some(outer_extras) = self.outer_extras {
1859            // So that any items defined in `#outer_extras` don't conflict with
1860            // existing names defined in this scope.
1861            quote! {
1862                const _: () = {
1863                    #impl_tokens
1864
1865                    #outer_extras
1866                };
1867            }
1868        } else {
1869            impl_tokens
1870        }
1871    }
1872}
1873
1874// A polyfill for `Option::then_some`, which was added after our MSRV.
1875//
1876// The `#[allow(unused)]` is necessary because, on sufficiently recent toolchain
1877// versions, `b.then_some(...)` resolves to the inherent method rather than to
1878// this trait, and so this trait is considered unused.
1879//
1880// FIXME(#67): Remove this once our MSRV is >= 1.62.
1881#[allow(unused)]
1882trait BoolExt {
1883    fn then_some<T>(self, t: T) -> Option<T>;
1884}
1885
1886impl BoolExt for bool {
1887    fn then_some<T>(self, t: T) -> Option<T> {
1888        if self {
1889            Some(t)
1890        } else {
1891            None
1892        }
1893    }
1894}