Skip to main content

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