about summary refs log tree commit diff
diff options
context:
space:
mode:
authorXiretza <xiretza@xiretza.xyz>2022-08-19 15:02:10 +0200
committerXiretza <xiretza@xiretza.xyz>2022-08-21 09:17:43 +0200
commita960f8304cee9af374aae7bade15554734f37480 (patch)
treeebeae37fbf28a5735cb96eca6c9eedc0c9e83f74
parent91ad4e38f53ce1ef8783233bde36a81cd8177981 (diff)
downloadrust-a960f8304cee9af374aae7bade15554734f37480.tar.gz
rust-a960f8304cee9af374aae7bade15554734f37480.zip
Make derived SessionDiagnostics generic on diagnostic level
Deriving SessionDiagnostic on a type no longer forces that diagnostic to
be one of warning, error, or fatal. The level is instead decided when
the struct is passed to the respective Handler::emit_*() method.
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs82
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs81
-rw-r--r--compiler/rustc_macros/src/lib.rs2
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs6
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr120
5 files changed, 107 insertions, 184 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 6b5b8b59320..244edec2841 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -21,7 +21,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
             builder: DiagnosticDeriveBuilder {
                 diag,
                 fields: build_field_mapping(&structure),
-                kind: None,
+                kind: DiagnosticDeriveKind::SessionDiagnostic,
                 code: None,
                 slug: None,
             },
