diff options
| author | David Wood <david.wood@huawei.com> | 2022-05-07 06:02:11 +0100 |
|---|---|---|
| committer | David Wood <david.wood@huawei.com> | 2022-05-12 07:21:51 +0100 |
| commit | 7b7061dd898b5a9c06477941e2d0840e27b9c67b (patch) | |
| tree | 9a1134b917032ed2345f64f1ba21daf59266d223 /compiler/rustc_macros/src/diagnostics/utils.rs | |
| parent | 1d2ea98cff1fde1d8b9e83a0eb639b8ec2cb82d8 (diff) | |
| download | rust-7b7061dd898b5a9c06477941e2d0840e27b9c67b.tar.gz rust-7b7061dd898b5a9c06477941e2d0840e27b9c67b.zip | |
macros: spanless subdiagnostics from `()` fields
Type attributes could previously be used to support spanless subdiagnostics but these couldn't easily be made optional in the same way that spanned subdiagnostics could by using a field attribute on a field with an `Option<Span>` type. Spanless subdiagnostics can now be specified on fields with `()` type or `Option<()>` type. Signed-off-by: David Wood <david.wood@huawei.com>
Diffstat (limited to 'compiler/rustc_macros/src/diagnostics/utils.rs')
| -rw-r--r-- | compiler/rustc_macros/src/diagnostics/utils.rs | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index aba861fc6aa..af5a30880e0 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use std::collections::BTreeSet; use std::str::FromStr; -use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility}; +use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple, Visibility}; use synstructure::BindingInfo; /// Checks whether the type name of `ty` matches `name`. @@ -25,7 +25,35 @@ pub(crate) fn type_matches_path(ty: &Type, name: &[&str]) -> bool { } } -/// Reports an error if the field's type is not `Applicability`. +/// Checks whether the type `ty` is `()`. +pub(crate) fn type_is_unit(ty: &Type) -> bool { + if let Type::Tuple(TypeTuple { elems, .. }) = ty { elems.is_empty() } else { false } +} + +/// Reports a type error for field with `attr`. +pub(crate) fn report_type_error( + attr: &Attribute, + ty_name: &str, +) -> Result<!, SessionDiagnosticDeriveError> { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let meta = attr.parse_meta()?; + + throw_span_err!( + attr.span().unwrap(), + &format!( + "the `#[{}{}]` attribute can only be applied to fields of type {}", + name, + match meta { + Meta::Path(_) => "", + Meta::NameValue(_) => " = ...", + Meta::List(_) => "(...)", + }, + ty_name + ) + ); +} + +/// Reports an error if the field's type does not match `path`. fn report_error_if_not_applied_to_ty( attr: &Attribute, info: &FieldInfo<'_>, @@ -33,23 +61,7 @@ fn report_error_if_not_applied_to_ty( ty_name: &str, ) -> Result<(), SessionDiagnosticDeriveError> { if !type_matches_path(&info.ty, path) { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - let meta = attr.parse_meta()?; - - throw_span_err!( - attr.span().unwrap(), - &format!( - "the `#[{}{}]` attribute can only be applied to fields of type `{}`", - name, - match meta { - Meta::Path(_) => "", - Meta::NameValue(_) => " = ...", - Meta::List(_) => "(...)", - }, - ty_name - ) - ); + report_type_error(attr, ty_name)?; } Ok(()) @@ -64,7 +76,7 @@ pub(crate) fn report_error_if_not_applied_to_applicability( attr, info, &["rustc_errors", "Applicability"], - "Applicability", + "`Applicability`", ) } @@ -73,7 +85,7 @@ pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, ) -> Result<(), SessionDiagnosticDeriveError> { - report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "Span") + report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`") } /// Inner type of a field and type of wrapper. |
