diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs index 735cfb11b36..3fb252cbf8d 100644 --- a/src/librustc_macros/src/hash_stable.rs +++ b/src/librustc_macros/src/hash_stable.rs @@ -47,6 +47,44 @@ fn parse_attributes(field: &syn::Field) -> Attributes { attrs } +pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let generic: syn::GenericParam = parse_quote!(__CTX); + s.add_bounds(synstructure::AddBounds::Generics); + s.add_impl_generic(generic); + let body = s.each(|bi| { + let attrs = parse_attributes(bi.ast()); + if attrs.ignore { + quote!{} + } else if let Some(project) = attrs.project { + quote!{ + &#bi.#project.hash_stable(__hcx, __hasher); + } + } else { + quote!{ + #bi.hash_stable(__hcx, __hasher); + } + } + }); + + let discriminant = match s.ast().data { + syn::Data::Enum(_) => quote! { + ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); + }, + syn::Data::Struct(_) => quote! {}, + syn::Data::Union(_) => panic!("cannot derive on union"), + }; + + s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>), quote!{ + fn hash_stable( + &self, + __hcx: &mut __CTX, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + #discriminant + match *self { #body } + } + }) +} + pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let generic: syn::GenericParam = parse_quote!('__ctx); s.add_bounds(synstructure::AddBounds::Generics); diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs index 351d60b9368..af022115ed0 100644 --- a/src/librustc_macros/src/lib.rs +++ b/src/librustc_macros/src/lib.rs @@ -24,4 +24,9 @@ pub fn symbols(input: TokenStream) -> TokenStream { } decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); +decl_derive!( + [HashStable_Generic, attributes(stable_hasher)] => + hash_stable::hash_stable_generic_derive +); + decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive);