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