about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-11-19 23:25:25 +0000
committerMichael Goulet <michael@errs.io>2023-11-21 05:49:45 +0000
commitc9143ea1d9bad9871e77476f523da9d013357158 (patch)
tree2944c6d5ebf1b5e4e1d4c6f870add7710f12ee7b
parent426bc70ad661e6edd66949f3d938c0c07571dbc5 (diff)
downloadrust-c9143ea1d9bad9871e77476f523da9d013357158.tar.gz
rust-c9143ea1d9bad9871e77476f523da9d013357158.zip
Unify HashStable implementations
-rw-r--r--compiler/rustc_macros/src/hash_stable.rs113
1 files changed, 49 insertions, 64 deletions
diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs
index 564e3a1edfa..2893937fc4a 100644
--- a/compiler/rustc_macros/src/hash_stable.rs
+++ b/compiler/rustc_macros/src/hash_stable.rs
@@ -38,95 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
     attrs
 }
 
+pub(crate) fn hash_stable_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    hash_stable_derive_with_mode(s, HashStableMode::Normal)
+}
+
 pub(crate) fn hash_stable_generic_derive(
-    mut s: synstructure::Structure<'_>,
+    s: synstructure::Structure<'_>,
 ) -> proc_macro2::TokenStream {
-    let generic: syn::GenericParam = parse_quote!(__CTX);
-    s.add_bounds(synstructure::AddBounds::Generics);
-    s.add_impl_generic(generic);
-    s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
+    hash_stable_derive_with_mode(s, HashStableMode::Generic)
+}
 
-    let discriminant = hash_stable_discriminant(&mut s);
-    let body = hash_stable_body(&mut s);
+pub(crate) fn hash_stable_no_context_derive(
+    s: synstructure::Structure<'_>,
+) -> proc_macro2::TokenStream {
+    hash_stable_derive_with_mode(s, HashStableMode::NoContext)
+}
 
-    s.bound_impl(
-        quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
-        quote! {
-            #[inline]
-            fn hash_stable(
-                &self,
-                __hcx: &mut __CTX,
-                __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
-                #discriminant
-                match *self { #body }
-            }
-        },
-    )
+enum HashStableMode {
+    // Use the query-system aware stable hashing context.
+    Normal,
+    // Emit a generic implementation that uses a crate-local `StableHashingContext`
+    // trait, when the crate is upstream of `rustc_middle`.
+    Generic,
+    // Emit a hash-stable implementation that takes no context,
+    // and emits per-field where clauses for (almost-)perfect derives.
+    NoContext,
 }
 
-pub(crate) fn hash_stable_no_context_derive(
+fn hash_stable_derive_with_mode(
     mut s: synstructure::Structure<'_>,
+    mode: HashStableMode,
 ) -> proc_macro2::TokenStream {
-    let generic: syn::GenericParam = parse_quote!(__CTX);
-    s.add_bounds(synstructure::AddBounds::Fields);
-    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"),
+    let generic: syn::GenericParam = match mode {
+        HashStableMode::Normal => parse_quote!('__ctx),
+        HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
     };
 
-    s.bound_impl(
-        quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
-        quote! {
-            #[inline]
-            fn hash_stable(
-                &self,
-                __hcx: &mut __CTX,
-                __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
-                #discriminant
-                match *self { #body }
-            }
-        },
-    )
-}
+    // no_context impl is able to derive by-field, which is closer to a perfect derive.
+    s.add_bounds(match mode {
+        HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics,
+        HashStableMode::NoContext => synstructure::AddBounds::Fields,
+    });
+
+    // For generic impl, add `where __CTX: HashStableContext`.
+    match mode {
+        HashStableMode::Normal => {}
+        HashStableMode::Generic => {
+            s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
+        }
+        HashStableMode::NoContext => {}
+    }
 
-pub(crate) fn hash_stable_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 discriminant = hash_stable_discriminant(&mut s);
     let body = hash_stable_body(&mut s);
 
+    let context: syn::Type = match mode {
+        HashStableMode::Normal => {
+            parse_quote!(::rustc_query_system::ich::StableHashingContext<'__ctx>)
+        }
+        HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
+    };
+
     s.bound_impl(
         quote!(
             ::rustc_data_structures::stable_hasher::HashStable<
-                ::rustc_query_system::ich::StableHashingContext<'__ctx>,
+                #context
             >
         ),
         quote! {
             #[inline]
             fn hash_stable(
                 &self,
-                __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
+                __hcx: &mut #context,
                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                 #discriminant
                 match *self { #body }