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