diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 72f20efc8346b..2aa292bbce2b6 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -1,25 +1,23 @@ #![deny(unused_must_use)] +use super::error::throw_invalid_nested_attr; +use super::utils::{SpannedOption, SubdiagnosticKind}; use crate::diagnostics::error::{ - invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, - DiagnosticDeriveError, + invalid_nested_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, }; use crate::diagnostics::utils::{ report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path, - Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, + FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, }; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; use std::collections::HashMap; -use std::str::FromStr; use syn::{ parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type, }; use synstructure::{BindingInfo, Structure}; -use super::utils::SpannedOption; - /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? #[derive(Copy, Clone, PartialEq, Eq)] pub(crate) enum DiagnosticDeriveKind { @@ -45,7 +43,7 @@ pub(crate) struct DiagnosticDeriveBuilder { pub slug: SpannedOption, /// Error codes are a optional part of the struct attribute - this is only set to detect /// multiple specifications. - pub code: SpannedOption, + pub code: SpannedOption<()>, } impl HasFieldMap for DiagnosticDeriveBuilder { @@ -129,6 +127,30 @@ impl DiagnosticDeriveBuilder { || is_subdiagnostic } + fn parse_subdiag_attribute( + &self, + attr: &Attribute, + ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> { + let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?; + + if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag { + let meta = attr.parse_meta()?; + throw_invalid_attr!(attr, &meta, |diag| diag + .help("consider creating a `Subdiagnostic` instead")); + } + + let slug = slug.unwrap_or_else(|| match subdiag { + SubdiagnosticKind::Label => parse_quote! { _subdiag::label }, + SubdiagnosticKind::Note => parse_quote! { _subdiag::note }, + SubdiagnosticKind::Help => parse_quote! { _subdiag::help }, + SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn }, + SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion }, + SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), + }); + + Ok((subdiag, slug)) + } + /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct /// attributes like `#[diag(..)]`, such as the slug and error code. Generates /// diagnostic builder calls for setting error code and creating note/help messages. @@ -137,98 +159,64 @@ impl DiagnosticDeriveBuilder { attr: &Attribute, ) -> Result { let diag = &self.diag; - let span = attr.span().unwrap(); let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); let meta = attr.parse_meta()?; - let is_diag = name == "diag"; - - let nested = match meta { - // Most attributes are lists, like `#[diag(..)]` for most cases or - // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug. - Meta::List(MetaList { ref nested, .. }) => nested, - // Subdiagnostics without spans can be applied to the type too, and these are just - // paths: `#[help]`, `#[note]` and `#[warning]` - Meta::Path(_) if !is_diag => { - let fn_name = if name == "warning" { - Ident::new("warn", attr.span()) - } else { - Ident::new(name, attr.span()) - }; - return Ok(self.add_subdiagnostic(&fn_name, parse_quote! { _subdiag::#fn_name })); - } - _ => throw_invalid_attr!(attr, &meta), - }; - - // Check the kind before doing any further processing so that there aren't misleading - // "no kind specified" errors if there are failures later. - match name { - "error" | "lint" => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("`error` and `lint` have been replaced by `diag`") - }), - "warn_" => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("`warn_` have been replaced by `warning`") - }), - "diag" | "help" | "note" | "warning" => (), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `diag`, `help`, `note` and `warning` are valid attributes") - }), - } + if name == "diag" { + let Meta::List(MetaList { ref nested, .. }) = meta else { + throw_invalid_attr!( + attr, + &meta + ); + }; - // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or - // `#[help(typeck::another_help)]`. - let mut nested_iter = nested.into_iter(); - if let Some(nested_attr) = nested_iter.next() { - // Report an error if there are any other list items after the path. - if !is_diag && nested_iter.next().is_some() { - throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "`help`, `note` and `warning` struct attributes can only have one argument", - ) - }); - } + let mut nested_iter = nested.into_iter().peekable(); - match nested_attr { - NestedMeta::Meta(Meta::Path(path)) => { - if is_diag { - self.slug.set_once(path.clone(), span); - } else { - let fn_name = proc_macro2::Ident::new(name, attr.span()); - return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); - } + match nested_iter.peek() { + Some(NestedMeta::Meta(Meta::Path(slug))) => { + self.slug.set_once(slug.clone(), slug.span().unwrap()); + nested_iter.next(); } - NestedMeta::Meta(meta @ Meta::NameValue(_)) - if is_diag && meta.path().segments.last().unwrap().ident == "code" => - { - // don't error for valid follow-up attributes - } - nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("first argument of the attribute should be the diagnostic slug") - }), + Some(NestedMeta::Meta(Meta::NameValue { .. })) => {} + Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag + .help("a diagnostic slug is required as the first argument")), + None => throw_invalid_attr!(attr, &meta, |diag| diag + .help("a diagnostic slug is required as the first argument")), }; - } - // Remaining attributes are optional, only `code = ".."` at the moment. - let mut tokens = Vec::new(); - for nested_attr in nested_iter { - let meta = match nested_attr { - syn::NestedMeta::Meta(meta) => meta, - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; + // Remaining attributes are optional, only `code = ".."` at the moment. + let mut tokens = TokenStream::new(); + for nested_attr in nested_iter { + let (value, path) = match nested_attr { + NestedMeta::Meta(Meta::NameValue(MetaNameValue { + lit: syn::Lit::Str(value), + path, + .. + })) => (value, path), + NestedMeta::Meta(Meta::Path(_)) => { + invalid_nested_attr(attr, &nested_attr) + .help("diagnostic slug must be the first argument") + .emit(); + continue; + } + _ => { + invalid_nested_attr(attr, &nested_attr).emit(); + continue; + } + }; - let path = meta.path(); - let nested_name = path.segments.last().unwrap().ident.to_string(); - // Struct attributes are only allowed to be applied once, and the diagnostic - // changes will be set in the initialisation code. - if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta { - let span = s.span().unwrap(); + let nested_name = path.segments.last().unwrap().ident.to_string(); + // Struct attributes are only allowed to be applied once, and the diagnostic + // changes will be set in the initialisation code. + let span = value.span().unwrap(); match nested_name.as_str() { "code" => { - self.code.set_once(s.value(), span); - let code = &self.code.value_ref(); - tokens.push(quote! { + self.code.set_once((), span); + + let code = value.value(); + tokens.extend(quote! { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }); } @@ -236,12 +224,22 @@ impl DiagnosticDeriveBuilder { .help("only `code` is a valid nested attributes following the slug") .emit(), } - } else { - invalid_nested_attr(attr, &nested_attr).emit() } + return Ok(tokens); } - Ok(tokens.into_iter().collect()) + let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; + let fn_ident = format_ident!("{}", subdiag); + match subdiag { + SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { + Ok(self.add_subdiagnostic(&fn_ident, slug)) + } + SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => { + throw_invalid_attr!(attr, &meta, |diag| diag + .help("`#[label]` and `#[suggestion]` can only be applied to fields")); + } + SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), + } } fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { @@ -305,217 +303,83 @@ impl DiagnosticDeriveBuilder { info: FieldInfo<'_>, binding: TokenStream, ) -> Result { - let meta = attr.parse_meta()?; - match meta { - Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding), - Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding), - _ => throw_invalid_attr!(attr, &meta), - } - } - - fn generate_inner_field_code_path( - &mut self, - attr: &Attribute, - info: FieldInfo<'_>, - binding: TokenStream, - ) -> Result { - assert!(matches!(attr.parse_meta()?, Meta::Path(_))); let diag = &self.diag; - let meta = attr.parse_meta()?; - let ident = &attr.path.segments.last().unwrap().ident; - let name = ident.to_string(); - let name = name.as_str(); - match name { - "skip_arg" => { - // Don't need to do anything - by virtue of the attribute existing, the - // `set_arg` call will not be generated. - Ok(quote! {}) - } - "primary_span" => { - match self.kind { + if let Meta::Path(_) = meta { + let ident = &attr.path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + match name { + "skip_arg" => { + // Don't need to do anything - by virtue of the attribute existing, the + // `set_arg` call will not be generated. + return Ok(quote! {}); + } + "primary_span" => match self.kind { DiagnosticDeriveKind::Diagnostic => { report_error_if_not_applied_to_span(attr, &info)?; - Ok(quote! { + return Ok(quote! { #diag.set_span(#binding); - }) + }); } DiagnosticDeriveKind::LintDiagnostic => { throw_invalid_attr!(attr, &meta, |diag| { diag.help("the `primary_span` field attribute is not valid for lint diagnostics") }) } - } + }, + "subdiagnostic" => return Ok(quote! { #diag.subdiagnostic(#binding); }), + _ => {} } - "label" => { + } + + let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; + + let fn_ident = format_ident!("{}", subdiag); + match subdiag { + SubdiagnosticKind::Label => { report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label })) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } - "note" | "help" | "warning" => { - let warn_ident = Ident::new("warn", Span::call_site()); - let (ident, path) = match name { - "note" => (ident, parse_quote! { _subdiag::note }), - "help" => (ident, parse_quote! { _subdiag::help }), - "warning" => (&warn_ident, parse_quote! { _subdiag::warn }), - _ => unreachable!(), - }; + SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - Ok(self.add_spanned_subdiagnostic(binding, ident, path)) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } else if type_is_unit(&info.ty) { - Ok(self.add_subdiagnostic(ident, path)) + Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { report_type_error(attr, "`Span` or `()`")? } } - "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help( - "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \ - are valid field attributes", - ) - }), - } - } - - fn generate_inner_field_code_list( - &mut self, - attr: &Attribute, - info: FieldInfo<'_>, - binding: TokenStream, - ) -> Result { - let meta = attr.parse_meta()?; - let Meta::List(MetaList { ref path, ref nested, .. }) = meta else { unreachable!() }; - - let ident = &attr.path.segments.last().unwrap().ident; - let name = path.segments.last().unwrap().ident.to_string(); - let name = name.as_ref(); - match name { - "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => { - return self.generate_inner_field_code_suggestion(attr, info); - } - "label" | "help" | "note" | "warning" => (), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help( - "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \ - valid field attributes", - ) - }), - } - - // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a - // path, e.g. `#[label(typeck::label)]`. - let mut nested_iter = nested.into_iter(); - let msg = match nested_iter.next() { - Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(), - Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr), - None => throw_invalid_attr!(attr, &meta), - }; - - // None of these attributes should have anything following the slug. - if nested_iter.next().is_some() { - throw_invalid_attr!(attr, &meta); - } - - match name { - "label" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) - } - "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => { - Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) - } - "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)), - // `warning` must be special-cased because the attribute `warn` already has meaning and - // so isn't used, despite the diagnostic API being named `warn`. - "warning" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self - .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)), - "warning" if type_is_unit(&info.ty) => { - Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg)) - } - "note" | "help" | "warning" => report_type_error(attr, "`Span` or `()`")?, - _ => unreachable!(), - } - } - - fn generate_inner_field_code_suggestion( - &mut self, - attr: &Attribute, - info: FieldInfo<'_>, - ) -> Result { - let diag = &self.diag; - - let mut meta = attr.parse_meta()?; - let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta else { unreachable!() }; - - let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; - - let mut code = None; - - let mut nested_iter = nested.into_iter().peekable(); - let msg = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() { - let path = path.clone(); - // Move the iterator forward if a path was found (don't otherwise so that - // code/applicability can be found or an error emitted). - nested_iter.next(); - Some(path) - } else { - None - }; - - for nested_attr in nested_iter { - let meta = match nested_attr { - syn::NestedMeta::Meta(ref meta) => meta, - syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let span = meta.span().unwrap(); - match nested_name { - "code" => { - let formatted_str = self.build_format(&s.value(), s.span()); - code.set_once(formatted_str, span); - } - "applicability" => match Applicability::from_str(&s.value()) { - Ok(v) => applicability.set_once(quote! { #v }, span), - Err(()) => { - span_err(span, "invalid applicability").emit(); - } - }, - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "only `message`, `code` and `applicability` are valid field \ - attributes", - ) - }), - } + SubdiagnosticKind::Suggestion { + suggestion_kind, + applicability: static_applicability, + code, + } => { + let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; + + if let Some((static_applicability, span)) = static_applicability { + applicability.set_once(quote! { #static_applicability }, span); } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - if matches!(meta, Meta::Path(_)) { - diag.help("a diagnostic slug must be the first argument to the attribute") - } else { - diag - } - }), + + let applicability = applicability + .value() + .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified }); + let style = suggestion_kind.to_suggestion_style(); + + Ok(quote! { + #diag.span_suggestion_with_style( + #span_field, + rustc_errors::fluent::#slug, + #code, + #applicability, + #style + ); + }) } + SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), } - - let applicability = applicability - .value() - .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); - - let name = path.segments.last().unwrap().ident.to_string(); - let method = format_ident!("span_{}", name); - - let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion }); - let msg = quote! { rustc_errors::fluent::#msg }; - let code = code.value().unwrap_or_else(|| quote! { String::new() }); - - Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) } /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index eb63a7e52e5fd..ad481c14bab8d 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -76,13 +76,15 @@ struct InvalidNestedStructAttr1 {} #[derive(Diagnostic)] #[diag(nonsense = "...", code = "E0123", slug = "foo")] //~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute -//~^^ ERROR diagnostic slug not specified +//~| ERROR `#[diag(slug = ...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr2 {} #[derive(Diagnostic)] #[diag(nonsense = 4, code = "E0123", slug = "foo")] //~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute -//~^^ ERROR diagnostic slug not specified +//~| ERROR `#[diag(slug = ...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified struct InvalidNestedStructAttr3 {} #[derive(Diagnostic)] @@ -217,6 +219,7 @@ struct Suggest { #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithoutCode { #[suggestion(typeck::suggestion)] + //~^ ERROR suggestion without `code = "..."` suggestion: (Span, Applicability), } @@ -225,6 +228,7 @@ struct SuggestWithoutCode { struct SuggestWithBadKey { #[suggestion(nonsense = "bar")] //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute + //~| ERROR suggestion without `code = "..."` suggestion: (Span, Applicability), } @@ -233,6 +237,7 @@ struct SuggestWithBadKey { struct SuggestWithShorthandMsg { #[suggestion(msg = "bar")] //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute + //~| ERROR suggestion without `code = "..."` suggestion: (Span, Applicability), } @@ -507,7 +512,7 @@ struct OptUnitField { #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct LabelWithTrailingPath { #[label(typeck::label, foo)] - //~^ ERROR `#[label(...)]` is not a valid attribute + //~^ ERROR `#[label(foo)]` is not a valid attribute span: Span, } @@ -515,7 +520,7 @@ struct LabelWithTrailingPath { #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct LabelWithTrailingNameValue { #[label(typeck::label, foo = "...")] - //~^ ERROR `#[label(...)]` is not a valid attribute + //~^ ERROR `#[label(foo = ...)]` is not a valid attribute span: Span, } @@ -523,7 +528,7 @@ struct LabelWithTrailingNameValue { #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct LabelWithTrailingList { #[label(typeck::label, foo("..."))] - //~^ ERROR `#[label(...)]` is not a valid attribute + //~^ ERROR `#[label(foo(...))]` is not a valid attribute span: Span, } @@ -605,3 +610,44 @@ struct MissingApplicabilityInSuggestionTuple { suggestion: (Span,), //~^ ERROR wrong types for suggestion } + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct MissingCodeInSuggestion { + #[suggestion(typeck::suggestion)] + //~^ ERROR suggestion without `code = "..."` + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[multipart_suggestion(typeck::suggestion)] +//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute +//~| ERROR cannot find attribute `multipart_suggestion` in this scope +#[multipart_suggestion()] +//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute +//~| ERROR cannot find attribute `multipart_suggestion` in this scope +struct MultipartSuggestion { + #[multipart_suggestion(typeck::suggestion)] + //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute + //~| ERROR cannot find attribute `multipart_suggestion` in this scope + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[suggestion(typeck::suggestion, code = "...")] +//~^ ERROR `#[suggestion(...)]` is not a valid attribute +struct SuggestionOnStruct { + #[primary_span] + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[label] +//~^ ERROR `#[label]` is not a valid attribute +struct LabelOnStruct { + #[primary_span] + suggestion: Span, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f5432b0bf6561..9919b12beaf0a 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -20,8 +20,6 @@ error: `#[nonsense(...)]` is not a valid attribute | LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: only `diag`, `help`, `note` and `warning` are valid attributes error: diagnostic slug not specified --> $DIR/diagnostic-derive.rs:53:1 @@ -41,7 +39,7 @@ error: `#[diag("...")]` is not a valid attribute LL | #[diag("E0123")] | ^^^^^^^ | - = help: first argument of the attribute should be the diagnostic slug + = help: a diagnostic slug is required as the first argument error: diagnostic slug not specified --> $DIR/diagnostic-derive.rs:60:1 @@ -60,7 +58,7 @@ error: `#[diag(nonsense(...))]` is not a valid attribute LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^ | - = help: first argument of the attribute should be the diagnostic slug + = help: a diagnostic slug is required as the first argument error: diagnostic slug not specified --> $DIR/diagnostic-derive.rs:71:1 @@ -79,7 +77,15 @@ error: `#[diag(nonsense = ...)]` is not a valid attribute LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^^ | - = help: first argument of the attribute should be the diagnostic slug + = help: only `code` is a valid nested attributes following the slug + +error: `#[diag(slug = ...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:77:42 + | +LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^ + | + = help: only `code` is a valid nested attributes following the slug error: diagnostic slug not specified --> $DIR/diagnostic-derive.rs:77:1 @@ -87,32 +93,40 @@ error: diagnostic slug not specified LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")] LL | | LL | | +LL | | LL | | struct InvalidNestedStructAttr2 {} | |__________________________________^ | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: `#[diag(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:83:8 + --> $DIR/diagnostic-derive.rs:84:8 | LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] | ^^^^^^^^^^^^ + +error: `#[diag(slug = ...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:84:38 | - = help: first argument of the attribute should be the diagnostic slug +LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^ + | + = help: only `code` is a valid nested attributes following the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:83:1 + --> $DIR/diagnostic-derive.rs:84:1 | LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")] LL | | LL | | +LL | | LL | | struct InvalidNestedStructAttr3 {} | |__________________________________^ | = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: `#[diag(slug = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:89:58 + --> $DIR/diagnostic-derive.rs:91:58 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] | ^^^^^^^^^^^^ @@ -120,55 +134,57 @@ LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] = help: only `code` is a valid nested attributes following the slug error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:96:5 + --> $DIR/diagnostic-derive.rs:98:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:103:1 + --> $DIR/diagnostic-derive.rs:105:8 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:102:1 + --> $DIR/diagnostic-derive.rs:104:8 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:103:49 + --> $DIR/diagnostic-derive.rs:105:49 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:102:49 + --> $DIR/diagnostic-derive.rs:104:49 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:65 + --> $DIR/diagnostic-derive.rs:111:65 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:109:49 + --> $DIR/diagnostic-derive.rs:111:49 | LL | #[diag(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] | ^^^^^^^ error: `#[diag(typeck::ambiguous_lifetime_bound)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:114:42 + --> $DIR/diagnostic-derive.rs:116:42 | LL | #[diag(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: diagnostic slug must be the first argument error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:119:1 + --> $DIR/diagnostic-derive.rs:121:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +192,7 @@ LL | struct KindNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:122:1 + --> $DIR/diagnostic-derive.rs:124:1 | LL | / #[diag(code = "E0456")] LL | | @@ -186,33 +202,31 @@ LL | | struct SlugNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:133:5 + --> $DIR/diagnostic-derive.rs:135:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:141:5 + --> $DIR/diagnostic-derive.rs:143: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` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:158:5 + --> $DIR/diagnostic-derive.rs:160:5 | LL | #[label(typeck::label)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:166:45 + --> $DIR/diagnostic-derive.rs:168:45 | LL | #[suggestion(typeck::suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:171:16 + --> $DIR/diagnostic-derive.rs:173:16 | LL | #[derive(Diagnostic)] | - ^ expected `'}'` in format string @@ -223,7 +237,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:181:15 + --> $DIR/diagnostic-derive.rs:183:15 | LL | #[derive(Diagnostic)] | ^ unmatched `}` in format string @@ -232,29 +246,47 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:201:5 + --> $DIR/diagnostic-derive.rs:203:5 | LL | #[label(typeck::label)] | ^^^^^^^^^^^^^^^^^^^^^^^ +error: suggestion without `code = "..."` + --> $DIR/diagnostic-derive.rs:221:5 + | +LL | #[suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: `#[suggestion(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:226:18 + --> $DIR/diagnostic-derive.rs:229:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^ | - = help: only `message`, `code` and `applicability` are valid field attributes + = help: only `code` and `applicability` are valid nested attributes + +error: suggestion without `code = "..."` + --> $DIR/diagnostic-derive.rs:229:5 + | +LL | #[suggestion(nonsense = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion(msg = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:234:18 + --> $DIR/diagnostic-derive.rs:238:18 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^ | - = help: only `message`, `code` and `applicability` are valid field attributes + = help: only `code` and `applicability` are valid nested attributes + +error: suggestion without `code = "..."` + --> $DIR/diagnostic-derive.rs:238:5 + | +LL | #[suggestion(msg = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:256:5 + --> $DIR/diagnostic-derive.rs:261:5 | LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | @@ -264,73 +296,75 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: specified multiple times - --> $DIR/diagnostic-derive.rs:272:24 + --> $DIR/diagnostic-derive.rs:277:24 | LL | suggestion: (Span, Span, Applicability), | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:272:18 + --> $DIR/diagnostic-derive.rs:277:18 | LL | suggestion: (Span, Span, Applicability), | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:280:33 + --> $DIR/diagnostic-derive.rs:285:33 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:280:18 + --> $DIR/diagnostic-derive.rs:285:18 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ error: `#[label = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:287:5 + --> $DIR/diagnostic-derive.rs:292:5 | LL | #[label = "bar"] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:438:52 + --> $DIR/diagnostic-derive.rs:443:52 | LL | #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:440:24 + --> $DIR/diagnostic-derive.rs:445:24 | LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:446:52 + --> $DIR/diagnostic-derive.rs:451:52 | LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:509:5 +error: `#[label(foo)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:514:28 | LL | #[label(typeck::label, foo)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ + | + = help: a diagnostic slug must be the first argument to the attribute -error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:517:5 +error: `#[label(foo = ...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:522:28 | LL | #[label(typeck::label, foo = "...")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ -error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:525:5 +error: `#[label(foo(...))]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:530:28 | LL | #[label(typeck::label, foo("..."))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:538:5 + --> $DIR/diagnostic-derive.rs:543:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -338,15 +372,13 @@ LL | #[primary_span] = help: the `primary_span` field attribute is not valid for lint diagnostics error: `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:558:1 + --> $DIR/diagnostic-derive.rs:563:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `error` and `lint` have been replaced by `diag` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:558:1 + --> $DIR/diagnostic-derive.rs:563:1 | LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -358,15 +390,13 @@ LL | | struct ErrorAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:565:1 + --> $DIR/diagnostic-derive.rs:570:1 | LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `warn_` have been replaced by `warning` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:565:1 + --> $DIR/diagnostic-derive.rs:570:1 | LL | / #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -378,15 +408,13 @@ LL | | struct WarnAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:572:1 + --> $DIR/diagnostic-derive.rs:577:1 | LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `error` and `lint` have been replaced by `diag` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:572:1 + --> $DIR/diagnostic-derive.rs:577:1 | LL | / #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -398,15 +426,13 @@ LL | | struct LintAttributeOnSessionDiag {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:584:1 | LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `error` and `lint` have been replaced by `diag` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:579:1 + --> $DIR/diagnostic-derive.rs:584:1 | LL | / #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -418,19 +444,19 @@ LL | | struct LintAttributeOnLintDiag {} = help: specify the slug as the first argument to the attribute, such as `#[diag(typeck::example_error)]` error: specified multiple times - --> $DIR/diagnostic-derive.rs:588:52 + --> $DIR/diagnostic-derive.rs:593:52 | LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:588:38 + --> $DIR/diagnostic-derive.rs:593:38 | LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")] | ^^^^^^^^^^^^ error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:597:24 + --> $DIR/diagnostic-derive.rs:602:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -438,13 +464,59 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:605:17 + --> $DIR/diagnostic-derive.rs:610:17 | LL | suggestion: (Span,), | ^^^^^^^ | = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` +error: suggestion without `code = "..."` + --> $DIR/diagnostic-derive.rs:617:5 + | +LL | #[suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[multipart_suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:624:1 + | +LL | #[multipart_suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider creating a `Subdiagnostic` instead + +error: `#[multipart_suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:627:1 + | +LL | #[multipart_suggestion()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider creating a `Subdiagnostic` instead + +error: `#[multipart_suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:631:5 + | +LL | #[multipart_suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider creating a `Subdiagnostic` instead + +error: `#[suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:639:1 + | +LL | #[suggestion(typeck::suggestion, code = "...")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[label]` and `#[suggestion]` can only be applied to fields + +error: `#[label]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:648:1 + | +LL | #[label] + | ^^^^^^^^ + | + = help: `#[label]` and `#[suggestion]` can only be applied to fields + error: cannot find attribute `nonsense` in this scope --> $DIR/diagnostic-derive.rs:53:3 | @@ -452,35 +524,53 @@ LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:141:7 + --> $DIR/diagnostic-derive.rs:143:7 | LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive.rs:558:3 + --> $DIR/diagnostic-derive.rs:563:3 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^ error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive.rs:565:3 + --> $DIR/diagnostic-derive.rs:570:3 | LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^ help: a built-in attribute with a similar name exists: `warn` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:572:3 + --> $DIR/diagnostic-derive.rs:577:3 | LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:579:3 + --> $DIR/diagnostic-derive.rs:584:3 | LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive.rs:624:3 + | +LL | #[multipart_suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive.rs:627:3 + | +LL | #[multipart_suggestion()] + | ^^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive.rs:631:7 + | +LL | #[multipart_suggestion(typeck::suggestion)] + | ^^^^^^^^^^^^^^^^^^^^ + error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent` --> $DIR/diagnostic-derive.rs:66:8 | @@ -488,7 +578,7 @@ LL | #[diag(nonsense, code = "E0123")] | ^^^^^^^^ not found in `rustc_errors::fluent` error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:331:10 + --> $DIR/diagnostic-derive.rs:336:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` @@ -501,7 +591,7 @@ LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 58 previous errors +error: aborting due to 72 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`.