@@ -38,95 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
3838 attrs
3939}
4040
41+ pub ( crate ) fn hash_stable_derive ( s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
42+ hash_stable_derive_with_mode ( s, HashStableMode :: Normal )
43+ }
44+
4145pub ( crate ) fn hash_stable_generic_derive (
42- mut s : synstructure:: Structure < ' _ > ,
46+ s : synstructure:: Structure < ' _ > ,
4347) -> proc_macro2:: TokenStream {
44- let generic: syn:: GenericParam = parse_quote ! ( __CTX) ;
45- s. add_bounds ( synstructure:: AddBounds :: Generics ) ;
46- s. add_impl_generic ( generic) ;
47- s. add_where_predicate ( parse_quote ! { __CTX: crate :: HashStableContext } ) ;
48+ hash_stable_derive_with_mode ( s, HashStableMode :: Generic )
49+ }
4850
49- let discriminant = hash_stable_discriminant ( & mut s) ;
50- let body = hash_stable_body ( & mut s) ;
51+ pub ( crate ) fn hash_stable_no_context_derive (
52+ s : synstructure:: Structure < ' _ > ,
53+ ) -> proc_macro2:: TokenStream {
54+ hash_stable_derive_with_mode ( s, HashStableMode :: NoContext )
55+ }
5156
52- s. bound_impl (
53- quote ! ( :: rustc_data_structures:: stable_hasher:: HashStable <__CTX>) ,
54- quote ! {
55- #[ inline]
56- fn hash_stable(
57- & self ,
58- __hcx: & mut __CTX,
59- __hasher: & mut :: rustc_data_structures:: stable_hasher:: StableHasher ) {
60- #discriminant
61- match * self { #body }
62- }
63- } ,
64- )
57+ enum HashStableMode {
58+ // Use the query-system aware stable hashing context.
59+ Normal ,
60+ // Emit a generic implementation that uses a crate-local `StableHashingContext`
61+ // trait, when the crate is upstream of `rustc_middle`.
62+ Generic ,
63+ // Emit a hash-stable implementation that takes no context,
64+ // and emits per-field where clauses for (almost-)perfect derives.
65+ NoContext ,
6566}
6667
67- pub ( crate ) fn hash_stable_no_context_derive (
68+ fn hash_stable_derive_with_mode (
6869 mut s : synstructure:: Structure < ' _ > ,
70+ mode : HashStableMode ,
6971) -> proc_macro2:: TokenStream {
70- let generic: syn:: GenericParam = parse_quote ! ( __CTX) ;
71- s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
72- s. add_impl_generic ( generic) ;
73- let body = s. each ( |bi| {
74- let attrs = parse_attributes ( bi. ast ( ) ) ;
75- if attrs. ignore {
76- quote ! { }
77- } else if let Some ( project) = attrs. project {
78- quote ! {
79- ( & #bi. #project) . hash_stable( __hcx, __hasher) ;
80- }
81- } else {
82- quote ! {
83- #bi. hash_stable( __hcx, __hasher) ;
84- }
85- }
86- } ) ;
87-
88- let discriminant = match s. ast ( ) . data {
89- syn:: Data :: Enum ( _) => quote ! {
90- :: std:: mem:: discriminant( self ) . hash_stable( __hcx, __hasher) ;
91- } ,
92- syn:: Data :: Struct ( _) => quote ! { } ,
93- syn:: Data :: Union ( _) => panic ! ( "cannot derive on union" ) ,
72+ let generic: syn:: GenericParam = match mode {
73+ HashStableMode :: Normal => parse_quote ! ( ' __ctx) ,
74+ HashStableMode :: Generic | HashStableMode :: NoContext => parse_quote ! ( __CTX) ,
9475 } ;
9576
96- s . bound_impl (
97- quote ! ( :: rustc_data_structures :: stable_hasher :: HashStable <__CTX> ) ,
98- quote ! {
99- # [ inline ]
100- fn hash_stable (
101- & self ,
102- __hcx : & mut __CTX ,
103- __hasher : & mut :: rustc_data_structures :: stable_hasher :: StableHasher ) {
104- #discriminant
105- match * self { #body }
106- }
107- } ,
108- )
109- }
77+ // no_context impl is able to derive by-field, which is closer to a perfect derive.
78+ s . add_bounds ( match mode {
79+ HashStableMode :: Normal | HashStableMode :: Generic => synstructure :: AddBounds :: Generics ,
80+ HashStableMode :: NoContext => synstructure :: AddBounds :: Fields ,
81+ } ) ;
82+
83+ // For generic impl, add `where __CTX: HashStableContext`.
84+ match mode {
85+ HashStableMode :: Normal => { }
86+ HashStableMode :: Generic => {
87+ s . add_where_predicate ( parse_quote ! { __CTX : crate :: HashStableContext } ) ;
88+ }
89+ HashStableMode :: NoContext => { }
90+ }
11091
111- pub ( crate ) fn hash_stable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
112- let generic: syn:: GenericParam = parse_quote ! ( ' __ctx) ;
113- s. add_bounds ( synstructure:: AddBounds :: Generics ) ;
11492 s. add_impl_generic ( generic) ;
11593
11694 let discriminant = hash_stable_discriminant ( & mut s) ;
11795 let body = hash_stable_body ( & mut s) ;
11896
97+ let context: syn:: Type = match mode {
98+ HashStableMode :: Normal => {
99+ parse_quote ! ( :: rustc_query_system:: ich:: StableHashingContext <' __ctx>)
100+ }
101+ HashStableMode :: Generic | HashStableMode :: NoContext => parse_quote ! ( __CTX) ,
102+ } ;
103+
119104 s. bound_impl (
120105 quote ! (
121106 :: rustc_data_structures:: stable_hasher:: HashStable <
122- :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
107+ #context
123108 >
124109 ) ,
125110 quote ! {
126111 #[ inline]
127112 fn hash_stable(
128113 & self ,
129- __hcx: & mut :: rustc_query_system :: ich :: StableHashingContext < ' __ctx> ,
114+ __hcx: & mut #context ,
130115 __hasher: & mut :: rustc_data_structures:: stable_hasher:: StableHasher ) {
131116 #discriminant
132117 match * self { #body }
0 commit comments