about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs216
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs2
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr80
3 files changed, 154 insertions, 144 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 8b40e295bd8..dce5d3cfb84 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -211,11 +211,39 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
     }
 }
 
+/// Provides frequently-needed information about the diagnostic kinds being derived for this type.
+#[derive(Clone, Copy, Debug)]
+struct KindsStatistics {
+    has_multipart_suggestion: bool,
+    all_multipart_suggestions: bool,
+    has_normal_suggestion: bool,
+}
+
+impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
+    fn from_iter<T: IntoIterator<Item = &'a SubdiagnosticKind>>(kinds: T) -> Self {
+        let mut ret = Self {
+            has_multipart_suggestion: false,
+            all_multipart_suggestions: true,
+            has_normal_suggestion: false,
+        };
+        for kind in kinds {
+            if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
+                ret.has_multipart_suggestion = true;
+            } else {
+                ret.all_multipart_suggestions = false;
+            }
+
+            if let SubdiagnosticKind::Suggestion { .. } = kind {
+                ret.has_normal_suggestion = true;
+            }
+        }
+        ret
+    }
+}
+
 impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
-    fn identify_kind(
-        &mut self,
-    ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
-        let mut kind_slug = None;
+    fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+        let mut kind_slugs = vec![];
 
         for attr in self.variant.ast().attrs {
             let span = attr.span().unwrap();
@@ -362,10 +390,10 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                 | SubdiagnosticKind::MultipartSuggestion { .. } => {}
             }
 
-            kind_slug.set_once(((kind, slug), span))
+            kind_slugs.push((kind, slug))
         }
 
-        Ok(kind_slug.map(|(kind_slug, _)| kind_slug))
+        Ok(kind_slugs)
     }
 
     /// Generates the code for a field with no attributes.
@@ -387,7 +415,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
     fn generate_field_attr_code(
         &mut self,
         binding: &BindingInfo<'_>,
-        kind: &SubdiagnosticKind,
+        kind_stats: KindsStatistics,
     ) -> TokenStream {
         let ast = binding.ast();
         assert!(ast.attrs.len() > 0, "field without attributes generating attr code");
@@ -405,7 +433,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                 };
 
                 let generated = self
-                    .generate_field_code_inner(kind, attr, info)
+                    .generate_field_code_inner(kind_stats, attr, info)
                     .unwrap_or_else(|v| v.to_compile_error());
 
                 inner_ty.with(binding, generated)
