diff --git a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl index e89fa586d2a..336e7a66857 100644 --- a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl +++ b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl @@ -1,2 +1,87 @@ -parser-struct-literal-body-without-path = struct literal body without path +parser-struct-literal-body-without-path = + struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block + +typeck-field-multiply-specified-in-initializer = + field `{$ident}` specified more than once + .label = used more than once + .previous-use-label = first use of `{$ident}` + +typeck-unrecognized-atomic-operation = + unrecognized atomic operation function: `{$op}` + .label = unrecognized atomic operation + +typeck-wrong-number-of-generic-arguments-to-intrinsic = + intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} + .label = expected {$expected} {$descr} {$expected -> + [one] parameter + *[other] parameters + } + +typeck-unrecognized-intrinsic-function = + unrecognized intrinsic function: `{$name}` + .label = unrecognized intrinsic + +typeck-lifetimes-or-bounds-mismatch-on-trait = + lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration + .label = lifetimes do not match {$item_kind} in trait + .generics-label = lifetimes in impl do not match this {$item_kind} in trait + +typeck-drop-impl-on-wrong-item = + the `Drop` trait may only be implemented for structs, enums, and unions + .label = must be a struct, enum, or union + +typeck-field-already-declared = + field `{$field_name}` is already declared + .label = field already declared + .previous-decl-label = `{$field_name}` first declared here + +typeck-copy-impl-on-type-with-dtor = + the trait `Copy` may not be implemented for this type; the type has a destructor + .label = `Copy` not allowed on types with destructors + +typeck-multiple-relaxed-default-bounds = + type parameter has more than one relaxed default bound, only one is supported + +typeck-copy-impl-on-non-adt = + the trait `Copy` may not be implemented for this type + .label = type is not a structure or enumeration + +typeck-trait-object-declared-with-no-traits = + at least one trait is required for an object type + +typeck-ambiguous-lifetime-bound = + ambiguous lifetime bound, explicit lifetime bound required + +typeck-assoc-type-binding-not-allowed = + associated type bindings are not allowed here + .label = associated type not allowed here + +typeck-functional-record-update-on-non-struct = + functional record update syntax requires a struct + +typeck-typeof-reserved-keyword-used = + `typeof` is a reserved keyword but unimplemented + .label = reserved keyword + +typeck-return-stmt-outside-of-fn-body = + return statement outside of function body + .encl-body-label = the return is part of this body... + .encl-fn-label = ...not the enclosing function body + +typeck-yield-expr-outside-of-generator = + yield expression outside of generator literal + +typeck-struct-expr-non-exhaustive = + cannot create non-exhaustive {$what} using struct expression + +typeck-method-call-on-unknown-type = + the type of this value must be known to call a method on a raw pointer on it + +typeck-value-of-associated-struct-already-specified = + the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified + .label = re-bound here + .previous-bound-label = `{$item_name}` bound here first + +typeck-address-of-temporary-taken = cannot take address of a temporary + .label = temporary value diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index c8281bd37d1..6a763d4d140 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -261,7 +261,7 @@ pub trait Emitter { message: &'a DiagnosticMessage, args: &'a FluentArgs<'_>, ) -> Cow<'_, str> { - trace!(?message); + trace!(?message, ?args); let (identifier, attr) = match message { DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg), DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), @@ -283,7 +283,13 @@ pub trait Emitter { let mut err = vec![]; let translated = bundle.format_pattern(value, Some(&args), &mut err); trace!(?translated, ?err); - debug_assert!(err.is_empty()); + debug_assert!( + err.is_empty(), + "identifier: {:?}, args: {:?}, errors: {:?}", + identifier, + args, + err + ); translated } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 94db957d299..c927fcb2109 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -777,6 +777,17 @@ impl Handler { result } + /// Construct a builder at the `Warn` level with the `msg` and the `code`. + pub fn struct_warn_with_code( + &self, + msg: impl Into, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_, ()> { + let mut result = self.struct_warn(msg); + result.code(code); + result + } + /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. pub fn struct_span_fatal( &self, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 03e139755ba..2693aea9bba 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -63,9 +63,14 @@ decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_fo decl_derive!([Lift, attributes(lift)] => lift::lift_derive); decl_derive!( [SessionDiagnostic, attributes( - message, - lint, + // struct attributes + warning, error, + // nested parts of struct attributes + code, + slug, + // field attributes + message, label, suggestion, suggestion_short, diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 4430e1cdfc5..05c013dcea7 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -16,11 +16,11 @@ use std::collections::{BTreeSet, HashMap}; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(SessionDiagnostic)] -/// #[code = "E0505"] -/// #[error = "cannot move out of {name} because it is borrowed"] +/// #[error(code = "E0505", slug = "move-out-of-borrow-error")] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, +/// #[message] /// #[label = "cannot move out of borrow"] /// pub span: Span, /// #[label = "`{ty}` first borrowed here"] @@ -79,13 +79,6 @@ impl std::convert::From for SessionDiagnosticDeriveError { } } -/// Equivalent to `rustc:errors::diagnostic::DiagnosticId`, except stores the quoted expression to -/// initialise the code with. -enum DiagnosticId { - Error(proc_macro2::TokenStream), - Lint(proc_macro2::TokenStream), -} - #[derive(Debug)] enum SessionDiagnosticDeriveError { SynError(syn::Error), @@ -100,7 +93,7 @@ impl SessionDiagnosticDeriveError { // Return ! to avoid having to create a blank DiagnosticBuilder to return when an // error has already been emitted to the compiler. quote! { - unreachable!() + { unreachable!(); } } } } @@ -152,17 +145,25 @@ impl<'a> SessionDiagnosticDerive<'a> { } Self { - builder: SessionDiagnosticDeriveBuilder { diag, sess, fields: fields_map, kind: None }, + builder: SessionDiagnosticDeriveBuilder { + diag, + sess, + fields: fields_map, + kind: None, + code: None, + slug: None, + }, structure, } } + fn into_tokens(self) -> proc_macro2::TokenStream { let SessionDiagnosticDerive { mut structure, mut builder } = self; let ast = structure.ast(); let attrs = &ast.attrs; - let implementation = { + let (implementation, param_ty) = { if let syn::Data::Struct(..) = ast.data { let preamble = { let preamble = attrs.iter().map(|attr| { @@ -170,6 +171,7 @@ impl<'a> SessionDiagnosticDerive<'a> { .generate_structure_code(attr) .unwrap_or_else(|v| v.to_compile_error()) }); + quote! { #(#preamble)*; } @@ -213,58 +215,94 @@ impl<'a> SessionDiagnosticDerive<'a> { // it can be referred to by Fluent messages. if field.attrs.is_empty() { let diag = &builder.diag; - let ident = &field_binding.binding; + let ident = field_binding.ast().ident.as_ref().unwrap(); quote! { #diag.set_arg(stringify!(#ident), #field_binding.into_diagnostic_arg()); } } else { quote! {} } }); - // Finally, putting it altogether. - match builder.kind { - None => { - span_err(ast.span().unwrap(), "`code` not specified") - .help("use the `#[code = \"...\"]` attribute to set this diagnostic's error code ") - .emit(); - SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + let span = ast.span().unwrap(); + let (diag, sess) = (&builder.diag, &builder.sess); + let init = match (builder.kind, builder.slug, builder.code) { + (None, _, _) => { + span_err(span, "diagnostic kind not specified") + .help("use the `#[error(...)]` attribute to create an error") + .emit(); + return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); } - Some((kind, _)) => match kind { - DiagnosticId::Lint(_lint) => todo!(), - DiagnosticId::Error(code) => { - let (diag, sess) = (&builder.diag, &builder.sess); - quote! { - let mut #diag = #sess.struct_err_with_code("", rustc_errors::DiagnosticId::Error(#code)); - #preamble - match self { - #attrs - } - match self { - #args - } - #diag - } + (Some((kind, _)), None, _) => { + span_err(span, "`slug` not specified") + .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr())) + .emit(); + return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + } + (Some((kind, _)), _, None) => { + span_err(span, "`code` not specified") + .help(&format!("use the `#[{}(code = \"...\")]` attribute to set this diagnostic's error code", kind.descr())) + .emit(); + return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + } + (Some((SessionDiagnosticKind::Error, _)), Some((slug, _)), Some((code, _))) => { + quote! { + let mut #diag = #sess.struct_err_with_code( + rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticId::Error(#code.to_string()) + ); } - }, - } + } + (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _)), Some((code, _))) => { + quote! { + let mut #diag = #sess.struct_warn_with_code( + rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticId::Error(#code.to_string()) + ); + } + } + }; + + let implementation = quote! { + #init + #preamble + match self { + #attrs + } + match self { + #args + } + #diag + }; + let param_ty = match builder.kind { + Some((SessionDiagnosticKind::Error, _)) => { + quote! { rustc_errors::ErrorGuaranteed } + } + Some((SessionDiagnosticKind::Warn, _)) => quote! { () }, + _ => unreachable!(), + }; + + (implementation, param_ty) } else { span_err( ast.span().unwrap(), "`#[derive(SessionDiagnostic)]` can only be used on structs", ) .emit(); - SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + + let implementation = SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + let param_ty = quote! { rustc_errors::ErrorGuaranteed }; + (implementation, param_ty) } }; let sess = &builder.sess; structure.gen_impl(quote! { - gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess> + gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty> for @Self { fn into_diagnostic( self, #sess: &'__session_diagnostic_sess rustc_session::Session - ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, rustc_errors::ErrorGuaranteed> { + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> { use rustc_errors::IntoDiagnosticArg; #implementation } @@ -282,6 +320,25 @@ struct FieldInfo<'a> { span: &'a proc_macro2::Span, } +/// What kind of session diagnostic is being derived - an error or a warning? +#[derive(Copy, Clone)] +enum SessionDiagnosticKind { + /// `#[error(..)]` + Error, + /// `#[warn(..)]` + Warn, +} + +impl SessionDiagnosticKind { + /// Returns human-readable string corresponding to the kind. + fn descr(&self) -> &'static str { + match self { + SessionDiagnosticKind::Error => "error", + SessionDiagnosticKind::Warn => "warning", + } + } +} + /// Tracks persistent information required for building up the individual calls to diagnostic /// methods for the final generated method. This is a separate struct to `SessionDiagnosticDerive` /// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a @@ -289,89 +346,182 @@ struct FieldInfo<'a> { struct SessionDiagnosticDeriveBuilder<'a> { /// Name of the session parameter that's passed in to the `as_error` method. sess: syn::Ident, + /// The identifier to use for the generated `DiagnosticBuilder` instance. + diag: syn::Ident, /// Store a map of field name to its corresponding field. This is built on construction of the /// derive builder. fields: HashMap, - /// The identifier to use for the generated `DiagnosticBuilder` instance. - diag: syn::Ident, - - /// Whether this is a lint or an error. This dictates how the diag will be initialised. `Span` - /// stores at what `Span` the kind was first set at (for error reporting purposes, if the kind - /// was multiply specified). - kind: Option<(DiagnosticId, proc_macro2::Span)>, + /// Kind of diagnostic requested via the struct attribute. + 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)>, + /// Error codes are a mandatory part of the struct attribute. Slugs may replace error codes + /// in future but it is desirable to mandate error codes until such a time. + code: Option<(String, proc_macro::Span)>, } impl<'a> SessionDiagnosticDeriveBuilder<'a> { + /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct + /// attributes like `#[error(..)#`, such as the diagnostic kind, slug and code. + /// + /// Returns a `proc_macro2::TokenStream` so that the `Err(..)` variant can be transformed into + /// the same type via `to_compile_error`. fn generate_structure_code( &mut self, attr: &syn::Attribute, ) -> Result { - Ok(match attr.parse_meta()? { - syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let formatted_str = self.build_format(&s.value(), attr.span()); - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - match name { - "message" => { - let diag = &self.diag; - quote! { - #diag.set_primary_message(#formatted_str); + let span = attr.span().unwrap(); + let name = attr.path.segments.last().unwrap().ident.to_string(); + + let nested = match attr.parse_meta()? { + syn::Meta::List(syn::MetaList { nested, .. }) => nested, + syn::Meta::Path(..) => throw_span_err!( + span, + &format!("`#[{}]` is not a valid `SessionDiagnostic` struct attribute", name) + ), + syn::Meta::NameValue(..) => throw_span_err!( + span, + &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` struct attribute", name) + ), + }; + + let kind = match name.as_str() { + "error" => SessionDiagnosticKind::Error, + "warning" => SessionDiagnosticKind::Warn, + other => throw_span_err!( + span, + &format!("`#[{}(...)]` is not a valid `SessionDiagnostic` struct attribute", other) + ), + }; + self.set_kind_once(kind, span)?; + + for attr in nested { + let span = attr.span().unwrap(); + let meta = match attr { + syn::NestedMeta::Meta(meta) => meta, + syn::NestedMeta::Lit(_) => throw_span_err!( + span, + &format!( + "`#[{}(\"...\")]` is not a valid `SessionDiagnostic` struct attribute", + name + ) + ), + }; + + 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. + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + match nested_name.as_str() { + "slug" => { + self.set_slug_once(s.value(), s.span().unwrap()); + } + "code" => { + self.set_code_once(s.value(), s.span().unwrap()); + } + other => { + let diag = span_err( + span, + &format!( + "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute", + name, other + ), + ); + diag.emit(); } } - attr @ "error" | attr @ "lint" => { - self.set_kind_once( - if attr == "error" { - DiagnosticId::Error(formatted_str) - } else if attr == "lint" { - DiagnosticId::Lint(formatted_str) - } else { - unreachable!() - }, - s.span(), - )?; - // This attribute is only allowed to be applied once, and the attribute - // will be set in the initialisation code. - quote! {} - } - other => throw_span_err!( - attr.span().unwrap(), + } + syn::Meta::NameValue(..) => { + span_err( + span, &format!( - "`#[{} = ...]` is not a valid `SessionDiagnostic` struct attribute", - other - ) - ), + "`#[{}({} = ...)]` is not a valid `SessionDiagnostic` struct attribute", + name, nested_name + ), + ) + .help("value must be a string") + .emit(); + } + syn::Meta::Path(..) => { + span_err( + span, + &format!( + "`#[{}({})]` is not a valid `SessionDiagnostic` struct attribute", + name, nested_name + ), + ) + .emit(); + } + syn::Meta::List(..) => { + span_err( + span, + &format!( + "`#[{}({}(...))]` is not a valid `SessionDiagnostic` struct attribute", + name, nested_name + ), + ) + .emit(); } } - _ => todo!("unhandled meta kind"), - }) + } + + Ok(quote! {}) } #[must_use] fn set_kind_once( &mut self, - kind: DiagnosticId, - span: proc_macro2::Span, + kind: SessionDiagnosticKind, + span: proc_macro::Span, ) -> Result<(), SessionDiagnosticDeriveError> { - if self.kind.is_none() { - self.kind = Some((kind, span)); - Ok(()) - } else { - let kind_str = |kind: &DiagnosticId| match kind { - DiagnosticId::Lint(..) => "lint", - DiagnosticId::Error(..) => "error", - }; + match self.kind { + None => { + self.kind = Some((kind, span)); + Ok(()) + } + Some((prev_kind, prev_span)) => { + let existing = prev_kind.descr(); + let current = kind.descr(); - let existing_kind = kind_str(&self.kind.as_ref().unwrap().0); - let this_kind = kind_str(&kind); + let msg = if current == existing { + format!("`{}` specified multiple times", existing) + } else { + format!("`{}` specified when `{}` was already specified", current, existing) + }; + throw_span_err!(span, &msg, |diag| diag + .span_note(prev_span, "previously specified here")); + } + } + } - let msg = if this_kind == existing_kind { - format!("`{}` specified multiple times", existing_kind) - } else { - format!("`{}` specified when `{}` was already specified", this_kind, existing_kind) - }; - throw_span_err!(span.unwrap(), &msg); + fn set_code_once(&mut self, code: String, span: proc_macro::Span) { + match self.code { + None => { + self.code = Some((code, span)); + } + Some((_, prev_span)) => { + span_err(span, "`code` specified multiple times") + .span_note(prev_span, "previously specified here") + .emit(); + } + } + } + + fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) { + match self.slug { + None => { + self.slug = Some((slug, span)); + } + Some((_, prev_span)) => { + span_err(span, "`slug` specified multiple times") + .span_note(prev_span, "previously specified here") + .emit(); + } } } @@ -413,26 +563,29 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); - // At this point, we need to dispatch based on the attribute key + the - // type. let meta = attr.parse_meta()?; match meta { + syn::Meta::Path(_) => match name { + "message" => { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + return Ok(quote! { + #diag.set_span(*#field_binding); + }); + } else { + throw_span_err!( + attr.span().unwrap(), + "the `#[message]` attribute can only be applied to fields of type `Span`" + ); + } + } + other => throw_span_err!( + attr.span().unwrap(), + &format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other) + ), + }, syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { let formatted_str = self.build_format(&s.value(), attr.span()); match name { - "message" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - return Ok(quote! { - #diag.set_span(*#field_binding); - #diag.set_primary_message(#formatted_str); - }); - } else { - throw_span_err!( - attr.span().unwrap(), - "the `#[message = \"...\"]` attribute can only be applied to fields of type `Span`" - ); - } - } "label" => { if type_matches_path(&info.ty, &["rustc_span", "Span"]) { return Ok(quote! { @@ -441,7 +594,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { } else { throw_span_err!( attr.span().unwrap(), - "The `#[label = ...]` attribute can only be applied to fields of type `Span`" + "the `#[label = ...]` attribute can only be applied to fields of type `Span`" ); } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 76a2c579990..74c0f67e633 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -21,7 +21,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, FluentBundle, MultiSpan, + EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -209,10 +209,10 @@ pub struct PerfStats { /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. -pub trait SessionDiagnostic<'a> { +pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `sess`. #[must_use] - fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, ErrorGuaranteed>; + fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, T>; } impl Session { @@ -343,6 +343,13 @@ impl Session { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.diagnostic().struct_err_with_code(msg, code) } + pub fn struct_warn_with_code( + &self, + msg: impl Into, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_warn_with_code(msg, code) + } pub fn struct_span_fatal>( &self, sp: S, @@ -409,6 +416,9 @@ impl Session { pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { err.into_diagnostic(self).emit() } + pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { + warning.into_diagnostic(self).emit() + } #[inline] pub fn err_count(&self) -> usize { self.diagnostic().err_count() diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 47077779616..20355dfa331 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -3,9 +3,9 @@ use rustc_macros::SessionDiagnostic; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] -#[error = "E0062"] +#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")] pub struct FieldMultiplySpecifiedInInitializer { - #[message = "field `{ident}` specified more than once"] + #[message] #[label = "used more than once"] pub span: Span, #[label = "first use of `{ident}`"] @@ -14,19 +14,18 @@ pub struct FieldMultiplySpecifiedInInitializer { } #[derive(SessionDiagnostic)] -#[error = "E0092"] +#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")] pub struct UnrecognizedAtomicOperation<'a> { - #[message = "unrecognized atomic operation function: `{op}`"] + #[message] #[label = "unrecognized atomic operation"] pub span: Span, pub op: &'a str, } #[derive(SessionDiagnostic)] -#[error = "E0094"] +#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { - #[message = "intrinsic has wrong number of {descr} \ - parameters: found {found}, expected {expected}"] + #[message] #[label = "expected {expected} {descr} parameter{expected_pluralize}"] pub span: Span, pub found: usize, @@ -36,18 +35,18 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(SessionDiagnostic)] -#[error = "E0093"] +#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")] pub struct UnrecognizedIntrinsicFunction { - #[message = "unrecognized intrinsic function: `{name}`"] + #[message] #[label = "unrecognized intrinsic"] pub span: Span, pub name: Symbol, } #[derive(SessionDiagnostic)] -#[error = "E0195"] +#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")] pub struct LifetimesOrBoundsMismatchOnTrait { - #[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"] + #[message] #[label = "lifetimes do not match {item_kind} in trait"] pub span: Span, #[label = "lifetimes in impl do not match this {item_kind} in trait"] @@ -57,18 +56,18 @@ pub struct LifetimesOrBoundsMismatchOnTrait { } #[derive(SessionDiagnostic)] -#[error = "E0120"] +#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")] pub struct DropImplOnWrongItem { - #[message = "the `Drop` trait may only be implemented for structs, enums, and unions"] + #[message] #[label = "must be a struct, enum, or union"] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0124"] +#[error(code = "E0124", slug = "typeck-field-already-declared")] pub struct FieldAlreadyDeclared { pub field_name: Ident, - #[message = "field `{field_name}` is already declared"] + #[message] #[label = "field already declared"] pub span: Span, #[label = "`{field_name}` first declared here"] @@ -76,70 +75,69 @@ pub struct FieldAlreadyDeclared { } #[derive(SessionDiagnostic)] -#[error = "E0184"] +#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")] pub struct CopyImplOnTypeWithDtor { - #[message = "the trait `Copy` may not be implemented for this type; the \ - type has a destructor"] + #[message] #[label = "Copy not allowed on types with destructors"] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0203"] +#[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")] pub struct MultipleRelaxedDefaultBounds { - #[message = "type parameter has more than one relaxed default bound, only one is supported"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0206"] +#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")] pub struct CopyImplOnNonAdt { - #[message = "the trait `Copy` may not be implemented for this type"] + #[message] #[label = "type is not a structure or enumeration"] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0224"] +#[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")] pub struct TraitObjectDeclaredWithNoTraits { - #[message = "at least one trait is required for an object type"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0227"] +#[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")] pub struct AmbiguousLifetimeBound { - #[message = "ambiguous lifetime bound, explicit lifetime bound required"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0229"] +#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")] pub struct AssocTypeBindingNotAllowed { - #[message = "associated type bindings are not allowed here"] + #[message] #[label = "associated type not allowed here"] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0436"] +#[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")] pub struct FunctionalRecordUpdateOnNonStruct { - #[message = "functional record update syntax requires a struct"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0516"] +#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")] pub struct TypeofReservedKeywordUsed { - #[message = "`typeof` is a reserved keyword but unimplemented"] + #[message] #[label = "reserved keyword"] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0572"] +#[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")] pub struct ReturnStmtOutsideOfFnBody { - #[message = "return statement outside of function body"] + #[message] pub span: Span, #[label = "the return is part of this body..."] pub encl_body_span: Option, @@ -148,31 +146,31 @@ pub struct ReturnStmtOutsideOfFnBody { } #[derive(SessionDiagnostic)] -#[error = "E0627"] +#[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")] pub struct YieldExprOutsideOfGenerator { - #[message = "yield expression outside of generator literal"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0639"] +#[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")] pub struct StructExprNonExhaustive { - #[message = "cannot create non-exhaustive {what} using struct expression"] + #[message] pub span: Span, pub what: &'static str, } #[derive(SessionDiagnostic)] -#[error = "E0699"] +#[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")] pub struct MethodCallOnUnknownType { - #[message = "the type of this value must be known to call a method on a raw pointer on it"] + #[message] pub span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0719"] +#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")] pub struct ValueOfAssociatedStructAlreadySpecified { - #[message = "the value of the associated type `{item_name}` (from trait `{def_path}`) is already specified"] + #[message] #[label = "re-bound here"] pub span: Span, #[label = "`{item_name}` bound here first"] @@ -182,9 +180,9 @@ pub struct ValueOfAssociatedStructAlreadySpecified { } #[derive(SessionDiagnostic)] -#[error = "E0745"] +#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")] pub struct AddressOfTemporaryTaken { - #[message = "cannot take address of a temporary"] + #[message] #[label = "temporary value"] pub span: Span, } diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs index 05adb35951e..32248fb01e9 100644 --- a/src/test/ui-fulldeps/session-derive-errors.rs +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -26,12 +26,15 @@ use rustc_errors::Applicability; extern crate rustc_session; #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] +#[error(code = "E0123", slug = "hello-world")] struct Hello {} #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[warning(code = "E0123", slug = "hello-world")] +struct HelloWarn {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs enum SessionDiagnosticOnEnum { Foo, @@ -39,13 +42,46 @@ enum SessionDiagnosticOnEnum { } #[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] #[error = "E0123"] -#[label = "This is in the wrong place"] -//~^ ERROR `#[label = ...]` is not a valid `SessionDiagnostic` struct attribute -struct WrongPlace {} +//~^ ERROR `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute +struct WrongStructAttrStyle {} #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[nonsense(code = "E0123", slug = "foo")] +//~^ ERROR `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute +//~^^ ERROR diagnostic kind not specified +//~^^^ ERROR cannot find attribute `nonsense` in this scope +struct InvalidStructAttr {} + +#[derive(SessionDiagnostic)] +#[error("E0123")] +//~^ ERROR `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute +//~^^ ERROR `slug` not specified +struct InvalidLitNestedAttr {} + +#[derive(SessionDiagnostic)] +#[error(nonsense, code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr {} + +#[derive(SessionDiagnostic)] +#[error(nonsense("foo"), code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr1 {} + +#[derive(SessionDiagnostic)] +#[error(nonsense = "...", code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr2 {} + +#[derive(SessionDiagnostic)] +#[error(nonsense = 4, code = "E0123", slug = "foo")] +//~^ ERROR `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute +struct InvalidNestedStructAttr3 {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] struct WrongPlaceField { #[suggestion = "this is the wrong kind of attribute"] //~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute @@ -53,101 +89,113 @@ struct WrongPlaceField { } #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] -#[error = "E0456"] //~ ERROR `error` specified multiple times +#[error(code = "E0123", slug = "foo")] +#[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times struct ErrorSpecifiedTwice {} #[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[error = "E0123"] -#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified -struct LintSpecifiedAfterError {} +#[error(code = "E0123", slug = "foo")] +#[warning(code = "E0293", slug = "bar")] +//~^ ERROR `warning` specified when `error` was already specified +struct WarnSpecifiedAfterError {} #[derive(SessionDiagnostic)] -#[message = "Some lint message"] -#[error = "E0123"] -struct LintButHasErrorCode {} +#[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times +struct CodeSpecifiedTwice {} #[derive(SessionDiagnostic)] -struct ErrorCodeNotProvided {} //~ ERROR `code` not specified - -// FIXME: Uncomment when emitting lints is supported. -/* -#[derive(SessionDiagnostic)] -#[message = "Hello, world!"] -#[lint = "clashing_extern_declarations"] -#[lint = "improper_ctypes"] // FIXME: ERROR `lint` specified multiple times -struct LintSpecifiedTwice {} +#[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times +struct SlugSpecifiedTwice {} #[derive(SessionDiagnostic)] -#[lint = "Some lint message"] -#[message = "Some error message"] -#[error = "E0123"] // ERROR `error` specified when `lint` was already specified -struct ErrorSpecifiedAfterLint {} -*/ +struct KindNotProvided {} //~ ERROR diagnostic kind not specified #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0456")] //~ ERROR `slug` not specified +struct SlugNotProvided {} + +#[derive(SessionDiagnostic)] +#[error(slug = "foo")] //~ ERROR `code` not specified +struct CodeNotProvided {} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct MessageWrongType { + #[message] + //~^ ERROR `#[message]` attribute can only be applied to fields of type `Span` + foo: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct InvalidPathFieldAttr { + #[nonsense] + //~^ ERROR `#[nonsense]` is not a valid `SessionDiagnostic` field attribute + //~^^ ERROR cannot find attribute `nonsense` in this scope + foo: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] struct ErrorWithField { name: String, - #[message = "This error has a field, and references {name}"] + #[label = "This error has a field, and references {name}"] span: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct ErrorWithMessageAppliedToField { - #[message = "this message is applied to a String field"] - //~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type `Span` + #[label = "this message is applied to a String field"] + //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` name: String, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This error has a field, and references {name}"] -//~^ ERROR `name` doesn't refer to a field on this type +#[error(code = "E0123", slug = "foo")] struct ErrorWithNonexistentField { - descr: String, + #[label = "This error has a field, and references {name}"] + //~^ ERROR `name` doesn't refer to a field on this type + foo: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This is missing a closing brace: {name"] +#[error(code = "E0123", slug = "foo")] //~^ ERROR invalid format string: expected `'}'` struct ErrorMissingClosingBrace { + #[label = "This is missing a closing brace: {name"] + foo: Span, name: String, val: usize, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "This is missing an opening brace: name}"] +#[error(code = "E0123", slug = "foo")] //~^ ERROR invalid format string: unmatched `}` struct ErrorMissingOpeningBrace { + #[label = "This is missing an opening brace: name}"] + foo: Span, name: String, val: usize, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something"] +#[error(code = "E0123", slug = "foo")] struct LabelOnSpan { #[label = "See here"] sp: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something"] +#[error(code = "E0123", slug = "foo")] struct LabelOnNonSpan { #[label = "See here"] - //~^ ERROR The `#[label = ...]` attribute can only be applied to fields of type `Span` + //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` id: u32, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct Suggest { #[suggestion(message = "This is a suggestion", code = "This is the suggested code")] #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")] @@ -157,14 +205,14 @@ struct Suggest { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithoutCode { #[suggestion(message = "This is a suggestion")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithBadKey { #[suggestion(nonsense = "This is nonsense")] //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` @@ -172,7 +220,7 @@ struct SuggestWithBadKey { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithShorthandMsg { #[suggestion(msg = "This is a suggestion")] //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` @@ -180,7 +228,7 @@ struct SuggestWithShorthandMsg { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithoutMsg { #[suggestion(code = "This is suggested code")] //~^ ERROR missing suggestion message @@ -188,14 +236,14 @@ struct SuggestWithoutMsg { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithTypesSwapped { #[suggestion(message = "This is a message", code = "This is suggested code")] suggestion: (Applicability, Span), } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithWrongTypeApplicabilityOnly { #[suggestion(message = "This is a message", code = "This is suggested code")] //~^ ERROR wrong field type for suggestion @@ -203,14 +251,14 @@ struct SuggestWithWrongTypeApplicabilityOnly { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithSpanOnly { #[suggestion(message = "This is a message", code = "This is suggested code")] suggestion: Span, } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithDuplicateSpanAndApplicability { #[suggestion(message = "This is a message", code = "This is suggested code")] //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span` @@ -218,7 +266,7 @@ struct SuggestWithDuplicateSpanAndApplicability { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct SuggestWithDuplicateApplicabilityAndSpan { #[suggestion(message = "This is a message", code = "This is suggested code")] //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one @@ -226,7 +274,7 @@ struct SuggestWithDuplicateApplicabilityAndSpan { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct WrongKindOfAnnotation { #[label("wrong kind of annotation for label")] //~^ ERROR invalid annotation list `#[label(...)]` @@ -234,8 +282,7 @@ struct WrongKindOfAnnotation { } #[derive(SessionDiagnostic)] -#[error = "E0123"] -#[message = "Something something else"] +#[error(code = "E0123", slug = "foo")] struct OptionsInErrors { #[label = "Label message"] label: Option, @@ -244,11 +291,11 @@ struct OptionsInErrors { } #[derive(SessionDiagnostic)] -#[error = "E0456"] +#[error(code = "E0456", slug = "foo")] struct MoveOutOfBorrowError<'tcx> { name: Ident, ty: Ty<'tcx>, - #[message = "cannot move {ty} out of borrow"] + #[message] #[label = "cannot move out of borrow"] span: Span, #[label = "`{ty}` first borrowed here"] @@ -258,9 +305,9 @@ struct MoveOutOfBorrowError<'tcx> { } #[derive(SessionDiagnostic)] -#[error = "E0123"] +#[error(code = "E0123", slug = "foo")] struct ErrorWithLifetime<'a> { - #[message = "Some message that references {name}"] + #[label = "Some message that references {name}"] span: Span, name: &'a str, } diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr index afe941e2527..d1075003525 100644 --- a/src/test/ui-fulldeps/session-derive-errors.stderr +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -1,7 +1,7 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs - --> $DIR/session-derive-errors.rs:34:1 + --> $DIR/session-derive-errors.rs:37:1 | -LL | / #[error = "E0123"] +LL | / #[error(code = "E0123", slug = "foo")] LL | | LL | | enum SessionDiagnosticOnEnum { LL | | Foo, @@ -9,95 +9,221 @@ LL | | Bar, LL | | } | |_^ -error: `#[label = ...]` is not a valid `SessionDiagnostic` struct attribute - --> $DIR/session-derive-errors.rs:43:1 +error: `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:46:1 | -LL | #[label = "This is in the wrong place"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error = "E0123"] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[nonsense(...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:51:1 + | +LL | #[nonsense(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostic kind not specified + --> $DIR/session-derive-errors.rs:51:1 + | +LL | / #[nonsense(code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | +LL | | struct InvalidStructAttr {} + | |___________________________^ + | + = help: use the `#[error(...)]` attribute to create an error + +error: `#[error("...")]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:58:9 + | +LL | #[error("E0123")] + | ^^^^^^^ + +error: `slug` not specified + --> $DIR/session-derive-errors.rs:58:1 + | +LL | / #[error("E0123")] +LL | | +LL | | +LL | | struct InvalidLitNestedAttr {} + | |______________________________^ + | + = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug + +error: `#[error(nonsense)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:64:9 + | +LL | #[error(nonsense, code = "E0123", slug = "foo")] + | ^^^^^^^^ + +error: `#[error(nonsense(...))]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:69:9 + | +LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^ + +error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:74:9 + | +LL | #[error(nonsense = "...", code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^ + +error: `#[error(nonsense = ...)]` is not a valid `SessionDiagnostic` struct attribute + --> $DIR/session-derive-errors.rs:79:9 + | +LL | #[error(nonsense = 4, code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^ + | + = help: value must be a string error: `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute - --> $DIR/session-derive-errors.rs:50:5 + --> $DIR/session-derive-errors.rs:86:5 | LL | #[suggestion = "this is the wrong kind of attribute"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `error` specified multiple times - --> $DIR/session-derive-errors.rs:58:11 + --> $DIR/session-derive-errors.rs:93:1 | -LL | #[error = "E0456"] - | ^^^^^^^ +LL | #[error(code = "E0456", slug = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:92:1 + | +LL | #[error(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `lint` specified when `error` was already specified - --> $DIR/session-derive-errors.rs:64:10 +error: `warning` specified when `error` was already specified + --> $DIR/session-derive-errors.rs:98:1 | -LL | #[lint = "some_useful_lint"] - | ^^^^^^^^^^^^^^^^^^ +LL | #[warning(code = "E0293", slug = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:97:1 + | +LL | #[error(code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `code` specified multiple times + --> $DIR/session-derive-errors.rs:103:32 + | +LL | #[error(code = "E0456", code = "E0457", slug = "bar")] + | ^^^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:103:16 + | +LL | #[error(code = "E0456", code = "E0457", slug = "bar")] + | ^^^^^^^ + +error: `slug` specified multiple times + --> $DIR/session-derive-errors.rs:107:46 + | +LL | #[error(code = "E0456", slug = "foo", slug = "bar")] + | ^^^^^ + | +note: previously specified here + --> $DIR/session-derive-errors.rs:107:32 + | +LL | #[error(code = "E0456", slug = "foo", slug = "bar")] + | ^^^^^ + +error: diagnostic kind not specified + --> $DIR/session-derive-errors.rs:111:1 + | +LL | struct KindNotProvided {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use the `#[error(...)]` attribute to create an error + +error: `slug` not specified + --> $DIR/session-derive-errors.rs:114:1 + | +LL | / #[error(code = "E0456")] +LL | | struct SlugNotProvided {} + | |_________________________^ + | + = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug error: `code` not specified - --> $DIR/session-derive-errors.rs:73:1 + --> $DIR/session-derive-errors.rs:118:1 | -LL | struct ErrorCodeNotProvided {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / #[error(slug = "foo")] +LL | | struct CodeNotProvided {} + | |_________________________^ | - = help: use the `#[code = "..."]` attribute to set this diagnostic's error code + = help: use the `#[error(code = "...")]` attribute to set this diagnostic's error code -error: the `#[message = "..."]` attribute can only be applied to fields of type `Span` - --> $DIR/session-derive-errors.rs:101:5 +error: the `#[message]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:124:5 | -LL | #[message = "this message is applied to a String field"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[message] + | ^^^^^^^^^^ + +error: `#[nonsense]` is not a valid `SessionDiagnostic` field attribute + --> $DIR/session-derive-errors.rs:132:5 + | +LL | #[nonsense] + | ^^^^^^^^^^^ + +error: the `#[label = ...]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:149:5 + | +LL | #[label = "this message is applied to a String field"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/session-derive-errors.rs:108:1 + --> $DIR/session-derive-errors.rs:157:5 | -LL | #[message = "This error has a field, and references {name}"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label = "This error has a field, and references {name}"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/session-derive-errors.rs:116:1 + --> $DIR/session-derive-errors.rs:163:20 | LL | #[derive(SessionDiagnostic)] | ----------------- in this derive macro expansion -LL | #[error = "E0123"] - | - because of this opening brace -LL | #[message = "This is missing a closing brace: {name"] - | ^ expected `'}'` in format string +LL | #[error(code = "E0123", slug = "foo")] + | - ^ expected `'}'` in format string + | | + | because of this opening brace | = 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: invalid format string: unmatched `}` found - --> $DIR/session-derive-errors.rs:125:1 + --> $DIR/session-derive-errors.rs:173:20 | LL | #[derive(SessionDiagnostic)] | ----------------- in this derive macro expansion -LL | #[error = "E0123"] -LL | #[message = "This is missing an opening brace: name}"] - | ^ unmatched `}` in format string +LL | #[error(code = "E0123", slug = "foo")] + | ^ unmatched `}` in format string | = 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/session-derive-errors.rs:144:5 +error: the `#[label = ...]` attribute can only be applied to fields of type `Span` + --> $DIR/session-derive-errors.rs:192:5 | LL | #[label = "See here"] | ^^^^^^^^^^^^^^^^^^^^^ error: `nonsense` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:169:18 + --> $DIR/session-derive-errors.rs:217:18 | LL | #[suggestion(nonsense = "This is nonsense")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `msg` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:177:18 + --> $DIR/session-derive-errors.rs:225:18 | LL | #[suggestion(msg = "This is a suggestion")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing suggestion message - --> $DIR/session-derive-errors.rs:185:7 + --> $DIR/session-derive-errors.rs:233:7 | LL | #[suggestion(code = "This is suggested code")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +231,7 @@ LL | #[suggestion(code = "This is suggested code")] = help: provide a suggestion message using `#[suggestion(message = "...")]` error: wrong field type for suggestion - --> $DIR/session-derive-errors.rs:200:5 + --> $DIR/session-derive-errors.rs:248:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -115,7 +241,7 @@ 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/session-derive-errors.rs:215:5 + --> $DIR/session-derive-errors.rs:263:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -123,7 +249,7 @@ LL | | suggestion: (Span, Span, Applicability), | |___________________________________________^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/session-derive-errors.rs:223:5 + --> $DIR/session-derive-errors.rs:271:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -131,10 +257,22 @@ LL | | suggestion: (Applicability, Applicability, Span), | |____________________________________________________^ error: invalid annotation list `#[label(...)]` - --> $DIR/session-derive-errors.rs:231:7 + --> $DIR/session-derive-errors.rs:279:7 | LL | #[label("wrong kind of annotation for label")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: cannot find attribute `nonsense` in this scope + --> $DIR/session-derive-errors.rs:51:3 + | +LL | #[nonsense(code = "E0123", slug = "foo")] + | ^^^^^^^^ + +error: cannot find attribute `nonsense` in this scope + --> $DIR/session-derive-errors.rs:132:7 + | +LL | #[nonsense] + | ^^^^^^^^ + +error: aborting due to 34 previous errors