about summary refs log tree commit diff
path: root/compiler/rustc_macros/src/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_macros/src/diagnostics')
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs22
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs29
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs14
3 files changed, 39 insertions, 26 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 1e1bfbb943e..72f20efc834 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -18,6 +18,8 @@ use syn::{
 };
 use synstructure::{BindingInfo, Structure};
 
+use super::utils::SpannedOption;
+
 /// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub(crate) enum DiagnosticDeriveKind {
@@ -40,10 +42,10 @@ pub(crate) struct DiagnosticDeriveBuilder {
     pub kind: DiagnosticDeriveKind,
     /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
     /// has the actual diagnostic message.
-    pub slug: Option<(Path, proc_macro::Span)>,
+    pub slug: SpannedOption<Path>,
     /// Error codes are a optional part of the struct attribute - this is only set to detect
     /// multiple specifications.
-    pub code: Option<(String, proc_macro::Span)>,
+    pub code: SpannedOption<String>,
 }
 
 impl HasFieldMap for DiagnosticDeriveBuilder {
@@ -191,7 +193,7 @@ impl DiagnosticDeriveBuilder {
             match nested_attr {
                 NestedMeta::Meta(Meta::Path(path)) => {
                     if is_diag {
-                        self.slug.set_once((path.clone(), span));
+                        self.slug.set_once(path.clone(), span);
                     } else {
                         let fn_name = proc_macro2::Ident::new(name, attr.span());
                         return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
@@ -224,8 +226,8 @@ impl DiagnosticDeriveBuilder {
                 let span = s.span().unwrap();
                 match nested_name.as_str() {
                     "code" => {
-                        self.code.set_once((s.value(), span));
-                        let code = &self.code.as_ref().map(|(v, _)| v);
+                        self.code.set_once(s.value(), span);
+                        let code = &self.code.value_ref();
                         tokens.push(quote! {
                             #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
                         });
@@ -476,10 +478,10 @@ impl DiagnosticDeriveBuilder {
                     match nested_name {
                         "code" => {
                             let formatted_str = self.build_format(&s.value(), s.span());
-                            code.set_once((formatted_str, span));
+                            code.set_once(formatted_str, span);
                         }
                         "applicability" => match Applicability::from_str(&s.value()) {
-                            Ok(v) => applicability.set_once((quote! { #v }, span)),
+                            Ok(v) => applicability.set_once(quote! { #v }, span),
                             Err(()) => {
                                 span_err(span, "invalid applicability").emit();
                             }
@@ -546,7 +548,7 @@ impl DiagnosticDeriveBuilder {
     fn span_and_applicability_of_ty(
         &self,
         info: FieldInfo<'_>,
-    ) -> Result<(TokenStream, Option<(TokenStream, proc_macro::Span)>), DiagnosticDeriveError> {
+    ) -> Result<(TokenStream, SpannedOption<TokenStream>), DiagnosticDeriveError> {
         match &info.ty {
             // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
             ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
@@ -570,9 +572,9 @@ impl DiagnosticDeriveBuilder {
 
                 for (idx, elem) in tup.elems.iter().enumerate() {
                     if type_matches_path(elem, &["rustc_span", "Span"]) {
-                        span_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
+                        span_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
                     } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
-                        applicability_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
+                        applicability_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
                     } else {
                         type_err(&elem.span())?;
                     }
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index bdeca3420bc..9116dd186f9 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -15,6 +15,8 @@ use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
+use super::utils::SpannedOption;
+
 /// Which kind of suggestion is being created?
 #[derive(Clone, Copy)]
 enum SubdiagnosticSuggestionKind {
@@ -195,10 +197,10 @@ struct SubdiagnosticDeriveBuilder<'a> {
     fields: HashMap<String, TokenStream>,
 
     /// Identifier for the binding to the `#[primary_span]` field.
-    span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
+    span_field: SpannedOption<proc_macro2::Ident>,
     /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
     /// `rustc_errors::Applicability::*` variant directly.
-    applicability: Option<(TokenStream, proc_macro::Span)>,
+    applicability: SpannedOption<TokenStream>,
 
     /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
     /// during finalization if still `false`.
@@ -283,7 +285,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             if let Some(nested_attr) = nested_iter.next() {
                 match nested_attr {
                     NestedMeta::Meta(Meta::Path(path)) => {
-                        slug.set_once((path.clone(), span));
+                        slug.set_once(path.clone(), span);
                     }
                     NestedMeta::Meta(meta @ Meta::NameValue(_))
                         if matches!(
@@ -326,7 +328,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     "code" => {
                         if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
                             let formatted_str = self.build_format(&value.value(), value.span());
-                            code.set_once((formatted_str, span));
+                            code.set_once(formatted_str, span);
                         } else {
                             span_err(
                                 span,
@@ -349,7 +351,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                                     span_err(span, "invalid applicability").emit();
                                     Applicability::Unspecified
                                 });
-                            self.applicability.set_once((quote! { #value }, span));
+                            self.applicability.set_once(quote! { #value }, span);
                         } else {
                             span_err(
                                 span,
@@ -485,7 +487,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                 report_error_if_not_applied_to_span(attr, &info)?;
 
                 let binding = info.binding.binding.clone();
-                self.span_field.set_once((binding, span));
+                self.span_field.set_once(binding, span);
 
                 Ok(quote! {})
             }
@@ -509,7 +511,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     report_error_if_not_applied_to_applicability(attr, &info)?;
 
                     let binding = info.binding.binding.clone();
-                    self.applicability.set_once((quote! { #binding }, span));
+                    self.applicability.set_once(quote! { #binding }, span);
                 } else {
                     span_err(span, "`#[applicability]` is only valid on suggestions").emit();
                 }
@@ -577,7 +579,7 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
                     match nested_name {
                         "code" => {
                             let formatted_str = self.build_format(&value.value(), value.span());
-                            code.set_once((formatted_str, span));
+                            code.set_once(formatted_str, span);
                         }
                         _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                             diag.help("`code` is the only valid nested attribute")
@@ -635,11 +637,12 @@ impl<'a> SubdiagnosticDeriveBuilder<'a> {
             .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
-        let span_field = self.span_field.as_ref().map(|(span, _)| span);
-        let applicability = self.applicability.take().map_or_else(
-            || quote! { rustc_errors::Applicability::Unspecified },
-            |(applicability, _)| applicability,
-        );
+        let span_field = self.span_field.value_ref();
+        let applicability = self
+            .applicability
+            .take()
+            .value()
+            .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
 
         let diag = &self.diag;
         let mut calls = TokenStream::new();
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index ad9ecd39b9e..3efcd216d19 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -172,13 +172,17 @@ pub(crate) struct FieldInfo<'a> {
 /// Small helper trait for abstracting over `Option` fields that contain a value and a `Span`
 /// for error reporting if they are set more than once.
 pub(crate) trait SetOnce<T> {
-    fn set_once(&mut self, _: (T, Span));
+    fn set_once(&mut self, value: T, span: Span);
 
     fn value(self) -> Option<T>;
+    fn value_ref(&self) -> Option<&T>;
 }
 
-impl<T> SetOnce<T> for Option<(T, Span)> {
-    fn set_once(&mut self, (value, span): (T, Span)) {
+/// An [`Option<T>`] that keeps track of the span that caused it to be set; used with [`SetOnce`].
+pub(super) type SpannedOption<T> = Option<(T, Span)>;
+
+impl<T> SetOnce<T> for SpannedOption<T> {
+    fn set_once(&mut self, value: T, span: Span) {
         match self {
             None => {
                 *self = Some((value, span));
@@ -194,6 +198,10 @@ impl<T> SetOnce<T> for Option<(T, Span)> {
     fn value(self) -> Option<T> {
         self.map(|(v, _)| v)
     }
+
+    fn value_ref(&self) -> Option<&T> {
+        self.as_ref().map(|(v, _)| v)
+    }
 }
 
 pub(crate) trait HasFieldMap {