@@ -415,15 +443,15 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
 
     fn generate_field_code_inner(
         &mut self,
-        kind: &SubdiagnosticKind,
+        kind_stats: KindsStatistics,
         attr: &Attribute,
         info: FieldInfo<'_>,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let meta = attr.parse_meta()?;
         match meta {
-            Meta::Path(path) => self.generate_field_code_inner_path(kind, attr, info, path),
+            Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
             Meta::List(list @ MetaList { .. }) => {
-                self.generate_field_code_inner_list(kind, attr, info, list)
+                self.generate_field_code_inner_list(kind_stats, attr, info, list)
             }
             _ => throw_invalid_attr!(attr, &meta),
         }
@@ -432,7 +460,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
     /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`).
     fn generate_field_code_inner_path(
         &mut self,
-        kind: &SubdiagnosticKind,
+        kind_stats: KindsStatistics,
         attr: &Attribute,
         info: FieldInfo<'_>,
         path: Path,
@@ -445,7 +473,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         match name {
             "skip_arg" => Ok(quote! {}),
             "primary_span" => {
-                if matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) {
+                if kind_stats.has_multipart_suggestion {
                     throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
                         diag.help(
                             "multipart suggestions use one or more `#[suggestion_part]`s rather \
@@ -464,32 +492,20 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
             "suggestion_part" => {
                 self.has_suggestion_parts = true;
 
-                match kind {
-                    SubdiagnosticKind::MultipartSuggestion { .. } => {
-                        span_err(
-                            span,
-                            "`#[suggestion_part(...)]` attribute without `code = \"...\"`",
-                        )
+                if kind_stats.has_multipart_suggestion {
+                    span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
                         .emit();
-                        Ok(quote! {})
-                    }
-                    SubdiagnosticKind::Label
-                    | SubdiagnosticKind::Note
-                    | SubdiagnosticKind::Help
-                    | SubdiagnosticKind::Warn
-                    | SubdiagnosticKind::Suggestion { .. } => {
-                        throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
-                            diag.help(
+                    Ok(quote! {})
+                } else {
+                    throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+                        diag.help(
                                 "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
                             )
-                        });
-                    }
+                    });
                 }
             }
             "applicability" => {
-                if let SubdiagnosticKind::Suggestion { .. }
-                | SubdiagnosticKind::MultipartSuggestion { .. } = kind
-                {
+                if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion {
                     report_error_if_not_applied_to_applicability(attr, &info)?;
 
                     let binding = info.binding.binding.clone();
@@ -501,13 +517,16 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                 Ok(quote! {})
             }
             _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
-                let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
-                    "suggestion_part"
-                } else {
-                    "primary_span"
-                };
+                let mut span_attrs = vec![];
+                if kind_stats.has_multipart_suggestion {
+                    span_attrs.push("suggestion_part");
+                }
+                if !kind_stats.all_multipart_suggestions {
+                    span_attrs.push("primary_span")
+                }
                 diag.help(format!(
-                    "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes",
+                    "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+                    span_attrs.join(", ")
                 ))
             }),
         }
