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