]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_macros/src/hash_stable.rs
Auto merge of #81635 - michaelwoerister:structured_def_path_hash, r=pnkfelix
[rust.git] / compiler / rustc_macros / src / hash_stable.rs
1 use proc_macro2::{self, Ident};
2 use quote::quote;
3 use syn::{self, parse_quote, Meta, NestedMeta};
4
5 struct Attributes {
6     ignore: bool,
7     project: Option<Ident>,
8 }
9
10 fn parse_attributes(field: &syn::Field) -> Attributes {
11     let mut attrs = Attributes { ignore: false, project: None };
12     for attr in &field.attrs {
13         if let Ok(meta) = attr.parse_meta() {
14             if !meta.path().is_ident("stable_hasher") {
15                 continue;
16             }
17             let mut any_attr = false;
18             if let Meta::List(list) = meta {
19                 for nested in list.nested.iter() {
20                     if let NestedMeta::Meta(meta) = nested {
21                         if meta.path().is_ident("ignore") {
22                             attrs.ignore = true;
23                             any_attr = true;
24                         }
25                         if meta.path().is_ident("project") {
26                             if let Meta::List(list) = meta {
27                                 if let Some(nested) = list.nested.iter().next() {
28                                     if let NestedMeta::Meta(meta) = nested {
29                                         attrs.project = meta.path().get_ident().cloned();
30                                         any_attr = true;
31                                     }
32                                 }
33                             }
34                         }
35                     }
36                 }
37             }
38             if !any_attr {
39                 panic!("error parsing stable_hasher");
40             }
41         }
42     }
43     attrs
44 }
45
46 pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
47     let generic: syn::GenericParam = parse_quote!(__CTX);
48     s.add_bounds(synstructure::AddBounds::Generics);
49     s.add_impl_generic(generic);
50     s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
51     let body = s.each(|bi| {
52         let attrs = parse_attributes(bi.ast());
53         if attrs.ignore {
54             quote! {}
55         } else if let Some(project) = attrs.project {
56             quote! {
57                 &#bi.#project.hash_stable(__hcx, __hasher);
58             }
59         } else {
60             quote! {
61                 #bi.hash_stable(__hcx, __hasher);
62             }
63         }
64     });
65
66     let discriminant = match s.ast().data {
67         syn::Data::Enum(_) => quote! {
68             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
69         },
70         syn::Data::Struct(_) => quote! {},
71         syn::Data::Union(_) => panic!("cannot derive on union"),
72     };
73
74     s.bound_impl(
75         quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
76         quote! {
77             fn hash_stable(
78                 &self,
79                 __hcx: &mut __CTX,
80                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
81                 #discriminant
82                 match *self { #body }
83             }
84         },
85     )
86 }
87
88 pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
89     let generic: syn::GenericParam = parse_quote!('__ctx);
90     s.add_bounds(synstructure::AddBounds::Generics);
91     s.add_impl_generic(generic);
92     let body = s.each(|bi| {
93         let attrs = parse_attributes(bi.ast());
94         if attrs.ignore {
95             quote! {}
96         } else if let Some(project) = attrs.project {
97             quote! {
98                 &#bi.#project.hash_stable(__hcx, __hasher);
99             }
100         } else {
101             quote! {
102                 #bi.hash_stable(__hcx, __hasher);
103             }
104         }
105     });
106
107     let discriminant = match s.ast().data {
108         syn::Data::Enum(_) => quote! {
109             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
110         },
111         syn::Data::Struct(_) => quote! {},
112         syn::Data::Union(_) => panic!("cannot derive on union"),
113     };
114
115     s.bound_impl(
116         quote!(
117             ::rustc_data_structures::stable_hasher::HashStable<
118                 ::rustc_middle::ich::StableHashingContext<'__ctx>,
119             >
120         ),
121         quote! {
122             fn hash_stable(
123                 &self,
124                 __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
125                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
126                 #discriminant
127                 match *self { #body }
128             }
129         },
130     )
131 }