]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_macros/src/hash_stable.rs
Merge commit '4f142aa1058f14f153f8bfd2d82f04ddb9982388' into clippyup
[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(NestedMeta::Meta(meta)) = list.nested.iter().next() {
28                                     attrs.project = meta.path().get_ident().cloned();
29                                     any_attr = true;
30                                 }
31                             }
32                         }
33                     }
34                 }
35             }
36             if !any_attr {
37                 panic!("error parsing stable_hasher");
38             }
39         }
40     }
41     attrs
42 }
43
44 pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
45     let generic: syn::GenericParam = parse_quote!(__CTX);
46     s.add_bounds(synstructure::AddBounds::Generics);
47     s.add_impl_generic(generic);
48     s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
49     let body = s.each(|bi| {
50         let attrs = parse_attributes(bi.ast());
51         if attrs.ignore {
52             quote! {}
53         } else if let Some(project) = attrs.project {
54             quote! {
55                 (&#bi.#project).hash_stable(__hcx, __hasher);
56             }
57         } else {
58             quote! {
59                 #bi.hash_stable(__hcx, __hasher);
60             }
61         }
62     });
63
64     let discriminant = match s.ast().data {
65         syn::Data::Enum(_) => quote! {
66             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
67         },
68         syn::Data::Struct(_) => quote! {},
69         syn::Data::Union(_) => panic!("cannot derive on union"),
70     };
71
72     s.bound_impl(
73         quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
74         quote! {
75             #[inline]
76             fn hash_stable(
77                 &self,
78                 __hcx: &mut __CTX,
79                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
80                 #discriminant
81                 match *self { #body }
82             }
83         },
84     )
85 }
86
87 pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
88     let generic: syn::GenericParam = parse_quote!('__ctx);
89     s.add_bounds(synstructure::AddBounds::Generics);
90     s.add_impl_generic(generic);
91     let body = s.each(|bi| {
92         let attrs = parse_attributes(bi.ast());
93         if attrs.ignore {
94             quote! {}
95         } else if let Some(project) = attrs.project {
96             quote! {
97                 (&#bi.#project).hash_stable(__hcx, __hasher);
98             }
99         } else {
100             quote! {
101                 #bi.hash_stable(__hcx, __hasher);
102             }
103         }
104     });
105
106     let discriminant = match s.ast().data {
107         syn::Data::Enum(_) => quote! {
108             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
109         },
110         syn::Data::Struct(_) => quote! {},
111         syn::Data::Union(_) => panic!("cannot derive on union"),
112     };
113
114     s.bound_impl(
115         quote!(
116             ::rustc_data_structures::stable_hasher::HashStable<
117                 ::rustc_query_system::ich::StableHashingContext<'__ctx>,
118             >
119         ),
120         quote! {
121             #[inline]
122             fn hash_stable(
123                 &self,
124                 __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
125                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
126                 #discriminant
127                 match *self { #body }
128             }
129         },
130     )
131 }