• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 mod r#enum;
32 mod ext;
33 #[cfg(test)]
34 mod output_tests;
35 mod repr;
36 
37 use proc_macro2::{TokenStream, TokenTree};
38 use quote::ToTokens;
39 
40 use {
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 
49 use {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.
74 macro_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 
84 trait IntoTokenStream {
into_ts(self) -> TokenStream85     fn into_ts(self) -> TokenStream;
86 }
87 
88 impl IntoTokenStream for TokenStream {
into_ts(self) -> TokenStream89     fn into_ts(self) -> TokenStream {
90         self
91     }
92 }
93 
94 impl IntoTokenStream for Result<TokenStream, Error> {
into_ts(self) -> TokenStream95     fn into_ts(self) -> TokenStream {
96         match self {
97             Ok(ts) => ts,
98             Err(err) => err.to_compile_error(),
99         }
100     }
101 }
102 
103 derive!(KnownLayout => derive_known_layout => derive_known_layout_inner);
104 derive!(Immutable => derive_no_cell => derive_no_cell_inner);
105 derive!(TryFromBytes => derive_try_from_bytes => derive_try_from_bytes_inner);
106 derive!(FromZeros => derive_from_zeros => derive_from_zeros_inner);
107 derive!(FromBytes => derive_from_bytes => derive_from_bytes_inner);
108 derive!(IntoBytes => derive_into_bytes => derive_into_bytes_inner);
109 derive!(Unaligned => derive_unaligned => derive_unaligned_inner);
110 derive!(ByteHash => derive_hash => derive_hash_inner);
111 derive!(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)]
derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream117 pub 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)]
derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream125 pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
126     derive_into_bytes(ts)
127 }
128 
derive_known_layout_inner(ast: &DeriveInput, _top_level: Trait) -> Result<TokenStream, Error>129 fn 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 
derive_no_cell_inner(ast: &DeriveInput, _top_level: Trait) -> TokenStream465 fn 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 
derive_try_from_bytes_inner(ast: &DeriveInput, top_level: Trait) -> Result<TokenStream, Error>500 fn 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 
derive_from_zeros_inner(ast: &DeriveInput, top_level: Trait) -> Result<TokenStream, Error>508 fn 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 
derive_from_bytes_inner(ast: &DeriveInput, top_level: Trait) -> Result<TokenStream, Error>518 fn 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 
derive_into_bytes_inner(ast: &DeriveInput, _top_level: Trait) -> Result<TokenStream, Error>529 fn 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 
derive_unaligned_inner(ast: &DeriveInput, _top_level: Trait) -> Result<TokenStream, Error>537 fn 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 
derive_hash_inner(ast: &DeriveInput, _top_level: Trait) -> Result<TokenStream, Error>545 fn 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 
derive_eq_inner(ast: &DeriveInput, _top_level: Trait) -> Result<TokenStream, Error>589 fn 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`
derive_try_from_bytes_struct( ast: &DeriveInput, strct: &DataStruct, top_level: Trait, ) -> Result<TokenStream, Error>635 fn 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().cast_unsized_unchecked(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`
derive_try_from_bytes_union( ast: &DeriveInput, unn: &DataUnion, top_level: Trait, ) -> TokenStream690 fn 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().cast_unsized_unchecked(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 
derive_try_from_bytes_enum( ast: &DeriveInput, enm: &DataEnum, top_level: Trait, ) -> Result<TokenStream, Error>746 fn 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.
try_gen_trivial_is_bit_valid( ast: &DeriveInput, top_level: Trait, ) -> Option<proc_macro2::TokenStream>804 fn 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`.
gen_trivial_is_bit_valid_unchecked() -> proc_macro2::TokenStream858 unsafe 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`
derive_from_zeros_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream875 fn 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.
find_zero_variant(enm: &DataEnum) -> Result<usize, bool>893 fn 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`
derive_from_zeros_enum(ast: &DeriveInput, enm: &DataEnum) -> Result<TokenStream, Error>969 fn 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`
derive_from_zeros_union(ast: &DeriveInput, unn: &DataUnion) -> TokenStream1027 fn 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`
derive_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> TokenStream1046 fn 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`.
derive_from_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> Result<TokenStream, Error>1073 fn 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.
enum_size_from_repr(repr: &EnumRepr) -> Result<usize, Error>1101 fn 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`
derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> TokenStream1116 fn 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 
derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> Result<TokenStream, Error>1133 fn 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`.
derive_into_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> Result<TokenStream, Error>1215 fn 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)
derive_into_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> Result<TokenStream, Error>1238 fn 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;
1255 please 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)`
derive_unaligned_struct(ast: &DeriveInput, strct: &DataStruct) -> Result<TokenStream, Error>1296 fn 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)`
derive_unaligned_enum(ast: &DeriveInput, enm: &DataEnum) -> Result<TokenStream, Error>1314 fn 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)`
derive_unaligned_union(ast: &DeriveInput, unn: &DataUnion) -> Result<TokenStream, Error>1339 fn 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.
1365 enum 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 
1378 impl 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`.
validator_macro_ident(&self) -> Ident1381     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.
validator_macro_context(&self) -> Option<&TokenStream>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)]
1402 enum Trait {
1403     KnownLayout,
1404     Immutable,
1405     TryFromBytes,
1406     FromZeros,
1407     FromBytes,
1408     IntoBytes,
1409     Unaligned,
1410     Sized,
1411     ByteHash,
1412     ByteEq,
1413 }
1414 
1415 impl ToTokens for Trait {
to_tokens(&self, tokens: &mut TokenStream)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 
1443 impl Trait {
crate_path(&self) -> Path1444     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)]
1453 enum TraitBound {
1454     Slf,
1455     Other(Trait),
1456 }
1457 
1458 enum FieldBounds<'a> {
1459     None,
1460     All(&'a [TraitBound]),
1461     Trailing(&'a [TraitBound]),
1462     Explicit(Vec<WherePredicate>),
1463 }
1464 
1465 impl<'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)]
1471 enum 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)]
1479 impl<'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`.
normalize_bounds(slf: Trait, bounds: &[TraitBound]) -> impl '_ + Iterator<Item = Trait>1484 fn 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)]
impl_block<D: DataExt>( input: &DeriveInput, data: &D, trt: Trait, field_type_trait_bounds: FieldBounds, self_type_trait_bounds: SelfBounds, padding_check: Option<PaddingCheck>, inner_extras: Option<TokenStream>, outer_extras: Option<TokenStream>, ) -> TokenStream1492 fn 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)]
1688 trait BoolExt {
then_some<T>(self, t: T) -> Option<T>1689     fn then_some<T>(self, t: T) -> Option<T>;
1690 }
1691 
1692 impl BoolExt for bool {
then_some<T>(self, t: T) -> Option<T>1693     fn then_some<T>(self, t: T) -> Option<T> {
1694         if self {
1695             Some(t)
1696         } else {
1697             None
1698         }
1699     }
1700 }
1701