zerocopy_derive/
lib.rs

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