about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-06-26 19:47:04 +0200
committerGitHub <noreply@github.com>2022-06-26 19:47:04 +0200
commit0b3b4ef2b521496b90345e62ef121bd1c9daba4d (patch)
tree78a191d2a8e95b804dcf645d8cdbdf9932bffe68 /src/test
parentdf26fdf3e1667e7ea2e442bb554aa9632677c862 (diff)
parentdc90d1d987d74af4950caca0f9b16d7fdf21b6af (diff)
downloadrust-0b3b4ef2b521496b90345e62ef121bd1c9daba4d.tar.gz
rust-0b3b4ef2b521496b90345e62ef121bd1c9daba4d.zip
Rollup merge of #98428 - davidtwco:translation-derive-typed-identifiers, r=oli-obk
macros: use typed identifiers in diag and subdiag derive

Using typed identifiers instead of strings with the Fluent identifiers in the diagnostic and subdiagnostic derives - this enables the diagnostic derive to benefit from the compile-time validation that comes with typed identifiers, namely that use of a non-existent Fluent identifier will not compile.

r? `````@oli-obk`````
Diffstat (limited to 'src/test')
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.rs4
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs241
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr287
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs159
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr207
5 files changed, 504 insertions, 394 deletions
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
index 817d8531da9..d6f63d44ba6 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
@@ -16,14 +16,14 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::Span;
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-expect-path")]
+#[error(parser::expect_path)]
 struct DeriveSessionDiagnostic {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "note")]
+#[note(parser::add_paren)]
 struct Note {
     #[primary_span]
     span: Span,
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 84d5de17309..7bec1897fa5 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -26,15 +26,15 @@ use rustc_errors::Applicability;
 extern crate rustc_session;
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "hello-world")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct Hello {}
 
 #[derive(SessionDiagnostic)]
