diff options
Diffstat (limited to 'compiler/rustc_macros/src')
| -rw-r--r-- | compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/diagnostics/subdiagnostic.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/diagnostics/utils.rs | 27 |
3 files changed, 43 insertions, 23 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index cd6e3687460..2e6e84ad80e 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -14,6 +14,8 @@ use syn::Token; use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type}; use synstructure::{BindingInfo, Structure, VariantInfo}; +use super::utils::SubdiagnosticVariant; + /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? #[derive(Clone, PartialEq, Eq)] pub(crate) enum DiagnosticDeriveKind { @@ -150,19 +152,19 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { fn parse_subdiag_attribute( &self, attr: &Attribute, - ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> { - let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + ) -> Result<Option<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> { + let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, self)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. return Ok(None); }; - if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag { + if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag.kind { throw_invalid_attr!(attr, |diag| diag .help("consider creating a `Subdiagnostic` instead")); } - let slug = slug.unwrap_or_else(|| match subdiag { + let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind { SubdiagnosticKind::Label => parse_quote! { _subdiag::label }, SubdiagnosticKind::Note => parse_quote! { _subdiag::note }, SubdiagnosticKind::Help => parse_quote! { _subdiag::help }, @@ -171,7 +173,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), }); - Ok(Some((subdiag, slug))) + Ok(Some((subdiag.kind, slug, subdiag.no_span))) } /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct @@ -229,7 +231,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(tokens); } - let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + let Some((subdiag, slug, _no_span)) = self.parse_subdiag_attribute(attr)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. return Ok(quote! {}); @@ -380,7 +382,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { _ => (), } - let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + let Some((subdiag, slug, _no_span)) = self.parse_subdiag_attribute(attr)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. return Ok(quote! {}); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 374ba1a45c0..e3d9eb96574 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -14,6 +14,8 @@ use quote::{format_ident, quote}; use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; +use super::utils::SubdiagnosticVariant; + /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct. pub(crate) struct SubdiagnosticDeriveBuilder { diag: syn::Ident, @@ -180,11 +182,13 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics { } impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { - fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> { + fn identify_kind( + &mut self, + ) -> Result<Vec<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> { let mut kind_slugs = vec![]; for attr in self.variant.ast().attrs { - let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + let Some(SubdiagnosticVariant { kind, slug, no_span }) = SubdiagnosticVariant::from_attr(attr, self)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. continue; @@ -202,7 +206,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { ); }; - kind_slugs.push((kind, slug)); + kind_slugs.push((kind, slug, no_span)); } Ok(kind_slugs) @@ -487,7 +491,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } }; - let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); + let kind_stats: KindsStatistics = + kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect(); let init = if kind_stats.has_multipart_suggestion { quote! { let mut suggestions = Vec::new(); } @@ -508,13 +513,17 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let diag = &self.parent.diag; let f = &self.parent.f; let mut calls = TokenStream::new(); - for (kind, slug) in kind_slugs { + for (kind, slug, no_span) in kind_slugs { let message = format_ident!("__message"); calls.extend( quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); }, ); - let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); + let name = format_ident!( + "{}{}", + if span_field.is_some() && !no_span { "span_" } else { "" }, + kind + ); let call = match kind { SubdiagnosticKind::Suggestion { suggestion_kind, @@ -566,7 +575,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } _ => { - if let Some(span) = span_field { + if let Some(span) = span_field && !no_span { quote! { #diag.#name(#span, #message); } } else { quote! { #diag.#name(#message); } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index e2434981f8d..85dd9f6a3ce 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -597,14 +597,20 @@ pub(super) enum SubdiagnosticKind { }, } -impl SubdiagnosticKind { - /// Constructs a `SubdiagnosticKind` from a field or type attribute such as `#[note]`, - /// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the +pub(super) struct SubdiagnosticVariant { + pub(super) kind: SubdiagnosticKind, + pub(super) slug: Option<Path>, + pub(super) no_span: bool, +} + +impl SubdiagnosticVariant { + /// Constructs a `SubdiagnosticVariant` from a field or type attribute such as `#[note]`, + /// `#[error(parser::add_paren, no_span)]` or `#[suggestion(code = "...")]`. Returns the /// `SubdiagnosticKind` and the diagnostic slug, if specified. pub(super) fn from_attr( attr: &Attribute, fields: &impl HasFieldMap, - ) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> { + ) -> Result<Option<SubdiagnosticVariant>, DiagnosticDeriveError> { // Always allow documentation comments. if is_doc_comment(attr) { return Ok(None); @@ -679,7 +685,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::Help | SubdiagnosticKind::Warn | SubdiagnosticKind::MultipartSuggestion { .. } => { - return Ok(Some((kind, None))); + return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false })); } SubdiagnosticKind::Suggestion { .. } => { throw_span_err!(span, "suggestion without `code = \"...\"`") @@ -696,11 +702,14 @@ impl SubdiagnosticKind { let mut first = true; let mut slug = None; + let mut no_span = false; list.parse_nested_meta(|nested| { if nested.input.is_empty() || nested.input.peek(Token![,]) { if first { slug = Some(nested.path); + } else if nested.path.is_ident("no_span") { + no_span = true; } else { span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit(); } @@ -775,19 +784,19 @@ impl SubdiagnosticKind { (_, SubdiagnosticKind::Suggestion { .. }) => { span_err(path_span, "invalid nested attribute") .help( - "only `style`, `code` and `applicability` are valid nested attributes", + "only `no_span`, `style`, `code` and `applicability` are valid nested attributes", ) .emit(); has_errors = true; } (_, SubdiagnosticKind::MultipartSuggestion { .. }) => { span_err(path_span, "invalid nested attribute") - .help("only `style` and `applicability` are valid nested attributes") + .help("only `no_span`, `style` and `applicability` are valid nested attributes") .emit(); has_errors = true; } _ => { - span_err(path_span, "invalid nested attribute").emit(); + span_err(path_span, "only `no_span` is a valid nested attribute").emit(); has_errors = true; } } @@ -831,7 +840,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::Warn => {} } - Ok(Some((kind, slug))) + Ok(Some(SubdiagnosticVariant { kind, slug, no_span })) } } |
