about summary refs log tree commit diff
path: root/compiler/rustc_macros/src/diagnostics/utils.rs
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2022-05-07 06:02:11 +0100
committerDavid Wood <david.wood@huawei.com>2022-05-12 07:21:51 +0100
commit7b7061dd898b5a9c06477941e2d0840e27b9c67b (patch)
tree9a1134b917032ed2345f64f1ba21daf59266d223 /compiler/rustc_macros/src/diagnostics/utils.rs
parent1d2ea98cff1fde1d8b9e83a0eb639b8ec2cb82d8 (diff)
downloadrust-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.rs54
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.