@@ -34,49 +34,31 @@ impl<'a> SessionDiagnosticDerive<'a> {
         let SessionDiagnosticDerive { mut structure, sess, mut builder } = self;
 
         let ast = structure.ast();
-        let (implementation, param_ty) = {
+        let implementation = {
             if let syn::Data::Struct(..) = ast.data {
                 let preamble = builder.preamble(&structure);
                 let (attrs, args) = builder.body(&mut structure);
 
                 let span = ast.span().unwrap();
                 let diag = &builder.diag;
-                let init = match (builder.kind.value(), builder.slug.value()) {
-                    (None, _) => {
-                        span_err(span, "diagnostic kind not specified")
-                            .help("use the `#[error(...)]` attribute to create an error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(kind), None) => {
+                let init = match builder.slug.value() {
+                    None => {
                         span_err(span, "diagnostic slug not specified")
                             .help(&format!(
-                                "specify the slug as the first argument to the attribute, such as \
-                                 `#[{}(typeck::example_error)]`",
-                                kind.descr()
+                                "specify the slug as the first argument to the `#[diag(...)]` attribute, \
+                                such as `#[diag(typeck::example_error)]`",
                             ))
                             .emit();
                         return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some(DiagnosticDeriveKind::Lint), _) => {
-                        span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported")
-                            .help("use the `#[error(...)]` attribute to create a error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(DiagnosticDeriveKind::Error), Some(slug)) => {
-                        quote! {
-                            let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug);
-                        }
-                    }
-                    (Some(DiagnosticDeriveKind::Warn), Some(slug)) => {
+                    Some(slug) => {
                         quote! {
-                            let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug);
+                            let mut #diag = #sess.struct_diagnostic(rustc_errors::fluent::#slug);
                         }
                     }
                 };
 
-                let implementation = quote! {
+                quote! {
                     #init
                     #preamble
                     match self {
@@ -86,18 +68,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
                         #args
                     }
                     #diag
-                };
-                let param_ty = match builder.kind {
-                    Some((DiagnosticDeriveKind::Error, _)) => {
-                        quote! { rustc_errors::ErrorGuaranteed }
-                    }
-                    Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => {
-                        quote! { () }
-                    }
-                    _ => unreachable!(),
-                };
-
-                (implementation, param_ty)
+                }
             } else {
                 span_err(
                     ast.span().unwrap(),
@@ -105,20 +76,20 @@ impl<'a> SessionDiagnosticDerive<'a> {
                 )
                 .emit();
 
-                let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                let param_ty = quote! { rustc_errors::ErrorGuaranteed };
-                (implementation, param_ty)
+                DiagnosticDeriveError::ErrorHandled.to_compile_error()
             }
         };
 
         structure.gen_impl(quote! {
-            gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty>
+            gen impl<'__session_diagnostic_sess, G>
+                    rustc_session::SessionDiagnostic<'__session_diagnostic_sess, G>
                     for @Self
+                where G: rustc_errors::EmissionGuarantee
             {
                 fn into_diagnostic(
                     self,
                     #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess
-                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> {
+                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
                 }
@@ -139,7 +110,7 @@ impl<'a> LintDiagnosticDerive<'a> {
             builder: DiagnosticDeriveBuilder {
                 diag,
                 fields: build_field_mapping(&structure),
-                kind: None,
+                kind: DiagnosticDeriveKind::LintDiagnostic,
                 code: None,
                 slug: None,
             },
@@ -158,30 +129,17 @@ impl<'a> LintDiagnosticDerive<'a> {
 
                 let diag = &builder.diag;
                 let span = ast.span().unwrap();
-                let init = match (builder.kind.value(), builder.slug.value()) {
-                    (None, _) => {
-                        span_err(span, "diagnostic kind not specified")
-                            .help("use the `#[error(...)]` attribute to create an error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(kind), None) => {
+                let init = match builder.slug.value() {
+                    None => {
                         span_err(span, "diagnostic slug not specified")
                             .help(&format!(
                                 "specify the slug as the first argument to the attribute, such as \
-                                 `#[{}(typeck::example_error)]`",
-                                kind.descr()
+                                 `#[diag(typeck::example_error)]`",
                             ))
                             .emit();
                         return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some(DiagnosticDeriveKind::Error | DiagnosticDeriveKind::Warn), _) => {
-                        span_err(span, "only `#[lint(..)]` is supported")
-                            .help("use the `#[lint(...)]` attribute to create a lint")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(DiagnosticDeriveKind::Lint), Some(slug)) => {
+                    Some(slug) => {
                         quote! {
                             let mut #diag = #diag.build(rustc_errors::fluent::#slug);
                         }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 6c9561925fe..6a5997512bd 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -18,30 +18,15 @@ use syn::{
 };
 use synstructure::{BindingInfo, Structure};
 
-/// What kind of diagnostic is being derived - an error, a warning or a lint?
-#[derive(Copy, Clone)]
+/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
+#[derive(Copy, Clone, PartialEq, Eq)]
 pub(crate) enum DiagnosticDeriveKind {
-    /// `#[error(..)]`
-    Error,
-    /// `#[warn(..)]`
-    Warn,
-    /// `#[lint(..)]`
-    Lint,
-}
-
-impl DiagnosticDeriveKind {
-    /// Returns human-readable string corresponding to the kind.
-    pub fn descr(&self) -> &'static str {
-        match self {
-            DiagnosticDeriveKind::Error => "error",
-            DiagnosticDeriveKind::Warn => "warning",
-            DiagnosticDeriveKind::Lint => "lint",
-        }
-    }
+    SessionDiagnostic,
+    LintDiagnostic,
 }
 
 /// Tracks persistent information required for building up individual calls to diagnostic methods
-/// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and
+/// for generated diagnostic derives - both `SessionDiagnostic` for fatal/errors/warnings and
 /// `LintDiagnostic` for lints.
 pub(crate) struct DiagnosticDeriveBuilder {
     /// The identifier to use for the generated `DiagnosticBuilder` instance.
@@ -51,8 +36,8 @@ pub(crate) struct DiagnosticDeriveBuilder {
     /// derive builder.
     pub fields: HashMap<String, TokenStream>,
 
-    /// Kind of diagnostic requested via the struct attribute.
-    pub kind: Option<(DiagnosticDeriveKind, proc_macro::Span)>,
+    /// Kind of diagnostic that should be derived.
+    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)>,
@@ -143,7 +128,7 @@ impl DiagnosticDeriveBuilder {
     }
 
     /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
-    /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
+    /// attributes like `#[diag(..)]`, such as the slug and error code. Generates
     /// diagnostic builder calls for setting error code and creating note/help messages.
     fn generate_structure_code_for_attr(
         &mut self,
@@ -156,15 +141,15 @@ impl DiagnosticDeriveBuilder {
         let name = name.as_str();
         let meta = attr.parse_meta()?;
 
-        let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_");
+        let is_diag = matches!(name, "error" | "warning" | "lint" | "diag");
 
         let nested = match meta {
-            // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
+            // Most attributes are lists, like `#[diag(..)]` for most cases or
             // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
             Meta::List(MetaList { ref nested, .. }) => nested,
             // Subdiagnostics without spans can be applied to the type too, and these are just
-            // paths: `#[help]` and `#[note]`
-            Meta::Path(_) if is_help_note_or_warn => {
+            // paths: `#[help]`, `#[note]` and `#[warn_]`
+            Meta::Path(_) if !is_diag => {
                 let fn_name = if name == "warn_" {
                     Ident::new("warn", attr.span())
                 } else {
@@ -178,23 +163,32 @@ impl DiagnosticDeriveBuilder {
         // Check the kind before doing any further processing so that there aren't misleading
         // "no kind specified" errors if there are failures later.
         match name {
-            "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)),
-            "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)),
-            "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)),
-            "help" | "note" | "warn_" => (),
+            "error" | "warning" => {
+                if self.kind == DiagnosticDeriveKind::LintDiagnostic {
+                    span_err(span, "only `#[lint(..)]` is supported")
+                        .help("use the `#[lint(...)]` attribute to create a lint")
+                        .emit();
+                }
+            }
+            "lint" => {
+                if self.kind == DiagnosticDeriveKind::SessionDiagnostic {
+                    span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported")
+                        .help("use the `#[error(...)]` attribute to create a error")
+                        .emit();
+                }
+            }
+            "diag" | "help" | "note" | "warn_" => (),
             _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes",
-                )
+                diag.help("only `diag`, `help`, `note` and `warn_` are valid attributes")
             }),
         }
 
-        // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or
+        // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or
         // `#[help(typeck::another_help)]`.
         let mut nested_iter = nested.into_iter();
         if let Some(nested_attr) = nested_iter.next() {
             // Report an error if there are any other list items after the path.
-            if is_help_note_or_warn && nested_iter.next().is_some() {
+            if !is_diag && nested_iter.next().is_some() {
                 throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                     diag.help(
                         "`help`, `note` and `warn_` struct attributes can only have one argument",
@@ -203,16 +197,16 @@ impl DiagnosticDeriveBuilder {
             }
 
             match nested_attr {
-                NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => {
-                    let fn_name = proc_macro2::Ident::new(name, attr.span());
-                    return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
-                }
                 NestedMeta::Meta(Meta::Path(path)) => {
-                    self.slug.set_once((path.clone(), span));
+                    if is_diag {
+                        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); });
+                    }
                 }
                 NestedMeta::Meta(meta @ Meta::NameValue(_))
-                    if !is_help_note_or_warn
-                        && meta.path().segments.last().unwrap().ident == "code" =>
+                    if is_diag && meta.path().segments.last().unwrap().ident == "code" =>
                 {
                     // don't error for valid follow-up attributes
                 }
@@ -347,6 +341,7 @@ impl DiagnosticDeriveBuilder {
             }
             "primary_span" => {
                 report_error_if_not_applied_to_span(attr, &info)?;
+
                 Ok(quote! {
                     #diag.set_span(#binding);
                 })
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index e01d035767b..fe4ff2fb6aa 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -132,6 +132,7 @@ decl_derive!(
         warning,
         error,
         lint,
+        diag,
         help,
         note,
         warn_,
@@ -151,6 +152,7 @@ decl_derive!(
         warning,
         error,
         lint,
+        diag,
         help,
         note,
         warn_,
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 0a210cbdc94..8634fbc7aca 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -52,7 +52,7 @@ struct WrongStructAttrStyle {}
 #[derive(SessionDiagnostic)]
 #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 //~^ ERROR `#[nonsense(...)]` is not a valid attribute
-//~^^ ERROR diagnostic kind not specified
+//~^^ ERROR diagnostic slug not specified
 //~^^^ ERROR cannot find attribute `nonsense` in this scope
 struct InvalidStructAttr {}
 
@@ -103,7 +103,6 @@ struct WrongPlaceField {
 #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
-//~^^^ ERROR specified multiple times
 struct ErrorSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
@@ -111,7 +110,6 @@ struct ErrorSpecifiedTwice {}
 #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
-//~^^^ ERROR specified multiple times
 struct WarnSpecifiedAfterError {}
 
 #[derive(SessionDiagnostic)]
@@ -125,7 +123,7 @@ struct CodeSpecifiedTwice {}
 struct SlugSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
-struct KindNotProvided {} //~ ERROR diagnostic kind not specified
+struct KindNotProvided {} //~ ERROR diagnostic slug not specified
 
 #[derive(SessionDiagnostic)]
 #[error(code = "E0456")]
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index a1a054c67d4..8c826c9a284 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -21,9 +21,9 @@ error: `#[nonsense(...)]` is not a valid attribute
 LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: only `error`, `warning`, `help`, `note` and `warn_` are valid attributes
+   = help: only `diag`, `help`, `note` and `warn_` are valid attributes
 
-error: diagnostic kind not specified
+error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:53:1
    |
 LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
@@ -33,7 +33,7 @@ LL | |
 LL | | struct InvalidStructAttr {}
    | |___________________________^
    |
-   = help: use the `#[error(...)]` attribute to create an error
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[error("...")]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:60:9
@@ -52,7 +52,7 @@ LL | |
 LL | | struct InvalidLitNestedAttr {}
    | |______________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[error(nonsense(...))]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:71:9
@@ -71,7 +71,7 @@ LL | |
 LL | | struct InvalidNestedStructAttr1 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:77:9
@@ -90,7 +90,7 @@ LL | |
 LL | | struct InvalidNestedStructAttr2 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:83:9
@@ -109,7 +109,7 @@ LL | |
 LL | | struct InvalidNestedStructAttr3 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: `#[error(slug = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:89:59
@@ -138,18 +138,6 @@ LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:103:1
-   |
-LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/diagnostic-derive.rs:102:1
-   |
-LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: specified multiple times
   --> $DIR/diagnostic-derive.rs:103:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
@@ -162,85 +150,73 @@ LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:111:1
-   |
-LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
   --> $DIR/diagnostic-derive.rs:110:1
    |
-LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:111:1
-   |
 LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:110:1
+  --> $DIR/diagnostic-derive.rs:109:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:111:52
+  --> $DIR/diagnostic-derive.rs:110:52
    |
 LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
    |                                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:110:50
+  --> $DIR/diagnostic-derive.rs:109:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:118:66
+  --> $DIR/diagnostic-derive.rs:116:66
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:118:50
+  --> $DIR/diagnostic-derive.rs:116:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                  ^^^^^^^
 
 error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:123:43
+  --> $DIR/diagnostic-derive.rs:121:43
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:128:1
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:126:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use the `#[error(...)]` attribute to create an error
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:131:1
+  --> $DIR/diagnostic-derive.rs:129:1
    |
 LL | / #[error(code = "E0456")]
 LL | |
 LL | | struct SlugNotProvided {}
    | |_________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:142:5
+  --> $DIR/diagnostic-derive.rs:140:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:150:5
+  --> $DIR/diagnostic-derive.rs:148:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
@@ -248,19 +224,19 @@ LL |     #[nonsense]
    = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:167:5
+  --> $DIR/diagnostic-derive.rs:165:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:175:45
+  --> $DIR/diagnostic-derive.rs:173:45
    |
 LL |     #[suggestion(typeck::suggestion, code = "{name}")]
    |                                             ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:180:16
+  --> $DIR/diagnostic-derive.rs:178:16
    |
 LL | #[derive(SessionDiagnostic)]
    |           -    ^ expected `'}'` in format string
@@ -271,7 +247,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:190:15
+  --> $DIR/diagnostic-derive.rs:188:15
    |
 LL | #[derive(SessionDiagnostic)]
    |               ^ unmatched `}` in format string
@@ -280,13 +256,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` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:210:5
+  --> $DIR/diagnostic-derive.rs:208:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:235:18
+  --> $DIR/diagnostic-derive.rs:233:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -294,7 +270,7 @@ LL |     #[suggestion(nonsense = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:243:18
+  --> $DIR/diagnostic-derive.rs:241:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -302,7 +278,7 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:265:5
+  --> $DIR/diagnostic-derive.rs:263:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -312,7 +288,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:280:5
+  --> $DIR/diagnostic-derive.rs:278:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -320,7 +296,7 @@ LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:288:5
+  --> $DIR/diagnostic-derive.rs:286:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -328,60 +304,54 @@ LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:296:5
+  --> $DIR/diagnostic-derive.rs:294:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: applicability cannot be set in both the field and attribute
-  --> $DIR/diagnostic-derive.rs:447:52
+  --> $DIR/diagnostic-derive.rs:445:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:455:52
+  --> $DIR/diagnostic-derive.rs:453:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:518:5
+  --> $DIR/diagnostic-derive.rs:516:5
    |
 LL |     #[label(typeck::label, foo)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:526:5
+  --> $DIR/diagnostic-derive.rs:524:5
    |
 LL |     #[label(typeck::label, foo = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:534:5
+  --> $DIR/diagnostic-derive.rs:532:5
    |
 LL |     #[label(typeck::label, foo("..."))]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: only `#[error(..)]` and `#[warning(..)]` are supported
-  --> $DIR/diagnostic-derive.rs:540:1
+  --> $DIR/diagnostic-derive.rs:538:1
    |
-LL | / #[lint(typeck::ambiguous_lifetime_bound)]
-LL | |
-LL | | struct LintsBad {
-LL | | }
-   | |_^
+LL | #[lint(typeck::ambiguous_lifetime_bound)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use the `#[error(...)]` attribute to create a error
 
 error: only `#[lint(..)]` is supported
-  --> $DIR/diagnostic-derive.rs:551:1
+  --> $DIR/diagnostic-derive.rs:549:1
    |
-LL | / #[error(typeck::ambiguous_lifetime_bound)]
-LL | |
-LL | | struct ErrorsBad {
-LL | | }
-   | |_^
+LL | #[error(typeck::ambiguous_lifetime_bound)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use the `#[lint(...)]` attribute to create a lint
 
@@ -392,7 +362,7 @@ LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:150:7
+  --> $DIR/diagnostic-derive.rs:148:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
@@ -404,7 +374,7 @@ LL | #[error(nonsense, code = "E0123")]
    |         ^^^^^^^^ not found in `rustc_errors::fluent`
 
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:340:10
+  --> $DIR/diagnostic-derive.rs:338:10
    |
 LL | #[derive(SessionDiagnostic)]
    |          ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
@@ -417,7 +387,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 48 previous errors
+error: aborting due to 46 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.