From 99bc97940314176bc6ed38cea11723cc1fd9ee3b Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 23 Jun 2022 14:51:44 +0100 Subject: [PATCH] macros: use typed identifiers in diag derive Using typed identifiers instead of strings with the Fluent identifier enables the diagnostic derive to benefit from the compile-time validation that comes with typed identifiers - use of a non-existent Fluent identifier will not compile. Signed-off-by: David Wood --- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- .../locales/en-US/builtin_macros.ftl | 4 +- .../src/diagnostics/diagnostic.rs | 468 +++++++++++------- .../rustc_macros/src/diagnostics/error.rs | 37 +- .../rustc_macros/src/diagnostics/fluent.rs | 11 + compiler/rustc_macros/src/diagnostics/mod.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 18 +- compiler/rustc_typeck/src/errors.rs | 62 +-- .../ui-fulldeps/internal-lints/diagnostics.rs | 2 +- .../session-diagnostic/diagnostic-derive.rs | 239 +++++---- .../diagnostic-derive.stderr | 311 +++++++----- 11 files changed, 689 insertions(+), 471 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index c75d83bd0a0..aa355150b4f 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -36,7 +36,7 @@ pub fn expand_cfg( } #[derive(SessionDiagnostic)] -#[error(slug = "builtin-macros-requires-cfg-pattern")] +#[error(builtin_macros::requires_cfg_pattern)] struct RequiresCfgPattern { #[primary_span] #[label] @@ -44,7 +44,7 @@ struct RequiresCfgPattern { } #[derive(SessionDiagnostic)] -#[error(slug = "builtin-macros-expected-one-cfg-pattern")] +#[error(builtin_macros::expected_one_cfg_pattern)] struct OneCfgPattern { #[primary_span] span: Span, diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl index 1d3e33c8185..4a42d52f710 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -1,5 +1,5 @@ -builtin-macros-requires-cfg-pattern = +builtin_macros-requires-cfg-pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required -builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern +builtin_macros-expected-one-cfg-pattern = expected 1 cfg-pattern diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 95ee0d4a060..d0c86527189 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -12,7 +12,9 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use std::collections::HashMap; use std::str::FromStr; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type}; +use syn::{ + parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type, +}; use synstructure::{BindingInfo, Structure}; /// The central struct for constructing the `into_diagnostic` method from an annotated struct. @@ -118,23 +120,23 @@ impl<'a> SessionDiagnosticDerive<'a> { return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); } (Some((kind, _)), None) => { - span_err(span, "`slug` not specified") - .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr())) + span_err(span, "diagnostic slug not specified") + .help(&format!( + "specify the slug as the first argument to the attribute, such as \ + `#[{}(typeck::example_error)]`", + kind.descr() + )) .emit(); return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); } (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => { quote! { - let mut #diag = #sess.struct_err( - rustc_errors::DiagnosticMessage::new(#slug), - ); + let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug); } } (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => { quote! { - let mut #diag = #sess.struct_warn( - rustc_errors::DiagnosticMessage::new(#slug), - ); + let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug); } } }; @@ -226,7 +228,7 @@ struct SessionDiagnosticDeriveBuilder { kind: Option<(SessionDiagnosticKind, proc_macro::Span)>, /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that /// has the actual diagnostic message. - slug: Option<(String, proc_macro::Span)>, + slug: Option<(Path, proc_macro::Span)>, /// Error codes are a optional part of the struct attribute - this is only set to detect /// multiple specifications. code: Option<(String, proc_macro::Span)>, @@ -240,50 +242,79 @@ impl HasFieldMap for SessionDiagnosticDeriveBuilder { impl SessionDiagnosticDeriveBuilder { /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct - /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates + /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates /// diagnostic builder calls for setting error code and creating note/help messages. fn generate_structure_code( &mut self, 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()?; - if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) { - let diag = &self.diag; - let id = match meta { - Meta::Path(..) => quote! { #name }, - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - quote! { #s } - } - _ => unreachable!(), - }; - let fn_name = proc_macro2::Ident::new(name, attr.span()); - - return Ok(quote! { - #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id)); - }); - } + let is_help_or_note = matches!(name, "help" | "note"); let nested = match meta { + // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or + // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug. Meta::List(MetaList { ref nested, .. }) => nested, + // Subdiagnostics without spans can be applied to the type too, and these are just + // paths: `#[help]` and `#[note]` + Meta::Path(_) if is_help_or_note => { + let fn_name = proc_macro2::Ident::new(name, attr.span()); + return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); }); + } _ => throw_invalid_attr!(attr, &meta), }; - let kind = match name { - "error" => SessionDiagnosticKind::Error, - "warning" => SessionDiagnosticKind::Warn, + // Check the kind before doing any further processing so that there aren't misleading + // "no kind specified" errors if there are failures later. + match name { + "error" => self.kind.set_once((SessionDiagnosticKind::Error, span)), + "warning" => self.kind.set_once((SessionDiagnosticKind::Warn, span)), + "help" | "note" => (), _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `error` and `warning` are valid attributes") + diag.help("only `error`, `warning`, `help` and `note` are valid attributes") }), - }; - self.kind.set_once((kind, span)); + } + // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or + // `#[help(typeck::another_help)]`. + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + // Report an error if there are any other list items after the path. + if is_help_or_note && nested_iter.next().is_some() { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("`help` and `note` struct attributes can only have one argument") + }); + } + + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => { + let fn_name = proc_macro2::Ident::new(name, attr.span()); + return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); + } + NestedMeta::Meta(Meta::Path(path)) => { + self.slug.set_once((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if !is_help_or_note + && meta.path().segments.last().unwrap().ident.to_string() == "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") + }), + }; + } + + // Remaining attributes are optional, only `code = ".."` at the moment. let mut tokens = Vec::new(); - for nested_attr in nested { + for nested_attr in nested_iter { let meta = match nested_attr { syn::NestedMeta::Meta(meta) => meta, _ => throw_invalid_nested_attr!(attr, &nested_attr), @@ -291,28 +322,24 @@ impl SessionDiagnosticDeriveBuilder { let path = meta.path(); let nested_name = path.segments.last().unwrap().ident.to_string(); - match &meta { - // Struct attributes are only allowed to be applied once, and the diagnostic - // changes will be set in the initialisation code. - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let span = s.span().unwrap(); - match nested_name.as_str() { - "slug" => { - self.slug.set_once((s.value(), span)); - } - "code" => { - self.code.set_once((s.value(), span)); - let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v)); - tokens.push(quote! { - #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); - }); - } - _ => invalid_nested_attr(attr, &nested_attr) - .help("only `slug` and `code` are valid nested attributes") - .emit(), + // 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(); + match nested_name.as_str() { + "code" => { + self.code.set_once((s.value(), span)); + let code = &self.code.as_ref().map(|(v, _)| v); + tokens.push(quote! { + #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); + }); } + _ => invalid_nested_attr(attr, &nested_attr) + .help("only `code` is a valid nested attributes following the slug") + .emit(), } - _ => invalid_nested_attr(attr, &nested_attr).emit(), + } else { + invalid_nested_attr(attr, &nested_attr).emit() } } @@ -382,142 +409,215 @@ impl SessionDiagnosticDeriveBuilder { 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(); - - let meta = attr.parse_meta()?; - match meta { - Meta::Path(_) => 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" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(quote! { - #diag.set_span(#binding); - }) - } - "label" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, name)) - } - "note" | "help" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - Ok(self.add_spanned_subdiagnostic(binding, ident, name)) - } else if type_is_unit(&info.ty) { - Ok(self.add_subdiagnostic(ident, name)) - } 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") - }), - }, - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name { - "label" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value())) - } - "note" | "help" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value())) - } else if type_is_unit(&info.ty) { - Ok(self.add_subdiagnostic(ident, &s.value())) - } else { - report_type_error(attr, "`Span` or `()`")?; - } - } - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `label`, `note` and `help` are valid field attributes") - }), - }, - Meta::List(MetaList { ref path, ref nested, .. }) => { - let name = path.segments.last().unwrap().ident.to_string(); - let name = name.as_ref(); - - match name { - "suggestion" | "suggestion_short" | "suggestion_hidden" - | "suggestion_verbose" => (), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag - .help("only `suggestion{,_short,_hidden,_verbose}` are valid field attributes") - }), + 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" => { + report_error_if_not_applied_to_span(attr, &info)?; + Ok(quote! { + #diag.set_span(#binding); + }) + } + "label" => { + report_error_if_not_applied_to_span(attr, &info)?; + Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label })) + } + "note" | "help" => { + let path = match name { + "note" => parse_quote! { _subdiag::note }, + "help" => parse_quote! { _subdiag::help }, + _ => unreachable!(), }; + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + Ok(self.add_spanned_subdiagnostic(binding, ident, path)) + } else if type_is_unit(&info.ty) { + Ok(self.add_subdiagnostic(ident, path)) + } 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", + ) + }), + } + } - let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; + 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 mut msg = None; - let mut code = None; + 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" => (), + _ => throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \ + valid field attributes", + ) + }), + } - for nested_attr in nested { - let meta = match nested_attr { - syn::NestedMeta::Meta(ref meta) => meta, - syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr), - }; + // 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), + }; - 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 { - "message" => { - msg = Some(s.value()); - } - "code" => { - let formatted_str = self.build_format(&s.value(), s.span()); - code = Some(formatted_str); - } - "applicability" => { - applicability = match applicability { - Some(v) => { - span_err( - span, - "applicability cannot be set in both the field and attribute" - ).emit(); - Some(v) - } - None => match Applicability::from_str(&s.value()) { - Ok(v) => Some(quote! { #v }), - Err(()) => { - span_err(span, "invalid applicability").emit(); - None - } - }, - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "only `message`, `code` and `applicability` are valid field attributes", + // 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)), + "note" | "help" => { + 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 msg = None; + let mut code = None; + + let mut nested_iter = nested.into_iter().peekable(); + if let Some(nested_attr) = nested_iter.peek() { + if let NestedMeta::Meta(Meta::Path(path)) = nested_attr { + msg = Some(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). + if msg.is_some() { + let _ = nested_iter.next(); + } + + 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 = Some(formatted_str); + } + "applicability" => { + applicability = match applicability { + Some(v) => { + span_err( + span, + "applicability cannot be set in both the field and \ + attribute", ) - }), + .emit(); + Some(v) + } + None => match Applicability::from_str(&s.value()) { + Ok(v) => Some(quote! { #v }), + Err(()) => { + span_err(span, "invalid applicability").emit(); + None + } + }, } } - _ => throw_invalid_nested_attr!(attr, &nested_attr), + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "only `message`, `code` and `applicability` are valid field \ + attributes", + ) + }), } } - - let applicability = applicability - .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); - - let method = format_ident!("span_{}", name); - - let msg = msg.as_deref().unwrap_or("suggestion"); - let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) }; - let code = code.unwrap_or_else(|| quote! { String::new() }); - - Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) + _ => 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 + } + }), } - _ => throw_invalid_attr!(attr, &meta), } + + let applicability = + applicability.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.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 @@ -526,24 +626,24 @@ impl SessionDiagnosticDeriveBuilder { &self, field_binding: TokenStream, kind: &Ident, - fluent_attr_identifier: &str, + fluent_attr_identifier: Path, ) -> TokenStream { let diag = &self.diag; let fn_name = format_ident!("span_{}", kind); quote! { #diag.#fn_name( #field_binding, - rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier) + rustc_errors::fluent::#fluent_attr_identifier ); } } /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug /// and `fluent_attr_identifier`. - fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream { + fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream { let diag = &self.diag; quote! { - #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)); + #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier); } } @@ -569,7 +669,8 @@ impl SessionDiagnosticDeriveBuilder { } else { throw_span_err!( info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more than one `Span`" + "type of field annotated with `#[suggestion(...)]` contains more \ + than one `Span`" ); } } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) { @@ -578,7 +679,8 @@ impl SessionDiagnosticDeriveBuilder { } else { throw_span_err!( info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more than one Applicability" + "type of field annotated with `#[suggestion(...)]` contains more \ + than one Applicability" ); } } @@ -595,12 +697,18 @@ impl SessionDiagnosticDeriveBuilder { } throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| { - diag.help("`#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`") + diag.help( + "`#[suggestion(...)]` on a tuple field must be applied to fields of type \ + `(Span, Applicability)`", + ) }); } // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error. _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| { - diag.help("`#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`") + diag.help( + "`#[suggestion(...)]` should be applied to fields of type `Span` or \ + `(Span, Applicability)`", + ) }), } } diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index fd1dc2f3073..d088402abc6 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -39,6 +39,19 @@ pub(crate) fn _throw_err( SessionDiagnosticDeriveError::ErrorHandled } +/// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are +/// unlikely to come up much in use of the macro. +fn path_to_string(path: &syn::Path) -> String { + let mut out = String::new(); + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 || path.leading_colon.is_some() { + out.push_str("::"); + } + out.push_str(&segment.ident.to_string()); + } + out +} + /// Returns an error diagnostic on span `span` with msg `msg`. pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic { Diagnostic::spanned(span, Level::Error, msg) @@ -61,15 +74,13 @@ pub(crate) use throw_span_err; /// Returns an error diagnostic for an invalid attribute. pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic { let span = attr.span().unwrap(); - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - + let path = path_to_string(&attr.path); match meta { - Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", name)), + Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", path)), Meta::NameValue(_) => { - span_err(span, &format!("`#[{} = ...]` is not a valid attribute", name)) + span_err(span, &format!("`#[{} = ...]` is not a valid attribute", path)) } - Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", name)), + Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", path)), } } @@ -101,18 +112,16 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag }; let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); + let path = path_to_string(meta.path()); match meta { - Meta::NameValue(..) => span_err( - span, - &format!("`#[{}({} = ...)]` is not a valid attribute", name, nested_name), - ), + Meta::NameValue(..) => { + span_err(span, &format!("`#[{}({} = ...)]` is not a valid attribute", name, path)) + } Meta::Path(..) => { - span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, nested_name)) + span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, path)) } Meta::List(..) => { - span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, nested_name)) + span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, path)) } } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 42a9bf477a4..2317186e655 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -254,6 +254,17 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok ]; #generated + + pub mod _subdiag { + pub const note: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); + pub const help: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help")); + pub const label: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label")); + pub const suggestion: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion")); + } } } .into() diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 69573d904d4..88182ed5a12 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -22,14 +22,14 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(SessionDiagnostic)] -/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")] +/// #[error(borrowck::move_out_of_borrow, code = "E0505")] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, /// #[primary_span] /// #[label] /// pub span: Span, -/// #[label = "first-borrow-label"] +/// #[label(borrowck::first_borrow_label)] /// pub first_borrow_span: Span, /// #[suggestion(code = "{name}.clone()")] /// pub clone_sugg: Option<(Span, Applicability)> diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ba325d70422..30869f055f5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -244,7 +244,7 @@ impl MultiSugg { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-maybe-report-ambiguous-plus")] +#[error(parser::maybe_report_ambiguous_plus)] struct AmbiguousPlus { pub sum_ty: String, #[primary_span] @@ -253,7 +253,7 @@ struct AmbiguousPlus { } #[derive(SessionDiagnostic)] -#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")] +#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")] struct BadTypePlus { pub ty: String, #[primary_span] @@ -287,7 +287,7 @@ pub enum BadTypePlusSub { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")] +#[error(parser::maybe_recover_from_bad_qpath_stage_2)] struct BadQPathStage2 { #[primary_span] #[suggestion(applicability = "maybe-incorrect")] @@ -296,7 +296,7 @@ struct BadQPathStage2 { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-semicolon")] +#[error(parser::incorrect_semicolon)] struct IncorrectSemicolon<'a> { #[primary_span] #[suggestion_short(applicability = "machine-applicable")] @@ -307,26 +307,26 @@ struct IncorrectSemicolon<'a> { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-use-of-await")] +#[error(parser::incorrect_use_of_await)] struct IncorrectUseOfAwait { #[primary_span] - #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")] + #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")] span: Span, } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-use-of-await")] +#[error(parser::incorrect_use_of_await)] struct IncorrectAwait { #[primary_span] span: Span, - #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")] + #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")] sugg_span: (Span, Applicability), expr: String, question_mark: &'static str, } #[derive(SessionDiagnostic)] -#[error(slug = "parser-in-in-typo")] +#[error(parser::in_in_typo)] struct InInTypo { #[primary_span] span: Span, diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 67a3d4a4d02..758108e5d71 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -6,18 +6,18 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] -#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")] +#[error(typeck::field_multiply_specified_in_initializer, code = "E0062")] pub struct FieldMultiplySpecifiedInInitializer { #[primary_span] #[label] pub span: Span, - #[label = "previous-use-label"] + #[label(typeck::previous_use_label)] pub prev_span: Span, pub ident: Ident, } #[derive(SessionDiagnostic)] -#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")] +#[error(typeck::unrecognized_atomic_operation, code = "E0092")] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -26,7 +26,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(SessionDiagnostic)] -#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")] +#[error(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -37,7 +37,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(SessionDiagnostic)] -#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")] +#[error(typeck::unrecognized_intrinsic_function, code = "E0093")] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -46,19 +46,19 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(SessionDiagnostic)] -#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")] +#[error(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] pub span: Span, - #[label = "generics-label"] + #[label(typeck::generics_label)] pub generics_span: Option, pub item_kind: &'static str, pub ident: Ident, } #[derive(SessionDiagnostic)] -#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")] +#[error(typeck::drop_impl_on_wrong_item, code = "E0120")] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -66,18 +66,18 @@ pub struct DropImplOnWrongItem { } #[derive(SessionDiagnostic)] -#[error(code = "E0124", slug = "typeck-field-already-declared")] +#[error(typeck::field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] #[label] pub span: Span, - #[label = "previous-decl-label"] + #[label(typeck::previous_decl_label)] pub prev_span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")] +#[error(typeck::copy_impl_on_type_with_dtor, code = "E0184")] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -85,14 +85,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(SessionDiagnostic)] -#[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")] +#[error(typeck::multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")] +#[error(typeck::copy_impl_on_non_adt, code = "E0206")] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -100,23 +100,23 @@ pub struct CopyImplOnNonAdt { } #[derive(SessionDiagnostic)] -#[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")] +#[error(typeck::trait_object_declared_with_no_traits, code = "E0224")] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, - #[label = "alias-span"] + #[label(typeck::alias_span)] pub trait_alias_span: Option, } #[derive(SessionDiagnostic)] -#[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0227")] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")] +#[error(typeck::assoc_type_binding_not_allowed, code = "E0229")] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -124,14 +124,14 @@ pub struct AssocTypeBindingNotAllowed { } #[derive(SessionDiagnostic)] -#[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")] +#[error(typeck::functional_record_update_on_non_struct, code = "E0436")] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")] +#[error(typeck::typeof_reserved_keyword_used, code = "E0516")] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -142,25 +142,25 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(SessionDiagnostic)] -#[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")] +#[error(typeck::return_stmt_outside_of_fn_body, code = "E0572")] pub struct ReturnStmtOutsideOfFnBody { #[primary_span] pub span: Span, - #[label = "encl-body-label"] + #[label(typeck::encl_body_label)] pub encl_body_span: Option, - #[label = "encl-fn-label"] + #[label(typeck::encl_fn_label)] pub encl_fn_span: Option, } #[derive(SessionDiagnostic)] -#[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")] +#[error(typeck::yield_expr_outside_of_generator, code = "E0627")] pub struct YieldExprOutsideOfGenerator { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")] +#[error(typeck::struct_expr_non_exhaustive, code = "E0639")] pub struct StructExprNonExhaustive { #[primary_span] pub span: Span, @@ -168,26 +168,26 @@ pub struct StructExprNonExhaustive { } #[derive(SessionDiagnostic)] -#[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")] +#[error(typeck::method_call_on_unknown_type, code = "E0699")] pub struct MethodCallOnUnknownType { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")] +#[error(typeck::value_of_associated_struct_already_specified, code = "E0719")] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] pub span: Span, - #[label = "previous-bound-label"] + #[label(typeck::previous_bound_label)] pub prev_span: Span, pub item_name: Ident, pub def_path: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")] +#[error(typeck::address_of_temporary_taken, code = "E0745")] pub struct AddressOfTemporaryTaken { #[primary_span] #[label] @@ -233,7 +233,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { } #[derive(SessionDiagnostic)] -#[error(slug = "typeck-unconstrained-opaque-type")] +#[error(typeck::unconstrained_opaque_type)] #[note] pub struct UnconstrainedOpaqueType { #[primary_span] @@ -301,7 +301,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { } #[derive(SessionDiagnostic)] -#[error(code = "E0183", slug = "typeck-manual-implementation")] +#[error(typeck::manual_implementation, code = "E0183")] #[help] pub struct ManualImplementation { #[primary_span] @@ -311,7 +311,7 @@ pub struct ManualImplementation { } #[derive(SessionDiagnostic)] -#[error(slug = "typeck-substs-on-overridden-impl")] +#[error(typeck::substs_on_overridden_impl)] pub struct SubstsOnOverriddenImpl { #[primary_span] pub span: Span, diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs index 817d8531da9..3e349ab0258 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs @@ -16,7 +16,7 @@ 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, diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 84d5de17309..8cbee4c6d92 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, - #[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,116 +356,116 @@ 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, } @@ -465,14 +474,14 @@ struct NoApplicability { 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: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:81:1 + | +LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | struct InvalidNestedStructAttr3 {} + | |__________________________________^ + | + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` + +error: `#[error(slug = ...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:87:59 + | +LL | #[error(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:86:5 + --> $DIR/diagnostic-derive.rs:94:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: only `label`, `note` and `help` are valid field attributes - -error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:1 - | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: previously specified here - --> $DIR/diagnostic-derive.rs:92:1 - | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:16 - | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^^^ - | -note: previously specified here - --> $DIR/diagnostic-derive.rs:92:16 - | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^ - -error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:32 - | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^ - | -note: previously specified here - --> $DIR/diagnostic-derive.rs:92:32 - | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^ error: specified multiple times --> $DIR/diagnostic-derive.rs:101:1 | -LL | #[warning(code = "E0293", slug = "bar")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here --> $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:18 + --> $DIR/diagnostic-derive.rs:101:1 | -LL | #[warning(code = "E0293", slug = "bar")] - | ^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100: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:101:34 + --> $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:32 + --> $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:108:32 + --> $DIR/diagnostic-derive.rs:109:1 | -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:1 | -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:109:1 | -LL | #[error(code = "E0456", slug = "foo", slug = "bar")] - | ^^^^^ +LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:113:32 + --> $DIR/diagnostic-derive.rs:108:1 | -LL | #[error(code = "E0456", slug = "foo", slug = "bar")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: specified multiple times + --> $DIR/diagnostic-derive.rs:109:52 + | +LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] + | ^^^^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive.rs:108:50 + | +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^ + +error: specified multiple times + --> $DIR/diagnostic-derive.rs:116:66 + | +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] + | ^^^^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive.rs:116:50 + | +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] + | ^^^^^^^ + +error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs: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 +error: `#[label = ...]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:294:5 | -LL | #[label("bar")] - | ^^^^^^^^^^^^^^^ - | - = 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(message = "bar", code = "...", applicability = "batman")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +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 | #[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`.