From d9b874c083936fa14d139fec243f9df0897fdf09 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 1 Sep 2022 20:53:59 +0200 Subject: [PATCH] Allow deriving multiple subdiagnostics using one SessionSubdiagnostic This reimplements ac638c1, which had to be reverted in the previous commit because it contains a rebase accident that itself reverted significant unrelated changes to SessionSubdiagnostic. --- .../src/diagnostics/subdiagnostic.rs | 216 ++++++++++-------- .../subdiagnostic-derive.rs | 2 - .../subdiagnostic-derive.stderr | 80 +++---- 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>(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, DiagnosticDeriveError> { - let mut kind_slug = None; + fn identify_kind(&mut self) -> Result, 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 { 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 { - 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 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(); - quote! { #diag.#name(#span, #message, #code, #applicability, #style); } - } else { - span_err(self.span, "suggestion without `#[primary_span]` field").emit(); - quote! { unreachable!(); } + quote! { #diag.#name(#message, suggestions, #applicability, #style); } } - } - SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { - if !self.has_suggestion_parts { - span_err( - self.span, - "multipart suggestion without any `#[suggestion_part(...)]` fields", - ) - .emit(); + 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!(); } + } } - - 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!(); } + _ => { + if let Some(span) = span_field { + quote! { #diag.#name(#span, #message); } + } else { + quote! { #diag.#name(#message); } + } } - } - _ => { - 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`.