-#[warning(code = "E0123", slug = "hello-world")]
+#[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct HelloWarn {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs
 enum SessionDiagnosticOnEnum {
     Foo,
@@ -42,13 +42,13 @@ enum SessionDiagnosticOnEnum {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[error = "E0123"]
 //~^ ERROR `#[error = ...]` is not a valid attribute
 struct WrongStructAttrStyle {}
 
 #[derive(SessionDiagnostic)]
-#[nonsense(code = "E0123", slug = "foo")]
+#[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 //~^ ERROR `#[nonsense(...)]` is not a valid attribute
 //~^^ ERROR diagnostic kind not specified
 //~^^^ ERROR cannot find attribute `nonsense` in this scope
@@ -57,31 +57,39 @@ struct InvalidStructAttr {}
 #[derive(SessionDiagnostic)]
 #[error("E0123")]
 //~^ ERROR `#[error("...")]` is not a valid attribute
-//~^^ ERROR `slug` not specified
+//~^^ ERROR diagnostic slug not specified
 struct InvalidLitNestedAttr {}
 
 #[derive(SessionDiagnostic)]
-#[error(nonsense, code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense)]` is not a valid attribute
+#[error(nonsense, code = "E0123")]
+//~^ ERROR cannot find value `nonsense` in module `rustc_errors::fluent`
 struct InvalidNestedStructAttr {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense("foo"), code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense(...))]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr1 {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense = "...", code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr2 {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense = 4, code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr3 {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(slug = ...)]` is not a valid attribute
+struct InvalidNestedStructAttr4 {}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct WrongPlaceField {
     #[suggestion = "bar"]
     //~^ ERROR `#[suggestion = ...]` is not a valid attribute
@@ -89,44 +97,45 @@ struct WrongPlaceField {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[error(code = "E0456", slug = "bar")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
 //~^ 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(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
 //~^^^ ERROR specified multiple times
 struct WarnSpecifiedAfterError {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", code = "E0457", slug = "bar")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
 //~^ ERROR specified multiple times
 struct CodeSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo", slug = "bar")]
-//~^ ERROR specified multiple times
+#[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
+//~^ ERROR `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
 struct SlugSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
 struct KindNotProvided {} //~ ERROR diagnostic kind not specified
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456")] //~ ERROR `slug` not specified
+#[error(code = "E0456")]
+//~^ ERROR diagnostic slug not specified
 struct SlugNotProvided {}
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound)]
 struct CodeNotProvided {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct MessageWrongType {
     #[primary_span]
     //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span`
@@ -134,7 +143,7 @@ struct MessageWrongType {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct InvalidPathFieldAttr {
     #[nonsense]
     //~^ ERROR `#[nonsense]` is not a valid attribute
@@ -143,34 +152,34 @@ struct InvalidPathFieldAttr {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithField {
     name: String,
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithMessageAppliedToField {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    #[label(typeck::label)]
+    //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
     name: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNonexistentField {
-    #[suggestion(message = "bar", code = "{name}")]
+    #[suggestion(typeck::suggestion, code = "{name}")]
     //~^ ERROR `name` doesn't refer to a field on this type
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR invalid format string: expected `'}'`
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorMissingClosingBrace {
-    #[suggestion(message = "bar", code = "{name")]
+    #[suggestion(typeck::suggestion, code = "{name")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
@@ -178,48 +187,48 @@ struct ErrorMissingClosingBrace {
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR invalid format string: unmatched `}`
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorMissingOpeningBrace {
-    #[suggestion(message = "bar", code = "name}")]
+    #[suggestion(typeck::suggestion, code = "name}")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelOnSpan {
-    #[label = "bar"]
+    #[label(typeck::label)]
     sp: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelOnNonSpan {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    #[label(typeck::label)]
+    //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
     id: u32,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct Suggest {
-    #[suggestion(message = "bar", code = "This is the suggested code")]
-    #[suggestion_short(message = "qux", code = "This is the suggested code")]
-    #[suggestion_hidden(message = "foobar", code = "This is the suggested code")]
-    #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_short(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_hidden(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_verbose(typeck::suggestion, code = "This is the suggested code")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithoutCode {
-    #[suggestion(message = "bar")]
+    #[suggestion(typeck::suggestion)]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
     //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
@@ -227,7 +236,7 @@ struct SuggestWithBadKey {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
     //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
@@ -235,91 +244,91 @@ struct SuggestWithShorthandMsg {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithoutMsg {
     #[suggestion(code = "bar")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithTypesSwapped {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Span),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithWrongTypeApplicabilityOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR wrong field type for suggestion
     suggestion: Applicability,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithSpanOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateSpanAndApplicability {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
     suggestion: (Span, Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateApplicabilityAndSpan {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
     suggestion: (Applicability, Applicability, Span),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct WrongKindOfAnnotation {
-    #[label("bar")]
-    //~^ ERROR `#[label(...)]` is not a valid attribute
+    #[label = "bar"]
+    //~^ ERROR `#[label = ...]` is not a valid attribute
     z: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct OptionsInErrors {
-    #[label = "bar"]
+    #[label(typeck::label)]
     label: Option<Span>,
-    #[suggestion(message = "bar")]
+    #[suggestion(typeck::suggestion)]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
 struct MoveOutOfBorrowError<'tcx> {
     name: Ident,
     ty: Ty<'tcx>,
     #[primary_span]
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
-    #[label = "qux"]
+    #[label(typeck::label)]
     other_span: Span,
-    #[suggestion(message = "bar", code = "{name}.clone()")]
+    #[suggestion(typeck::suggestion, code = "{name}.clone()")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithLifetime<'a> {
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
     name: &'a str,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithDefaultLabelAttr<'a> {
     #[label]
     span: Span,
@@ -328,7 +337,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ArgFieldWithoutSkip {
     #[primary_span]
     span: Span,
@@ -336,7 +345,7 @@ struct ArgFieldWithoutSkip {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ArgFieldWithSkip {
     #[primary_span]
     span: Span,
@@ -347,132 +356,132 @@ struct ArgFieldWithSkip {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedNote {
     #[note]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedNoteCustom {
-    #[note = "bar"]
+    #[note(typeck::note)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[note]
 struct ErrorWithNote {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[note = "bar"]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[note(typeck::note)]
 struct ErrorWithNoteCustom {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedHelp {
     #[help]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedHelpCustom {
-    #[help = "bar"]
+    #[help(typeck::help)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[help]
 struct ErrorWithHelp {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[help = "bar"]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[help(typeck::help)]
 struct ErrorWithHelpCustom {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
 #[help]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithHelpWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[help = "bar"]
-#[error(code = "E0123", slug = "foo")]
+#[help(typeck::help)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithHelpCustomWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
 #[note]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNoteWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[note = "bar"]
-#[error(code = "E0123", slug = "foo")]
+#[note(typeck::note)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNoteCustomWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ApplicabilityInBoth {
-    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
     //~^ ERROR applicability cannot be set in both the field and attribute
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct InvalidApplicability {
-    #[suggestion(message = "bar", code = "...", applicability = "batman")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
     //~^ ERROR invalid applicability
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ValidApplicability {
-    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct NoApplicability {
-    #[suggestion(message = "bar", code = "...")]
+    #[suggestion(typeck::suggestion, code = "...")]
     suggestion: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "note")]
+#[note(parser::add_paren)]
 struct Note;
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "subdiagnostic")]
+#[error(typeck::ambiguous_lifetime_bound)]
 struct Subdiagnostic {
     #[subdiagnostic]
     note: Note,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct VecField {
     #[primary_span]
     #[label]
@@ -480,23 +489,47 @@ struct VecField {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct UnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: (),
-    #[help = "a"]
+    #[help(typeck::help)]
     bar: (),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct OptUnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: Option<()>,
-    #[help = "a"]
+    #[help(typeck::help)]
     bar: Option<()>,
 }
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingPath {
+    #[label(typeck::label, foo)]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingNameValue {
+    #[label(typeck::label, foo = "...")]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingList {
+    #[label(typeck::label, foo("..."))]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 85ea44ec278..0d9690e1f5a 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: `#[derive(SessionDiagnostic)]` can only be used on structs
   --> $DIR/diagnostic-derive.rs:37:1
    |
-LL | / #[error(code = "E0123", slug = "foo")]
+LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
 LL | | enum SessionDiagnosticOnEnum {
 LL | |     Foo,
@@ -18,15 +18,15 @@ LL | #[error = "E0123"]
 error: `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:51:1
    |
-LL | #[nonsense(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: only `error` and `warning` are valid attributes
+   = help: only `error`, `warning`, `help` and `note` are valid attributes
 
 error: diagnostic kind not specified
   --> $DIR/diagnostic-derive.rs:51:1
    |
-LL | / #[nonsense(code = "E0123", slug = "foo")]
+LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -40,8 +40,10 @@ error: `#[error("...")]` is not a valid attribute
    |
 LL | #[error("E0123")]
    |         ^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `slug` not specified
+error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:58:1
    |
 LL | / #[error("E0123")]
@@ -50,183 +52,215 @@ LL | |
 LL | | struct InvalidLitNestedAttr {}
    | |______________________________^
    |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
-
-error: `#[error(nonsense)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:64:9
-   |
-LL | #[error(nonsense, code = "E0123", slug = "foo")]
-   |         ^^^^^^^^
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense(...))]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:69:9
    |
 LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:69:1
+   |
+LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr1 {}
+   | |__________________________________^
+   |
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:74:9
+  --> $DIR/diagnostic-derive.rs:75:9
    |
 LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^^
    |
-   = help: only `slug` and `code` are valid nested attributes
+   = help: first argument of the attribute should be the diagnostic slug
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:75:1
+   |
+LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr2 {}
+   | |__________________________________^
+   |
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:79:9
+  --> $DIR/diagnostic-derive.rs:81:9
    |
 LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:86:5
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:81:1
    |
-LL |     #[suggestion = "bar"]
-   |     ^^^^^^^^^^^^^^^^^^^^^
+LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr3 {}
+   | |__________________________________^
    |
-   = help: only `label`, `note` and `help` are valid field attributes
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
-error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:1
+error: `#[error(slug = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:87:59
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
+   |                                                           ^^^^^^^^^^^^
    |
-note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:1
+   = help: only `code` is a valid nested attributes following the slug
+
+error: `#[suggestion = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:94:5
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion = "bar"]
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:16
+  --> $DIR/diagnostic-derive.rs:101:1
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:16
+  --> $DIR/diagnostic-derive.rs:100:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:32
+  --> $DIR/diagnostic-derive.rs:101:1
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:32
+  --> $DIR/diagnostic-derive.rs:100:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:1
+  --> $DIR/diagnostic-derive.rs:101:50
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   |                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:1
+  --> $DIR/diagnostic-derive.rs:100:50
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:18
+  --> $DIR/diagnostic-derive.rs:109:1
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   |                  ^^^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:16
+  --> $DIR/diagnostic-derive.rs:108:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:34
+  --> $DIR/diagnostic-derive.rs:109:1
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   |                                  ^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:32
+  --> $DIR/diagnostic-derive.rs:108:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:108:32
+  --> $DIR/diagnostic-derive.rs:109:52
    |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                                ^^^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   |                                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:16
+  --> $DIR/diagnostic-derive.rs:108:50
    |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:113:46
+  --> $DIR/diagnostic-derive.rs:116:66
    |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                              ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
+   |                                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:113:32
+  --> $DIR/diagnostic-derive.rs:116:50
    |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                ^^^^^
+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:121:43
+   |
+LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:118:1
+  --> $DIR/diagnostic-derive.rs:126:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use the `#[error(...)]` attribute to create an error
 
-error: `slug` not specified
-  --> $DIR/diagnostic-derive.rs:121:1
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:129:1
    |
 LL | / #[error(code = "E0456")]
+LL | |
 LL | | struct SlugNotProvided {}
    | |_________________________^
    |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:131:5
+  --> $DIR/diagnostic-derive.rs:140:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:139:5
+  --> $DIR/diagnostic-derive.rs:148:5
    |
 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`
-  --> $DIR/diagnostic-derive.rs:156:5
+error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:165:5
    |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:164:42
+  --> $DIR/diagnostic-derive.rs:173:45
    |
-LL |     #[suggestion(message = "bar", code = "{name}")]
-   |                                          ^^^^^^^^
+LL |     #[suggestion(typeck::suggestion, code = "{name}")]
+   |                                             ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:169:16
+  --> $DIR/diagnostic-derive.rs:178:16
    |
 LL | #[derive(SessionDiagnostic)]
    |           -    ^ expected `'}'` in format string
@@ -237,7 +271,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:179:15
+  --> $DIR/diagnostic-derive.rs:188:15
    |
 LL | #[derive(SessionDiagnostic)]
    |               ^ unmatched `}` in format string
@@ -245,14 +279,14 @@ LL | #[derive(SessionDiagnostic)]
    = note: if you intended to print `}`, you can escape it using `}}`
    = 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:199:5
+error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:208:5
    |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:224:18
+  --> $DIR/diagnostic-derive.rs:233:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -260,7 +294,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:232:18
+  --> $DIR/diagnostic-derive.rs:241:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -268,9 +302,9 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:254:5
+  --> $DIR/diagnostic-derive.rs:263:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: Applicability,
    | |_____________________________^
@@ -278,55 +312,77 @@ 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:269:5
+  --> $DIR/diagnostic-derive.rs:278:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:277:5
+  --> $DIR/diagnostic-derive.rs:286:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
-error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:285:5
-   |
-LL |     #[label("bar")]
-   |     ^^^^^^^^^^^^^^^
+error: `#[label = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:294:5
    |
-   = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes
+LL |     #[label = "bar"]
+   |     ^^^^^^^^^^^^^^^^
 
 error: applicability cannot be set in both the field and attribute
-  --> $DIR/diagnostic-derive.rs:436:49
+  --> $DIR/diagnostic-derive.rs:445:52
    |
-LL |     #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:444:49
+  --> $DIR/diagnostic-derive.rs:453:52
+   |
+LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:516:5
+   |
+LL |     #[label(typeck::label, foo)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:524:5
+   |
+LL |     #[label(typeck::label, foo = "...")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:532:5
    |
-LL |     #[suggestion(message = "bar", code = "...", applicability = "batman")]
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label, foo("..."))]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:51:3
    |
-LL | #[nonsense(code = "E0123", slug = "foo")]
+LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:139:7
+  --> $DIR/diagnostic-derive.rs:148:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
+error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
+  --> $DIR/diagnostic-derive.rs:64:9
+   |
+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:329:10
+  --> $DIR/diagnostic-derive.rs:338:10
    |
 LL | #[derive(SessionDiagnostic)]
    |          ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
@@ -345,6 +401,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 39 previous errors
+error: aborting due to 46 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0425.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index bb406c35c0e..6f4b6105b3e 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -20,7 +20,7 @@ use rustc_span::Span;
 use rustc_macros::SessionSubdiagnostic;
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-a")]
+#[label(parser::add_paren)]
 struct A {
     #[primary_span]
     span: Span,
@@ -29,13 +29,13 @@ struct A {
 
 #[derive(SessionSubdiagnostic)]
 enum B {
-    #[label(slug = "label-b-a")]
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
         var: String,
     },
-    #[label(slug = "label-b-b")]
+    #[label(parser::add_paren)]
     B {
         #[primary_span]
         span: Span,
@@ -44,7 +44,7 @@ enum B {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-c")]
+#[label(parser::add_paren)]
 //~^ ERROR label without `#[primary_span]` field
 struct C {
     var: String,
@@ -116,7 +116,8 @@ struct K {
 
 #[derive(SessionSubdiagnostic)]
 #[label(slug)]
-//~^ ERROR `#[label(slug)]` is not a valid attribute
+//~^ ERROR cannot find value `slug` in module `rustc_errors::fluent`
+//~^^ NOTE not found in `rustc_errors::fluent`
 struct L {
     #[primary_span]
     span: Span,
@@ -125,7 +126,7 @@ struct L {
 
 #[derive(SessionSubdiagnostic)]
 #[label()]
-//~^ ERROR `slug` must be set in a `#[label(...)]` attribute
+//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
 struct M {
     #[primary_span]
     span: Span,
@@ -133,7 +134,7 @@ struct M {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(code = "...")]
+#[label(parser::add_paren, code = "...")]
 //~^ ERROR `code` is not a valid nested attribute of a `label` attribute
 struct N {
     #[primary_span]
@@ -142,11 +143,20 @@ struct N {
 }
 
 #[derive(SessionSubdiagnostic)]
+#[label(parser::add_paren, applicability = "machine-applicable")]
+//~^ ERROR `applicability` is not a valid nested attribute of a `label` attribute
+struct O {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
 #[foo]
 //~^ ERROR cannot find attribute `foo` in this scope
 //~^^ ERROR unsupported type attribute for subdiagnostic enum
-enum O {
-    #[label(slug = "...")]
+enum P {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -155,7 +165,7 @@ enum O {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum P {
+enum Q {
     #[bar]
 //~^ ERROR `#[bar]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -167,7 +177,7 @@ enum P {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum Q {
+enum R {
     #[bar = "..."]
 //~^ ERROR `#[bar = ...]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -179,7 +189,7 @@ enum Q {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum R {
+enum S {
     #[bar = 4]
 //~^ ERROR `#[bar = ...]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -191,7 +201,7 @@ enum R {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum S {
+enum T {
     #[bar("...")]
 //~^ ERROR `#[bar("...")]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -203,9 +213,9 @@ enum S {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum T {
+enum U {
     #[label(code = "...")]
-//~^ ERROR `code` is not a valid nested attribute of a `label`
+//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
     A {
         #[primary_span]
         span: Span,
@@ -214,8 +224,8 @@ enum T {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum U {
-    #[label(slug = "label-u")]
+enum V {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -230,17 +240,17 @@ enum U {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
+#[label(parser::add_paren)]
 //~^ ERROR label without `#[primary_span]` field
-struct V {
+struct W {
     #[primary_span]
     //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span`
     span: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct W {
+#[label(parser::add_paren)]
+struct X {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -249,8 +259,8 @@ struct W {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct X {
+#[label(parser::add_paren)]
+struct Y {
     #[primary_span]
     span: Span,
     #[bar]
@@ -260,8 +270,8 @@ struct X {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct Y {
+#[label(parser::add_paren)]
+struct Z {
     #[primary_span]
     span: Span,
     #[bar = "..."]
@@ -271,8 +281,8 @@ struct Y {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct Z {
+#[label(parser::add_paren)]
+struct AA {
     #[primary_span]
     span: Span,
     #[bar("...")]
@@ -282,8 +292,8 @@ struct Z {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-aa")]
-struct AA {
+#[label(parser::add_paren)]
+struct AB {
     #[primary_span]
     span: Span,
     #[skip_arg]
@@ -291,36 +301,35 @@ struct AA {
 }
 
 #[derive(SessionSubdiagnostic)]
-union AB {
+union AC {
 //~^ ERROR unexpected unsupported untagged union
     span: u32,
     b: u64
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ac-1")]
+#[label(parser::add_paren)]
 //~^ NOTE previously specified here
 //~^^ NOTE previously specified here
-#[label(slug = "label-ac-2")]
+#[label(parser::add_paren)]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
-struct AC {
+struct AD {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ad-1", slug = "label-ad-2")]
-//~^ ERROR specified multiple times
-//~^^ NOTE previously specified here
-struct AD {
+#[label(parser::add_paren, parser::add_paren)]
+//~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute
+struct AE {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ad-1")]
-struct AE {
+#[label(parser::add_paren)]
+struct AF {
     #[primary_span]
 //~^ NOTE previously specified here
     span_a: Span,
@@ -330,15 +339,15 @@ struct AE {
 }
 
 #[derive(SessionSubdiagnostic)]
-struct AF {
+struct AG {
 //~^ ERROR subdiagnostic kind not specified
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "suggestion-af", code = "...")]
-struct AG {
+#[suggestion(parser::add_paren, code = "...")]
+struct AH {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -347,8 +356,8 @@ struct AG {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AH {
-    #[suggestion(slug = "suggestion-ag-a", code = "...")]
+enum AI {
+    #[suggestion(parser::add_paren, code = "...")]
     A {
         #[primary_span]
         span: Span,
@@ -356,7 +365,7 @@ enum AH {
         applicability: Applicability,
         var: String,
     },
-    #[suggestion(slug = "suggestion-ag-b", code = "...")]
+    #[suggestion(parser::add_paren, code = "...")]
     B {
         #[primary_span]
         span: Span,
@@ -367,10 +376,10 @@ enum AH {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...", code = "...")]
 //~^ ERROR specified multiple times
 //~^^ NOTE previously specified here
-struct AI {
+struct AJ {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -378,8 +387,8 @@ struct AI {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
-struct AJ {
+#[suggestion(parser::add_paren, code = "...")]
+struct AK {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -391,9 +400,9 @@ struct AJ {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
-struct AK {
+struct AL {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -402,17 +411,17 @@ struct AK {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
-struct AL {
+struct AM {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...")]
+#[suggestion(parser::add_paren)]
 //~^ ERROR suggestion without `code = "..."`
-struct AM {
+struct AN {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -420,34 +429,34 @@ struct AM {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="...", applicability = "foo")]
+#[suggestion(parser::add_paren, code ="...", applicability = "foo")]
 //~^ ERROR invalid applicability
-struct AN {
+struct AO {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[help(slug = "label-am")]
-struct AO {
+#[help(parser::add_paren)]
+struct AP {
     var: String
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "label-an")]
-struct AP;
+#[note(parser::add_paren)]
+struct AQ;
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
 //~^^ ERROR suggestion without `#[primary_span]` field
-struct AQ {
+struct AR {
     var: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="...", applicability = "machine-applicable")]
-struct AR {
+#[suggestion(parser::add_paren, code ="...", applicability = "machine-applicable")]
+struct AS {
     #[primary_span]
     span: Span,
 }
@@ -455,8 +464,8 @@ struct AR {
 #[derive(SessionSubdiagnostic)]
 #[label]
 //~^ ERROR unsupported type attribute for subdiagnostic enum
-enum AS {
-    #[label(slug = "...")]
+enum AT {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -465,24 +474,24 @@ enum AS {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-struct AT {
+#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+struct AU {
     #[primary_span]
     span: Span,
     var: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
-struct AU {
+struct AV {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AV {
-    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+enum AW {
+    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
     A {
         #[primary_span]
         span: Span,
@@ -491,8 +500,8 @@ enum AV {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AW {
-    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+enum AX {
+    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
     A {
         #[primary_span]
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 4984cc4b318..f833bd210f7 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:47:1
    |
-LL | / #[label(slug = "label-c")]
+LL | / #[label(parser::add_paren)]
 LL | |
 LL | | struct C {
 LL | |     var: String,
@@ -32,98 +32,106 @@ error: `#[label(bug = ...)]` is not a valid attribute
 LL | #[label(bug = "...")]
    |         ^^^^^^^^^^^
    |
-   = help: only `code`, `slug` and `applicability` are valid nested attributes
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label("...")]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:91:9
    |
 LL | #[label("...")]
    |         ^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label(slug = ...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:100:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label(slug(...))]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:109:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^^^^^^^^
-
-error: `#[label(slug)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:118:9
    |
-LL | #[label(slug)]
-   |         ^^^^
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `slug` must be set in a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:127:1
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:128:1
    |
 LL | #[label()]
    | ^^^^^^^^^^
 
 error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:136:1
+  --> $DIR/subdiagnostic-derive.rs:137:1
+   |
+LL | #[label(parser::add_paren, code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `applicability` is not a valid nested attribute of a `label` attribute
+  --> $DIR/subdiagnostic-derive.rs:146:1
    |
-LL | #[label(code = "...")]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren, applicability = "machine-applicable")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:145:1
+  --> $DIR/subdiagnostic-derive.rs:155:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:159:5
+  --> $DIR/subdiagnostic-derive.rs:169:5
    |
 LL |     #[bar]
    |     ^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:171:5
+  --> $DIR/subdiagnostic-derive.rs:181:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:183:5
+  --> $DIR/subdiagnostic-derive.rs:193:5
    |
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
 error: `#[bar("...")]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:195:11
+  --> $DIR/subdiagnostic-derive.rs:205:11
    |
 LL |     #[bar("...")]
    |           ^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:207:5
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:217:5
    |
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:224:5
+  --> $DIR/subdiagnostic-derive.rs:234:5
    |
 LL |     B {
    |     ^
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/subdiagnostic-derive.rs:236:5
+  --> $DIR/subdiagnostic-derive.rs:246:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:233:1
+  --> $DIR/subdiagnostic-derive.rs:243:1
    |
-LL | / #[label(slug = "...")]
+LL | / #[label(parser::add_paren)]
 LL | |
-LL | | struct V {
+LL | | struct W {
 LL | |     #[primary_span]
 LL | |
 LL | |     span: String,
@@ -131,13 +139,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:246:5
+  --> $DIR/subdiagnostic-derive.rs:256:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:256:5
+  --> $DIR/subdiagnostic-derive.rs:266:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -145,21 +153,21 @@ LL |     #[bar]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:267:5
+  --> $DIR/subdiagnostic-derive.rs:277:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:278:5
+  --> $DIR/subdiagnostic-derive.rs:288:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:294:1
+  --> $DIR/subdiagnostic-derive.rs:304:1
    |
-LL | / union AB {
+LL | / union AC {
 LL | |
 LL | |     span: u32,
 LL | |     b: u64
@@ -167,95 +175,91 @@ LL | | }
    | |_^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:304:9
+  --> $DIR/subdiagnostic-derive.rs:314:1
    |
-LL | #[label(slug = "label-ac-2")]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:301:9
+  --> $DIR/subdiagnostic-derive.rs:311:1
    |
-LL | #[label(slug = "label-ac-1")]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:304:1
+  --> $DIR/subdiagnostic-derive.rs:314:1
    |
-LL | #[label(slug = "label-ac-2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:301:1
+  --> $DIR/subdiagnostic-derive.rs:311:1
    |
-LL | #[label(slug = "label-ac-1")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:313:30
+error: `#[label(parser::add_paren)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:323:28
    |
-LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren, parser::add_paren)]
+   |                            ^^^^^^^^^^^^^^^^^
    |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:313:9
-   |
-LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
-   |         ^^^^^^^^^^^^^^^^^^^
+   = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:327:5
+  --> $DIR/subdiagnostic-derive.rs:336:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:324:5
+  --> $DIR/subdiagnostic-derive.rs:333:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:333:8
+  --> $DIR/subdiagnostic-derive.rs:342:8
    |
-LL | struct AF {
+LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:370:42
+  --> $DIR/subdiagnostic-derive.rs:379:47
    |
-LL | #[suggestion(slug = "...", code = "...", code = "...")]
-   |                                          ^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
+   |                                               ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:370:28
+  --> $DIR/subdiagnostic-derive.rs:379:33
    |
-LL | #[suggestion(slug = "...", code = "...", code = "...")]
-   |                            ^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
+   |                                 ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:388:5
+  --> $DIR/subdiagnostic-derive.rs:397:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:385:5
+  --> $DIR/subdiagnostic-derive.rs:394:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:399:5
+  --> $DIR/subdiagnostic-derive.rs:408:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:394:1
+  --> $DIR/subdiagnostic-derive.rs:403:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AK {
+LL | | struct AL {
 LL | |     #[primary_span]
 ...  |
 LL | |     applicability: Span,
@@ -263,22 +267,22 @@ LL | | }
    | |_^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:405:1
+  --> $DIR/subdiagnostic-derive.rs:414:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AL {
+LL | | struct AM {
 LL | |     #[primary_span]
 LL | |     span: Span,
 LL | | }
    | |_^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:413:1
+  --> $DIR/subdiagnostic-derive.rs:422:1
    |
-LL | / #[suggestion(slug = "...")]
+LL | / #[suggestion(parser::add_paren)]
 LL | |
-LL | | struct AM {
+LL | | struct AN {
 LL | |     #[primary_span]
 ...  |
 LL | |     applicability: Applicability,
@@ -286,50 +290,50 @@ LL | | }
    | |_^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:423:41
+  --> $DIR/subdiagnostic-derive.rs:432:46
    |
-LL | #[suggestion(slug = "...", code ="...", applicability = "foo")]
-   |                                         ^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:441:1
+  --> $DIR/subdiagnostic-derive.rs:450:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
 LL | |
-LL | | struct AQ {
+LL | | struct AR {
 LL | |     var: String,
 LL | | }
    | |_^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:441:1
+  --> $DIR/subdiagnostic-derive.rs:450:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
 LL | |
-LL | | struct AQ {
+LL | | struct AR {
 LL | |     var: String,
 LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:456:1
+  --> $DIR/subdiagnostic-derive.rs:465:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:476:34
+  --> $DIR/subdiagnostic-derive.rs:485:39
    |
-LL | #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-   |                                  ^^^^^^^
+LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                       ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:495:38
+  --> $DIR/subdiagnostic-derive.rs:504:43
    |
-LL |     #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-   |                                      ^^^^^^^
+LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                           ^^^^^^^
 
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
@@ -338,52 +342,59 @@ LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:145:3
+  --> $DIR/subdiagnostic-derive.rs:155:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:159:7
+  --> $DIR/subdiagnostic-derive.rs:169:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:171:7
+  --> $DIR/subdiagnostic-derive.rs:181:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:183:7
+  --> $DIR/subdiagnostic-derive.rs:193:7
    |
 LL |     #[bar = 4]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:195:7
+  --> $DIR/subdiagnostic-derive.rs:205:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:256:7
+  --> $DIR/subdiagnostic-derive.rs:266:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:267:7
+  --> $DIR/subdiagnostic-derive.rs:277:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:278:7
+  --> $DIR/subdiagnostic-derive.rs:288:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
-error: aborting due to 51 previous errors
+error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
+  --> $DIR/subdiagnostic-derive.rs:118:9
+   |
+LL | #[label(slug)]
+   |         ^^^^ not found in `rustc_errors::fluent`
+
+error: aborting due to 52 previous errors
 
+For more information about this error, try `rustc --explain E0425`.