diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index d0c86527189..00f3951d9a0 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -5,8 +5,8 @@ use crate::diagnostics::error::{ SessionDiagnosticDeriveError, }; use crate::diagnostics::utils::{ - report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path, - Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, + build_field_mapping, report_error_if_not_applied_to_span, report_type_error, type_is_unit, + type_matches_path, Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, }; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; @@ -25,26 +25,11 @@ pub(crate) struct SessionDiagnosticDerive<'a> { impl<'a> SessionDiagnosticDerive<'a> { pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self { - // Build the mapping of field names to fields. This allows attributes to peek values from - // other fields. - let mut fields_map = HashMap::new(); - - // Convenience bindings. - let ast = structure.ast(); - - if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { - for field in fields.iter() { - if let Some(ident) = &field.ident { - fields_map.insert(ident.to_string(), quote! { &self.#ident }); - } - } - } - Self { builder: SessionDiagnosticDeriveBuilder { diag, sess, - fields: fields_map, + fields: build_field_mapping(&structure), kind: None, code: None, slug: None, diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 636bcf1f7b1..24204556c98 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -2,10 +2,10 @@ use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriv use proc_macro::Span; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashMap}; use std::str::FromStr; use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple}; -use synstructure::BindingInfo; +use synstructure::{BindingInfo, Structure}; /// Checks whether the type name of `ty` matches `name`. /// @@ -325,3 +325,20 @@ impl quote::ToTokens for Applicability { }); } } + +/// Build the mapping of field names to fields. This allows attributes to peek values from +/// other fields. +pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap { + let mut fields_map = HashMap::new(); + + let ast = structure.ast(); + if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { + for field in fields.iter() { + if let Some(ident) = &field.ident { + fields_map.insert(ident.to_string(), quote! { &self.#ident }); + } + } + } + + fields_map +}