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