78 lines · 2.7 KB · Rust
RawDownload
// 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<TokenStream, ErrorGuaranteed> {    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<T: ?::core::marker::Sized + ::pin_init::Zeroable>() {}            fn ensure_zeroable #impl_gen ()                #whr            {                #(                    assert_zeroable::<#field_type>();                )*            }        };    })} pub(crate) fn maybe_derive(    input: DeriveInput,    dcx: &mut DiagCtxt,) -> Result<TokenStream, ErrorGuaranteed> {    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 <https://github.com/rust-lang/rust/issues/48214#issuecomment-2557829956>.            .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        {}    })}