@@ -517,7 +536,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
     /// `#[suggestion_part(code = "...")]`).
     fn generate_field_code_inner_list(
         &mut self,
-        kind: &SubdiagnosticKind,
+        kind_stats: KindsStatistics,
         attr: &Attribute,
         info: FieldInfo<'_>,
         list: MetaList,
@@ -529,7 +548,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
 
         match name {
             "suggestion_part" => {
-                if !matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) {
+                if !kind_stats.has_multipart_suggestion {
                     throw_invalid_attr!(attr, &Meta::List(list), |diag| {
                         diag.help(
                             "`#[suggestion_part(...)]` is only valid in multipart suggestions",
@@ -576,35 +595,36 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                 Ok(quote! { suggestions.push((#binding, #code)); })
             }
             _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
-                let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
-                    "suggestion_part"
-                } else {
-                    "primary_span"
-                };
+                let mut span_attrs = vec![];
+                if kind_stats.has_multipart_suggestion {
+                    span_attrs.push("suggestion_part");
+                }
+                if !kind_stats.all_multipart_suggestions {
+                    span_attrs.push("primary_span")
+                }
                 diag.help(format!(
-                    "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes",
+                    "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+                    span_attrs.join(", ")
                 ))
             }),
         }
     }
 
     pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
-        let Some((kind, slug)) = self.identify_kind()? else {
+        let kind_slugs = self.identify_kind()?;
+        if kind_slugs.is_empty() {
             throw_span_err!(
                 self.variant.ast().ident.span().unwrap(),
                 "subdiagnostic kind not specified"
             );
         };
 
-        let init = match &kind {
-            SubdiagnosticKind::Label
-            | SubdiagnosticKind::Note
-            | SubdiagnosticKind::Help
-            | SubdiagnosticKind::Warn
-            | SubdiagnosticKind::Suggestion { .. } => quote! {},
-            SubdiagnosticKind::MultipartSuggestion { .. } => {
-                quote! { let mut suggestions = Vec::new(); }
-            }
+        let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
+
+        let init = if kind_stats.has_multipart_suggestion {
+            quote! { let mut suggestions = Vec::new(); }
+        } else {
+            quote! {}
         };
 
         let attr_args: TokenStream = self
@@ -612,7 +632,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
             .bindings()
             .iter()
             .filter(|binding| !binding.ast().attrs.is_empty())
-            .map(|binding| self.generate_field_attr_code(binding, &kind))
+            .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
         let span_field = self.span_field.as_ref().map(|(span, _)| span);
@@ -622,48 +642,52 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         );
 
         let diag = &self.diag;
-        let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
-        let message = quote! { rustc_errors::fluent::#slug };
-        let call = match kind {
-            SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
-                if let Some(span) = span_field {
-                    let style = suggestion_kind.to_suggestion_style();
-
-                    quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
-                } else {
-                    span_err(self.span, "suggestion without `#[primary_span]` field").emit();
-                    quote! { unreachable!(); }
-                }
-            }
-            SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
-                if !self.has_suggestion_parts {
-                    span_err(
-                        self.span,
-                        "multipart suggestion without any `#[suggestion_part(...)]` fields",
-                    )
-                    .emit();
+        let mut calls = TokenStream::new();
+        for (kind, slug) in kind_slugs {
+            let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
+            let message = quote! { rustc_errors::fluent::#slug };
+            let call = match kind {
+                SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
+                    if let Some(span) = span_field {
+                        let style = suggestion_kind.to_suggestion_style();
+
+                        quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
+                    } else {
+                        span_err(self.span, "suggestion without `#[primary_span]` field").emit();
+                        quote! { unreachable!(); }
+                    }
                 }
+                SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
+                    if !self.has_suggestion_parts {
+                        span_err(
+                            self.span,
+                            "multipart suggestion without any `#[suggestion_part(...)]` fields",
+                        )
+                        .emit();
+                    }
 
-                let style = suggestion_kind.to_suggestion_style();
+                    let style = suggestion_kind.to_suggestion_style();
 
-                quote! { #diag.#name(#message, suggestions, #applicability, #style); }
-            }
-            SubdiagnosticKind::Label => {
-                if let Some(span) = span_field {
-                    quote! { #diag.#name(#span, #message); }
-                } else {
-                    span_err(self.span, "label without `#[primary_span]` field").emit();
-                    quote! { unreachable!(); }
+                    quote! { #diag.#name(#message, suggestions, #applicability, #style); }
                 }
-            }
-            _ => {
-                if let Some(span) = span_field {
-                    quote! { #diag.#name(#span, #message); }
-                } else {
-                    quote! { #diag.#name(#message); }
+                SubdiagnosticKind::Label => {
+                    if let Some(span) = span_field {
+                        quote! { #diag.#name(#span, #message); }
+                    } else {
+                        span_err(self.span, "label without `#[primary_span]` field").emit();
+                        quote! { unreachable!(); }
+                    }
                 }
-            }
-        };
+                _ => {
+                    if let Some(span) = span_field {
+                        quote! { #diag.#name(#span, #message); }
+                    } else {
+                        quote! { #diag.#name(#message); }
+                    }
+                }
+            };
+            calls.extend(call);
+        }
 
         let plain_args: TokenStream = self
             .variant
@@ -676,7 +700,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         Ok(quote! {
             #init
             #attr_args
-            #call
+            #calls
             #plain_args
         })
     }
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index 89eaec78c6f..812ca0c72bd 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -309,9 +309,7 @@ union AC {
 
 #[derive(SessionSubdiagnostic)]
 #[label(parser::add_paren)]
-//~^ NOTE previously specified here
 #[label(parser::add_paren)]
-//~^ ERROR specified multiple times
 struct AD {
     #[primary_span]
     span: Span,
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 75a34f44bbe..0a0247e8980 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -174,20 +174,8 @@ LL | |     b: u64
 LL | | }
    | |_^
 
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:313:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:311:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: `#[label(parser::add_paren)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:321:28
+  --> $DIR/subdiagnostic-derive.rs:319:28
    |
 LL | #[label(parser::add_paren, parser::add_paren)]
    |                            ^^^^^^^^^^^^^^^^^
@@ -195,67 +183,67 @@ LL | #[label(parser::add_paren, parser::add_paren)]
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:334:5
+  --> $DIR/subdiagnostic-derive.rs:332:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:331:5
+  --> $DIR/subdiagnostic-derive.rs:329:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:340:8
+  --> $DIR/subdiagnostic-derive.rs:338:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:377:47
+  --> $DIR/subdiagnostic-derive.rs:375:47
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                               ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:377:33
+  --> $DIR/subdiagnostic-derive.rs:375:33
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                 ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:395:5
+  --> $DIR/subdiagnostic-derive.rs:393:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:392:5
+  --> $DIR/subdiagnostic-derive.rs:390:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:405:5
+  --> $DIR/subdiagnostic-derive.rs:403:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:418:1
+  --> $DIR/subdiagnostic-derive.rs:416:1
    |
 LL | #[suggestion(parser::add_paren)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:428:46
+  --> $DIR/subdiagnostic-derive.rs:426:46
    |
 LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
    |                                              ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:446:1
+  --> $DIR/subdiagnostic-derive.rs:444:1
    |
 LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
@@ -265,25 +253,25 @@ LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:460:1
+  --> $DIR/subdiagnostic-derive.rs:458:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:480:39
+  --> $DIR/subdiagnostic-derive.rs:478:39
    |
 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:499:43
+  --> $DIR/subdiagnostic-derive.rs:497:43
    |
 LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
    |                                           ^^^^^^^
 
 error: `#[suggestion_part]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:522:5
+  --> $DIR/subdiagnostic-derive.rs:520:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
@@ -291,7 +279,7 @@ LL |     #[suggestion_part]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
 error: `#[suggestion_part(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:525:5
+  --> $DIR/subdiagnostic-derive.rs:523:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -299,7 +287,7 @@ LL |     #[suggestion_part(code = "...")]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:519:1
+  --> $DIR/subdiagnostic-derive.rs:517:1
    |
 LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
@@ -311,13 +299,13 @@ LL | | }
    | |_^
 
 error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute
-  --> $DIR/subdiagnostic-derive.rs:534:43
+  --> $DIR/subdiagnostic-derive.rs:532:43
    |
 LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
    |                                           ^^^^^^^^^^^^
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:534:1
+  --> $DIR/subdiagnostic-derive.rs:532:1
    |
 LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
 LL | |
@@ -328,19 +316,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:544:5
+  --> $DIR/subdiagnostic-derive.rs:542:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:552:5
+  --> $DIR/subdiagnostic-derive.rs:550:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:561:5
+  --> $DIR/subdiagnostic-derive.rs:559:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -348,7 +336,7 @@ LL |     #[primary_span]
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:558:1
+  --> $DIR/subdiagnostic-derive.rs:556:1
    |
 LL | / #[multipart_suggestion(parser::add_paren)]
 LL | |
@@ -360,19 +348,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:569:5
+  --> $DIR/subdiagnostic-derive.rs:567:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:572:5
+  --> $DIR/subdiagnostic-derive.rs:570:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(foo = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:575:23
+  --> $DIR/subdiagnostic-derive.rs:573:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^^^^^^^^^
@@ -380,37 +368,37 @@ LL |     #[suggestion_part(foo = "bar")]
    = help: `code` is the only valid nested attribute
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:578:5
+  --> $DIR/subdiagnostic-derive.rs:576:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:581:5
+  --> $DIR/subdiagnostic-derive.rs:579:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:589:37
+  --> $DIR/subdiagnostic-derive.rs:587:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:589:23
+  --> $DIR/subdiagnostic-derive.rs:587:23
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:619:5
+  --> $DIR/subdiagnostic-derive.rs:617:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:616:43
+  --> $DIR/subdiagnostic-derive.rs:614:43
    |
 LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,6 +463,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 64 previous errors
+error: aborting due to 63 previous errors
 
 For more information about this error, try `rustc --explain E0425`.