// SPDX-License-Identifier: GPL-2.0 use proc_macro2::TokenStream; use quote::quote; use syn::{parse_quote, Data, DeriveInput, Field, Fields}; use crate::{diagnostics::ErrorGuaranteed, DiagCtxt}; pub(crate) fn derive( input: DeriveInput, dcx: &mut DiagCtxt, ) -> Result { let fields = match input.data { Data::Struct(data_struct) => data_struct.fields, Data::Union(data_union) => Fields::Named(data_union.fields), Data::Enum(data_enum) => { return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum")); } }; let name = input.ident; let mut generics = input.generics; for param in generics.type_params_mut() { param.bounds.insert(0, parse_quote!(::pin_init::Zeroable)); } let (impl_gen, ty_gen, whr) = generics.split_for_impl(); let field_type = fields.iter().map(|field| &field.ty); Ok(quote! { // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. #[automatically_derived] unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen #whr {} const _: () = { fn assert_zeroable() {} fn ensure_zeroable #impl_gen () #whr { #( assert_zeroable::<#field_type>(); )* } }; }) } pub(crate) fn maybe_derive( input: DeriveInput, dcx: &mut DiagCtxt, ) -> Result { let fields = match input.data { Data::Struct(data_struct) => data_struct.fields, Data::Union(data_union) => Fields::Named(data_union.fields), Data::Enum(data_enum) => { return Err(dcx.error(data_enum.enum_token, "cannot derive `Zeroable` for an enum")); } }; let name = input.ident; let mut generics = input.generics; for param in generics.type_params_mut() { param.bounds.insert(0, parse_quote!(::pin_init::Zeroable)); } for Field { ty, .. } in fields { generics .make_where_clause() .predicates // the `for<'__dummy>` HRTB makes this not error without the `trivial_bounds` // feature . .push(parse_quote!(#ty: for<'__dummy> ::pin_init::Zeroable)); } let (impl_gen, ty_gen, whr) = generics.split_for_impl(); Ok(quote! { // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. #[automatically_derived] unsafe impl #impl_gen ::pin_init::Zeroable for #name #ty_gen #whr {} }) }