about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2022-04-27 04:28:21 +0100
committerDavid Wood <david.wood@huawei.com>2022-04-29 02:12:10 +0100
commit2647a4812c87c1fd9535d0c26db2b5f6433075d0 (patch)
tree2e8119e48ccda1d4f2714bd084faf80e7d16a523
parent36a396ce51391ff6b0c41898a4c21fc6d303c4a4 (diff)
downloadrust-2647a4812c87c1fd9535d0c26db2b5f6433075d0.tar.gz
rust-2647a4812c87c1fd9535d0c26db2b5f6433075d0.zip
macros: reuse `SetOnce` trait in diagnostic derive
`SetOnce` trait was introduced in the subdiagnostic derive to simplify
the code a little bit, re-use it in the diagnostic derive too.

Signed-off-by: David Wood <david.wood@huawei.com>
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs71
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs15
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr112
3 files changed, 102 insertions, 96 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 2336186dc71..78e273ef823 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -5,7 +5,8 @@ use crate::diagnostics::error::{
     SessionDiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, FieldInfo, HasFieldMap,
+    option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, FieldInfo,
+    HasFieldMap, SetOnce,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
@@ -240,7 +241,7 @@ struct SessionDiagnosticDeriveBuilder {
     slug: Option<(String, proc_macro::Span)>,
     /// Error codes are a optional part of the struct attribute - this is only set to detect
     /// multiple specifications.
-    code: Option<proc_macro::Span>,
+    code: Option<(String, proc_macro::Span)>,
 }
 
 impl HasFieldMap for SessionDiagnosticDeriveBuilder {
@@ -306,7 +307,7 @@ impl SessionDiagnosticDeriveBuilder {
                 diag.help("only `error` and `warning` are valid attributes")
             }),
         };
