zerocopy_derive/
lib.rs

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