-        self.set_kind_once(kind, span)?;
+        self.kind.set_once((kind, span));
 
         let mut tokens = Vec::new();
         for nested_attr in nested {
@@ -321,12 +322,17 @@ impl SessionDiagnosticDeriveBuilder {
                 // Struct attributes are only allowed to be applied once, and the diagnostic
                 // changes will be set in the initialisation code.
                 Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                    let span = s.span().unwrap();
                     match nested_name.as_str() {
                         "slug" => {
-                            self.set_slug_once(s.value(), s.span().unwrap());
+                            self.slug.set_once((s.value(), span));
                         }
                         "code" => {
-                            tokens.push(self.set_code_once(s.value(), s.span().unwrap()));
+                            self.code.set_once((s.value(), span));
+                            let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v));
+                            tokens.push(quote! {
+                                #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
+                            });
                         }
                         _ => invalid_nested_attr(attr, &nested_attr)
                             .help("only `slug` and `code` are valid nested attributes")
@@ -340,61 +346,6 @@ impl SessionDiagnosticDeriveBuilder {
         Ok(tokens.drain(..).collect())
     }
 
-    #[must_use]
-    fn set_kind_once(
-        &mut self,
-        kind: SessionDiagnosticKind,
-        span: proc_macro::Span,
-    ) -> Result<(), SessionDiagnosticDeriveError> {
-        match self.kind {
-            None => {
-                self.kind = Some((kind, span));
-                Ok(())
-            }
-            Some((prev_kind, prev_span)) => {
-                let existing = prev_kind.descr();
-                let current = kind.descr();
-
-                let msg = if current == existing {
-                    format!("`{}` specified multiple times", existing)
-                } else {
-                    format!("`{}` specified when `{}` was already specified", current, existing)
-                };
-                throw_span_err!(span, &msg, |diag| diag
-                    .span_note(prev_span, "previously specified here"));
-            }
-        }
-    }
-
-    fn set_code_once(&mut self, code: String, span: proc_macro::Span) -> TokenStream {
-        match self.code {
-            None => {
-                self.code = Some(span);
-            }
-            Some(prev_span) => {
-                span_err(span, "`code` specified multiple times")
-                    .span_note(prev_span, "previously specified here")
-                    .emit();
-            }
-        }
-
-        let diag = &self.diag;
-        quote! { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }
-    }
-
-    fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) {
-        match self.slug {
-            None => {
-                self.slug = Some((slug, span));
-            }
-            Some((_, prev_span)) => {
-                span_err(span, "`slug` specified multiple times")
-                    .span_note(prev_span, "previously specified here")
-                    .emit();
-            }
-        }
-    }
-
     fn generate_field_attr_code(
         &mut self,
         attr: &syn::Attribute,
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 5f55492edf9..df57a9f183f 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -90,21 +90,28 @@ struct WrongPlaceField {
 
 #[derive(SessionDiagnostic)]
 #[error(code = "E0123", slug = "foo")]
-#[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times
+#[error(code = "E0456", slug = "bar")]
+//~^ ERROR specified multiple times
+//~^^ ERROR specified multiple times
+//~^^^ ERROR specified multiple times
 struct ErrorSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
 #[error(code = "E0123", slug = "foo")]
 #[warning(code = "E0293", slug = "bar")]
-//~^ ERROR `warning` specified when `error` was already specified
+//~^ ERROR specified multiple times
+//~^^ ERROR specified multiple times
+//~^^^ ERROR specified multiple times
 struct WarnSpecifiedAfterError {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times
+#[error(code = "E0456", code = "E0457", slug = "bar")]
+//~^ ERROR specified multiple times
 struct CodeSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times
+#[error(code = "E0456", slug = "foo", slug = "bar")]
+//~^ ERROR specified multiple times
 struct SlugSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index ef4950ba3af..5a685ae43be 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -86,7 +86,7 @@ LL |     #[suggestion = "bar"]
    |
    = help: only `label`, `note` and `help` are valid field attributes
 
-error: `error` specified multiple times
+error: specified multiple times
   --> $DIR/diagnostic-derive.rs:93:1
    |
 LL | #[error(code = "E0456", slug = "bar")]
@@ -98,44 +98,92 @@ note: previously specified here
 LL | #[error(code = "E0123", slug = "foo")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `warning` specified when `error` was already specified
-  --> $DIR/diagnostic-derive.rs:98:1
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:93:16
+   |
+LL | #[error(code = "E0456", slug = "bar")]
+   |                ^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:92:16
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                ^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:93:32
+   |
+LL | #[error(code = "E0456", slug = "bar")]
+   |                                ^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:92:32
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                                ^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:1
    |
 LL | #[warning(code = "E0293", slug = "bar")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:97:1
+  --> $DIR/diagnostic-derive.rs:100:1
    |
 LL | #[error(code = "E0123", slug = "foo")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `code` specified multiple times
-  --> $DIR/diagnostic-derive.rs:103:32
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:18
+   |
+LL | #[warning(code = "E0293", slug = "bar")]
+   |                  ^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:100:16
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                ^^^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:101:34
+   |
+LL | #[warning(code = "E0293", slug = "bar")]
+   |                                  ^^^^^
+   |
+note: previously specified here
+  --> $DIR/diagnostic-derive.rs:100:32
+   |
+LL | #[error(code = "E0123", slug = "foo")]
+   |                                ^^^^^
+
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:108:32
    |
 LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
    |                                ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:103:16
+  --> $DIR/diagnostic-derive.rs:108:16
    |
 LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
    |                ^^^^^^^
 
-error: `slug` specified multiple times
-  --> $DIR/diagnostic-derive.rs:107:46
+error: specified multiple times
+  --> $DIR/diagnostic-derive.rs:113:46
    |
 LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
    |                                              ^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:107:32
+  --> $DIR/diagnostic-derive.rs:113:32
    |
 LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
    |                                ^^^^^
 
 error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:111:1
+  --> $DIR/diagnostic-derive.rs:118:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,7 +191,7 @@ LL | struct KindNotProvided {}
    = help: use the `#[error(...)]` attribute to create an error
 
 error: `slug` not specified
-  --> $DIR/diagnostic-derive.rs:114:1
+  --> $DIR/diagnostic-derive.rs:121:1
    |
 LL | / #[error(code = "E0456")]
 LL | | struct SlugNotProvided {}
@@ -152,13 +200,13 @@ LL | | struct SlugNotProvided {}
    = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:124:5
+  --> $DIR/diagnostic-derive.rs:131:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:132:5
+  --> $DIR/diagnostic-derive.rs:139:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
@@ -166,19 +214,19 @@ LL |     #[nonsense]
    = help: only `skip_arg`, `primary_span`, `label`, `note` and `help` are valid field attributes
 
 error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:149:5
+  --> $DIR/diagnostic-derive.rs:156:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:157:42
+  --> $DIR/diagnostic-derive.rs:164:42
    |
 LL |     #[suggestion(message = "bar", code = "{name}")]
    |                                          ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:162:16
+  --> $DIR/diagnostic-derive.rs:169:16
    |
 LL | #[derive(SessionDiagnostic)]
    |           -    ^ expected `'}'` in format string
@@ -189,7 +237,7 @@ LL | #[derive(SessionDiagnostic)]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:172:15
+  --> $DIR/diagnostic-derive.rs:179:15
    |
 LL | #[derive(SessionDiagnostic)]
    |               ^ unmatched `}` in format string
@@ -198,13 +246,13 @@ LL | #[derive(SessionDiagnostic)]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:192:5
+  --> $DIR/diagnostic-derive.rs:199:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:217:18
+  --> $DIR/diagnostic-derive.rs:224:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -212,7 +260,7 @@ LL |     #[suggestion(nonsense = "bar")]
    = help: only `message` and `code` are valid field attributes
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:225:18
+  --> $DIR/diagnostic-derive.rs:232:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -220,7 +268,7 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `message` and `code` are valid field attributes
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:247:5
+  --> $DIR/diagnostic-derive.rs:254:5
    |
 LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
 LL | |
@@ -230,7 +278,7 @@ LL | |     suggestion: Applicability,
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-  --> $DIR/diagnostic-derive.rs:262:5
+  --> $DIR/diagnostic-derive.rs:269:5
    |
 LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
 LL | |
@@ -238,7 +286,7 @@ LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:270:5
+  --> $DIR/diagnostic-derive.rs:277:5
    |
 LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
 LL | |
@@ -246,7 +294,7 @@ LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:278:5
+  --> $DIR/diagnostic-derive.rs:285:5
    |
 LL |     #[label("bar")]
    |     ^^^^^^^^^^^^^^^
@@ -254,25 +302,25 @@ LL |     #[label("bar")]
    = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes
 
 error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/diagnostic-derive.rs:399:1
+  --> $DIR/diagnostic-derive.rs:406:1
    |
 LL | #[help]
    | ^^^^^^^
 
 error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/diagnostic-derive.rs:407:1
+  --> $DIR/diagnostic-derive.rs:414:1
    |
 LL | #[help = "bar"]
    | ^^^^^^^^^^^^^^^
 
 error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/diagnostic-derive.rs:415:1
+  --> $DIR/diagnostic-derive.rs:422:1
    |
 LL | #[note]
    | ^^^^^^^
 
 error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
-  --> $DIR/diagnostic-derive.rs:423:1
+  --> $DIR/diagnostic-derive.rs:430:1
    |
 LL | #[note = "bar"]
    | ^^^^^^^^^^^^^^^
@@ -284,13 +332,13 @@ LL | #[nonsense(code = "E0123", slug = "foo")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:132:7
+  --> $DIR/diagnostic-derive.rs:139:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
 error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
-  --> $DIR/diagnostic-derive.rs:322:10
+  --> $DIR/diagnostic-derive.rs:329:10
    |
 LL | struct Hello {}
    | ------------ method `into_diagnostic_arg` not found for this
@@ -300,6 +348,6 @@ LL | #[derive(SessionDiagnostic)]
    |
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 37 previous errors
+error: aborting due to 41 previous errors
 
 For more information about this error, try `rustc --explain E0599`.