1
Fork 0

macros: translatable struct attrs and warnings

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-03-31 08:35:17 +01:00
parent f0de7df204
commit d0fd8d7880
9 changed files with 729 additions and 276 deletions

View file

@ -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 .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

View file

@ -261,7 +261,7 @@ pub trait Emitter {
message: &'a DiagnosticMessage, message: &'a DiagnosticMessage,
args: &'a FluentArgs<'_>, args: &'a FluentArgs<'_>,
) -> Cow<'_, str> { ) -> Cow<'_, str> {
trace!(?message); trace!(?message, ?args);
let (identifier, attr) = match message { let (identifier, attr) = match message {
DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg), DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
@ -283,7 +283,13 @@ pub trait Emitter {
let mut err = vec![]; let mut err = vec![];
let translated = bundle.format_pattern(value, Some(&args), &mut err); let translated = bundle.format_pattern(value, Some(&args), &mut err);
trace!(?translated, ?err); trace!(?translated, ?err);
debug_assert!(err.is_empty()); debug_assert!(
err.is_empty(),
"identifier: {:?}, args: {:?}, errors: {:?}",
identifier,
args,
err
);
translated translated
} }

View file

@ -777,6 +777,17 @@ impl Handler {
result result
} }
/// Construct a builder at the `Warn` level with the `msg` and the `code`.
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
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`. /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
pub fn struct_span_fatal( pub fn struct_span_fatal(
&self, &self,

View file

@ -63,9 +63,14 @@ decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_fo
decl_derive!([Lift, attributes(lift)] => lift::lift_derive); decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
decl_derive!( decl_derive!(
[SessionDiagnostic, attributes( [SessionDiagnostic, attributes(
message, // struct attributes
lint, warning,
error, error,
// nested parts of struct attributes
code,
slug,
// field attributes
message,
label, label,
suggestion, suggestion,
suggestion_short, suggestion_short,

View file

@ -16,11 +16,11 @@ use std::collections::{BTreeSet, HashMap};
/// # extern crate rust_middle; /// # extern crate rust_middle;
/// # use rustc_middle::ty::Ty; /// # use rustc_middle::ty::Ty;
/// #[derive(SessionDiagnostic)] /// #[derive(SessionDiagnostic)]
/// #[code = "E0505"] /// #[error(code = "E0505", slug = "move-out-of-borrow-error")]
/// #[error = "cannot move out of {name} because it is borrowed"]
/// pub struct MoveOutOfBorrowError<'tcx> { /// pub struct MoveOutOfBorrowError<'tcx> {
/// pub name: Ident, /// pub name: Ident,
/// pub ty: Ty<'tcx>, /// pub ty: Ty<'tcx>,
/// #[message]
/// #[label = "cannot move out of borrow"] /// #[label = "cannot move out of borrow"]
/// pub span: Span, /// pub span: Span,
/// #[label = "`{ty}` first borrowed here"] /// #[label = "`{ty}` first borrowed here"]
@ -79,13 +79,6 @@ impl std::convert::From<syn::Error> 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)] #[derive(Debug)]
enum SessionDiagnosticDeriveError { enum SessionDiagnosticDeriveError {
SynError(syn::Error), SynError(syn::Error),
@ -100,7 +93,7 @@ impl SessionDiagnosticDeriveError {
// Return ! to avoid having to create a blank DiagnosticBuilder to return when an // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
// error has already been emitted to the compiler. // error has already been emitted to the compiler.
quote! { quote! {
unreachable!() { unreachable!(); }
} }
} }
} }
@ -152,17 +145,25 @@ impl<'a> SessionDiagnosticDerive<'a> {
} }
Self { Self {
builder: SessionDiagnosticDeriveBuilder { diag, sess, fields: fields_map, kind: None }, builder: SessionDiagnosticDeriveBuilder {
diag,
sess,
fields: fields_map,
kind: None,
code: None,
slug: None,
},
structure, structure,
} }
} }
fn into_tokens(self) -> proc_macro2::TokenStream { fn into_tokens(self) -> proc_macro2::TokenStream {
let SessionDiagnosticDerive { mut structure, mut builder } = self; let SessionDiagnosticDerive { mut structure, mut builder } = self;
let ast = structure.ast(); let ast = structure.ast();
let attrs = &ast.attrs; let attrs = &ast.attrs;
let implementation = { let (implementation, param_ty) = {
if let syn::Data::Struct(..) = ast.data { if let syn::Data::Struct(..) = ast.data {
let preamble = { let preamble = {
let preamble = attrs.iter().map(|attr| { let preamble = attrs.iter().map(|attr| {
@ -170,6 +171,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
.generate_structure_code(attr) .generate_structure_code(attr)
.unwrap_or_else(|v| v.to_compile_error()) .unwrap_or_else(|v| v.to_compile_error())
}); });
quote! { quote! {
#(#preamble)*; #(#preamble)*;
} }
@ -213,27 +215,54 @@ impl<'a> SessionDiagnosticDerive<'a> {
// it can be referred to by Fluent messages. // it can be referred to by Fluent messages.
if field.attrs.is_empty() { if field.attrs.is_empty() {
let diag = &builder.diag; 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()); } quote! { #diag.set_arg(stringify!(#ident), #field_binding.into_diagnostic_arg()); }
} else { } else {
quote! {} quote! {}
} }
}); });
// Finally, putting it altogether. let span = ast.span().unwrap();
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()
}
Some((kind, _)) => match kind {
DiagnosticId::Lint(_lint) => todo!(),
DiagnosticId::Error(code) => {
let (diag, sess) = (&builder.diag, &builder.sess); 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, _)), 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! { quote! {
let mut #diag = #sess.struct_err_with_code("", rustc_errors::DiagnosticId::Error(#code)); 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 #preamble
match self { match self {
#attrs #attrs
@ -242,29 +271,38 @@ impl<'a> SessionDiagnosticDerive<'a> {
#args #args
} }
#diag #diag
};
let param_ty = match builder.kind {
Some((SessionDiagnosticKind::Error, _)) => {
quote! { rustc_errors::ErrorGuaranteed }
} }
} Some((SessionDiagnosticKind::Warn, _)) => quote! { () },
}, _ => unreachable!(),
} };
(implementation, param_ty)
} else { } else {
span_err( span_err(
ast.span().unwrap(), ast.span().unwrap(),
"`#[derive(SessionDiagnostic)]` can only be used on structs", "`#[derive(SessionDiagnostic)]` can only be used on structs",
) )
.emit(); .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; let sess = &builder.sess;
structure.gen_impl(quote! { 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 for @Self
{ {
fn into_diagnostic( fn into_diagnostic(
self, self,
#sess: &'__session_diagnostic_sess rustc_session::Session #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; use rustc_errors::IntoDiagnosticArg;
#implementation #implementation
} }
@ -282,6 +320,25 @@ struct FieldInfo<'a> {
span: &'a proc_macro2::Span, 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 /// 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` /// 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 /// 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> { struct SessionDiagnosticDeriveBuilder<'a> {
/// Name of the session parameter that's passed in to the `as_error` method. /// Name of the session parameter that's passed in to the `as_error` method.
sess: syn::Ident, 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 /// Store a map of field name to its corresponding field. This is built on construction of the
/// derive builder. /// derive builder.
fields: HashMap<String, &'a syn::Field>, fields: HashMap<String, &'a syn::Field>,
/// The identifier to use for the generated `DiagnosticBuilder` instance. /// Kind of diagnostic requested via the struct attribute.
diag: syn::Ident, kind: Option<(SessionDiagnosticKind, proc_macro::Span)>,
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
/// Whether this is a lint or an error. This dictates how the diag will be initialised. `Span` /// has the actual diagnostic message.
/// stores at what `Span` the kind was first set at (for error reporting purposes, if the kind slug: Option<(String, proc_macro::Span)>,
/// was multiply specified). /// Error codes are a mandatory part of the struct attribute. Slugs may replace error codes
kind: Option<(DiagnosticId, proc_macro2::Span)>, /// in future but it is desirable to mandate error codes until such a time.
code: Option<(String, proc_macro::Span)>,
} }
impl<'a> SessionDiagnosticDeriveBuilder<'a> { 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( fn generate_structure_code(
&mut self, &mut self,
attr: &syn::Attribute, attr: &syn::Attribute,
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> { ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
Ok(match attr.parse_meta()? { let span = attr.span().unwrap();
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 = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
match name { let nested = match attr.parse_meta()? {
"message" => { syn::Meta::List(syn::MetaList { nested, .. }) => nested,
let diag = &self.diag; syn::Meta::Path(..) => throw_span_err!(
quote! { span,
#diag.set_primary_message(#formatted_str); &format!("`#[{}]` is not a valid `SessionDiagnostic` struct attribute", name)
} ),
} syn::Meta::NameValue(..) => throw_span_err!(
attr @ "error" | attr @ "lint" => { span,
self.set_kind_once( &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` struct attribute", name)
if attr == "error" { ),
DiagnosticId::Error(formatted_str) };
} else if attr == "lint" {
DiagnosticId::Lint(formatted_str) let kind = match name.as_str() {
} else { "error" => SessionDiagnosticKind::Error,
unreachable!() "warning" => SessionDiagnosticKind::Warn,
},
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!( other => throw_span_err!(
attr.span().unwrap(), 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!( &format!(
"`#[{} = ...]` is not a valid `SessionDiagnostic` struct attribute", "`#[{}(\"...\")]` is not a valid `SessionDiagnostic` struct attribute",
other 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();
} }
} }
_ => todo!("unhandled meta kind"), }
}) syn::Meta::NameValue(..) => {
span_err(
span,
&format!(
"`#[{}({} = ...)]` 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();
}
}
}
Ok(quote! {})
} }
#[must_use] #[must_use]
fn set_kind_once( fn set_kind_once(
&mut self, &mut self,
kind: DiagnosticId, kind: SessionDiagnosticKind,
span: proc_macro2::Span, span: proc_macro::Span,
) -> Result<(), SessionDiagnosticDeriveError> { ) -> Result<(), SessionDiagnosticDeriveError> {
if self.kind.is_none() { match self.kind {
None => {
self.kind = Some((kind, span)); self.kind = Some((kind, span));
Ok(()) Ok(())
} else { }
let kind_str = |kind: &DiagnosticId| match kind { Some((prev_kind, prev_span)) => {
DiagnosticId::Lint(..) => "lint", let existing = prev_kind.descr();
DiagnosticId::Error(..) => "error", let current = kind.descr();
};
let existing_kind = kind_str(&self.kind.as_ref().unwrap().0); let msg = if current == existing {
let this_kind = kind_str(&kind); format!("`{}` specified multiple times", existing)
let msg = if this_kind == existing_kind {
format!("`{}` specified multiple times", existing_kind)
} else { } else {
format!("`{}` specified when `{}` was already specified", this_kind, existing_kind) format!("`{}` specified when `{}` was already specified", current, existing)
}; };
throw_span_err!(span.unwrap(), &msg); throw_span_err!(span, &msg, |diag| diag
.span_note(prev_span, "previously specified here"));
}
}
}
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 = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str(); let name = name.as_str();
// At this point, we need to dispatch based on the attribute key + the
// type.
let meta = attr.parse_meta()?; let meta = attr.parse_meta()?;
match meta { match meta {
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { syn::Meta::Path(_) => match name {
let formatted_str = self.build_format(&s.value(), attr.span());
match name {
"message" => { "message" => {
if type_matches_path(&info.ty, &["rustc_span", "Span"]) { if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
return Ok(quote! { return Ok(quote! {
#diag.set_span(*#field_binding); #diag.set_span(*#field_binding);
#diag.set_primary_message(#formatted_str);
}); });
} else { } else {
throw_span_err!( throw_span_err!(
attr.span().unwrap(), attr.span().unwrap(),
"the `#[message = \"...\"]` attribute can only be applied to fields of type `Span`" "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 {
"label" => { "label" => {
if type_matches_path(&info.ty, &["rustc_span", "Span"]) { if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
return Ok(quote! { return Ok(quote! {
@ -441,7 +594,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
} else { } else {
throw_span_err!( throw_span_err!(
attr.span().unwrap(), 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`"
); );
} }
} }

View file

@ -21,7 +21,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_errors::{ use rustc_errors::{
fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
ErrorGuaranteed, FluentBundle, MultiSpan, EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan,
}; };
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId; 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 /// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. /// `#[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`. /// Write out as a diagnostic out of `sess`.
#[must_use] #[must_use]
fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, ErrorGuaranteed>; fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, T>;
} }
impl Session { impl Session {
@ -343,6 +343,13 @@ impl Session {
) -> DiagnosticBuilder<'_, ErrorGuaranteed> { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_err_with_code(msg, code) self.diagnostic().struct_err_with_code(msg, code)
} }
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn_with_code(msg, code)
}
pub fn struct_span_fatal<S: Into<MultiSpan>>( pub fn struct_span_fatal<S: Into<MultiSpan>>(
&self, &self,
sp: S, sp: S,
@ -409,6 +416,9 @@ impl Session {
pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
err.into_diagnostic(self).emit() err.into_diagnostic(self).emit()
} }
pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
warning.into_diagnostic(self).emit()
}
#[inline] #[inline]
pub fn err_count(&self) -> usize { pub fn err_count(&self) -> usize {
self.diagnostic().err_count() self.diagnostic().err_count()

View file

@ -3,9 +3,9 @@ use rustc_macros::SessionDiagnostic;
use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0062"] #[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")]
pub struct FieldMultiplySpecifiedInInitializer { pub struct FieldMultiplySpecifiedInInitializer {
#[message = "field `{ident}` specified more than once"] #[message]
#[label = "used more than once"] #[label = "used more than once"]
pub span: Span, pub span: Span,
#[label = "first use of `{ident}`"] #[label = "first use of `{ident}`"]
@ -14,19 +14,18 @@ pub struct FieldMultiplySpecifiedInInitializer {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0092"] #[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")]
pub struct UnrecognizedAtomicOperation<'a> { pub struct UnrecognizedAtomicOperation<'a> {
#[message = "unrecognized atomic operation function: `{op}`"] #[message]
#[label = "unrecognized atomic operation"] #[label = "unrecognized atomic operation"]
pub span: Span, pub span: Span,
pub op: &'a str, pub op: &'a str,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0094"] #[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")]
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[message = "intrinsic has wrong number of {descr} \ #[message]
parameters: found {found}, expected {expected}"]
#[label = "expected {expected} {descr} parameter{expected_pluralize}"] #[label = "expected {expected} {descr} parameter{expected_pluralize}"]
pub span: Span, pub span: Span,
pub found: usize, pub found: usize,
@ -36,18 +35,18 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0093"] #[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")]
pub struct UnrecognizedIntrinsicFunction { pub struct UnrecognizedIntrinsicFunction {
#[message = "unrecognized intrinsic function: `{name}`"] #[message]
#[label = "unrecognized intrinsic"] #[label = "unrecognized intrinsic"]
pub span: Span, pub span: Span,
pub name: Symbol, pub name: Symbol,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0195"] #[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait { 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"] #[label = "lifetimes do not match {item_kind} in trait"]
pub span: Span, pub span: Span,
#[label = "lifetimes in impl do not match this {item_kind} in trait"] #[label = "lifetimes in impl do not match this {item_kind} in trait"]
@ -57,18 +56,18 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0120"] #[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")]
pub struct DropImplOnWrongItem { 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"] #[label = "must be a struct, enum, or union"]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0124"] #[error(code = "E0124", slug = "typeck-field-already-declared")]
pub struct FieldAlreadyDeclared { pub struct FieldAlreadyDeclared {
pub field_name: Ident, pub field_name: Ident,
#[message = "field `{field_name}` is already declared"] #[message]
#[label = "field already declared"] #[label = "field already declared"]
pub span: Span, pub span: Span,
#[label = "`{field_name}` first declared here"] #[label = "`{field_name}` first declared here"]
@ -76,70 +75,69 @@ pub struct FieldAlreadyDeclared {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0184"] #[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")]
pub struct CopyImplOnTypeWithDtor { pub struct CopyImplOnTypeWithDtor {
#[message = "the trait `Copy` may not be implemented for this type; the \ #[message]
type has a destructor"]
#[label = "Copy not allowed on types with destructors"] #[label = "Copy not allowed on types with destructors"]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0203"] #[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")]
pub struct MultipleRelaxedDefaultBounds { pub struct MultipleRelaxedDefaultBounds {
#[message = "type parameter has more than one relaxed default bound, only one is supported"] #[message]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0206"] #[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")]
pub struct CopyImplOnNonAdt { pub struct CopyImplOnNonAdt {
#[message = "the trait `Copy` may not be implemented for this type"] #[message]
#[label = "type is not a structure or enumeration"] #[label = "type is not a structure or enumeration"]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0224"] #[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")]
pub struct TraitObjectDeclaredWithNoTraits { pub struct TraitObjectDeclaredWithNoTraits {
#[message = "at least one trait is required for an object type"] #[message]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0227"] #[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")]
pub struct AmbiguousLifetimeBound { pub struct AmbiguousLifetimeBound {
#[message = "ambiguous lifetime bound, explicit lifetime bound required"] #[message]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0229"] #[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")]
pub struct AssocTypeBindingNotAllowed { pub struct AssocTypeBindingNotAllowed {
#[message = "associated type bindings are not allowed here"] #[message]
#[label = "associated type not allowed here"] #[label = "associated type not allowed here"]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0436"] #[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")]
pub struct FunctionalRecordUpdateOnNonStruct { pub struct FunctionalRecordUpdateOnNonStruct {
#[message = "functional record update syntax requires a struct"] #[message]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0516"] #[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
pub struct TypeofReservedKeywordUsed { pub struct TypeofReservedKeywordUsed {
#[message = "`typeof` is a reserved keyword but unimplemented"] #[message]
#[label = "reserved keyword"] #[label = "reserved keyword"]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0572"] #[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")]
pub struct ReturnStmtOutsideOfFnBody { pub struct ReturnStmtOutsideOfFnBody {
#[message = "return statement outside of function body"] #[message]
pub span: Span, pub span: Span,
#[label = "the return is part of this body..."] #[label = "the return is part of this body..."]
pub encl_body_span: Option<Span>, pub encl_body_span: Option<Span>,
@ -148,31 +146,31 @@ pub struct ReturnStmtOutsideOfFnBody {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0627"] #[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")]
pub struct YieldExprOutsideOfGenerator { pub struct YieldExprOutsideOfGenerator {
#[message = "yield expression outside of generator literal"] #[message]
pub span: Span, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0639"] #[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")]
pub struct StructExprNonExhaustive { pub struct StructExprNonExhaustive {
#[message = "cannot create non-exhaustive {what} using struct expression"] #[message]
pub span: Span, pub span: Span,
pub what: &'static str, pub what: &'static str,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0699"] #[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")]
pub struct MethodCallOnUnknownType { 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, pub span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0719"] #[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")]
pub struct ValueOfAssociatedStructAlreadySpecified { pub struct ValueOfAssociatedStructAlreadySpecified {
#[message = "the value of the associated type `{item_name}` (from trait `{def_path}`) is already specified"] #[message]
#[label = "re-bound here"] #[label = "re-bound here"]
pub span: Span, pub span: Span,
#[label = "`{item_name}` bound here first"] #[label = "`{item_name}` bound here first"]
@ -182,9 +180,9 @@ pub struct ValueOfAssociatedStructAlreadySpecified {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0745"] #[error(code = "E0745", slug = "typeck-address-of-temporary-taken")]
pub struct AddressOfTemporaryTaken { pub struct AddressOfTemporaryTaken {
#[message = "cannot take address of a temporary"] #[message]
#[label = "temporary value"] #[label = "temporary value"]
pub span: Span, pub span: Span,
} }

View file

@ -26,12 +26,15 @@ use rustc_errors::Applicability;
extern crate rustc_session; extern crate rustc_session;
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[message = "Hello, world!"] #[error(code = "E0123", slug = "hello-world")]
#[error = "E0123"]
struct Hello {} struct Hello {}
#[derive(SessionDiagnostic)] #[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 //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs
enum SessionDiagnosticOnEnum { enum SessionDiagnosticOnEnum {
Foo, Foo,
@ -39,13 +42,46 @@ enum SessionDiagnosticOnEnum {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
#[error = "E0123"] #[error = "E0123"]
#[label = "This is in the wrong place"] //~^ ERROR `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute
//~^ ERROR `#[label = ...]` is not a valid `SessionDiagnostic` struct attribute struct WrongStructAttrStyle {}
struct WrongPlace {}
#[derive(SessionDiagnostic)] #[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 { struct WrongPlaceField {
#[suggestion = "this is the wrong kind of attribute"] #[suggestion = "this is the wrong kind of attribute"]
//~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute //~^ ERROR `#[suggestion = ...]` is not a valid `SessionDiagnostic` field attribute
@ -53,101 +89,113 @@ struct WrongPlaceField {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[message = "Hello, world!"] #[error(code = "E0123", slug = "foo")]
#[error = "E0123"] #[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times
#[error = "E0456"] //~ ERROR `error` specified multiple times
struct ErrorSpecifiedTwice {} struct ErrorSpecifiedTwice {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[message = "Hello, world!"] #[error(code = "E0123", slug = "foo")]
#[error = "E0123"] #[warning(code = "E0293", slug = "bar")]
#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified //~^ ERROR `warning` specified when `error` was already specified
struct LintSpecifiedAfterError {} struct WarnSpecifiedAfterError {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[message = "Some lint message"] #[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times
#[error = "E0123"] struct CodeSpecifiedTwice {}
struct LintButHasErrorCode {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
struct ErrorCodeNotProvided {} //~ ERROR `code` not specified #[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times
struct SlugSpecifiedTwice {}
// 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 {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[lint = "Some lint message"] struct KindNotProvided {} //~ ERROR diagnostic kind not specified
#[message = "Some error message"]
#[error = "E0123"] // ERROR `error` specified when `lint` was already specified
struct ErrorSpecifiedAfterLint {}
*/
#[derive(SessionDiagnostic)] #[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 { struct ErrorWithField {
name: String, name: String,
#[message = "This error has a field, and references {name}"] #[label = "This error has a field, and references {name}"]
span: Span, span: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct ErrorWithMessageAppliedToField { struct ErrorWithMessageAppliedToField {
#[message = "this message is applied to a String field"] #[label = "this message is applied to a String field"]
//~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type `Span` //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
name: String, name: String,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "This error has a field, and references {name}"]
//~^ ERROR `name` doesn't refer to a field on this type
struct ErrorWithNonexistentField { 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)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "This is missing a closing brace: {name"]
//~^ ERROR invalid format string: expected `'}'` //~^ ERROR invalid format string: expected `'}'`
struct ErrorMissingClosingBrace { struct ErrorMissingClosingBrace {
#[label = "This is missing a closing brace: {name"]
foo: Span,
name: String, name: String,
val: usize, val: usize,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "This is missing an opening brace: name}"]
//~^ ERROR invalid format string: unmatched `}` //~^ ERROR invalid format string: unmatched `}`
struct ErrorMissingOpeningBrace { struct ErrorMissingOpeningBrace {
#[label = "This is missing an opening brace: name}"]
foo: Span,
name: String, name: String,
val: usize, val: usize,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "Something something"]
struct LabelOnSpan { struct LabelOnSpan {
#[label = "See here"] #[label = "See here"]
sp: Span, sp: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "Something something"]
struct LabelOnNonSpan { struct LabelOnNonSpan {
#[label = "See here"] #[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, id: u32,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct Suggest { struct Suggest {
#[suggestion(message = "This is a suggestion", code = "This is the suggested code")] #[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")] #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")]
@ -157,14 +205,14 @@ struct Suggest {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithoutCode { struct SuggestWithoutCode {
#[suggestion(message = "This is a suggestion")] #[suggestion(message = "This is a suggestion")]
suggestion: (Span, Applicability), suggestion: (Span, Applicability),
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithBadKey { struct SuggestWithBadKey {
#[suggestion(nonsense = "This is nonsense")] #[suggestion(nonsense = "This is nonsense")]
//~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]`
@ -172,7 +220,7 @@ struct SuggestWithBadKey {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithShorthandMsg { struct SuggestWithShorthandMsg {
#[suggestion(msg = "This is a suggestion")] #[suggestion(msg = "This is a suggestion")]
//~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]`
@ -180,7 +228,7 @@ struct SuggestWithShorthandMsg {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithoutMsg { struct SuggestWithoutMsg {
#[suggestion(code = "This is suggested code")] #[suggestion(code = "This is suggested code")]
//~^ ERROR missing suggestion message //~^ ERROR missing suggestion message
@ -188,14 +236,14 @@ struct SuggestWithoutMsg {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithTypesSwapped { struct SuggestWithTypesSwapped {
#[suggestion(message = "This is a message", code = "This is suggested code")] #[suggestion(message = "This is a message", code = "This is suggested code")]
suggestion: (Applicability, Span), suggestion: (Applicability, Span),
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithWrongTypeApplicabilityOnly { struct SuggestWithWrongTypeApplicabilityOnly {
#[suggestion(message = "This is a message", code = "This is suggested code")] #[suggestion(message = "This is a message", code = "This is suggested code")]
//~^ ERROR wrong field type for suggestion //~^ ERROR wrong field type for suggestion
@ -203,14 +251,14 @@ struct SuggestWithWrongTypeApplicabilityOnly {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithSpanOnly { struct SuggestWithSpanOnly {
#[suggestion(message = "This is a message", code = "This is suggested code")] #[suggestion(message = "This is a message", code = "This is suggested code")]
suggestion: Span, suggestion: Span,
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithDuplicateSpanAndApplicability { struct SuggestWithDuplicateSpanAndApplicability {
#[suggestion(message = "This is a message", code = "This is suggested code")] #[suggestion(message = "This is a message", code = "This is suggested code")]
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span` //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
@ -218,7 +266,7 @@ struct SuggestWithDuplicateSpanAndApplicability {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct SuggestWithDuplicateApplicabilityAndSpan { struct SuggestWithDuplicateApplicabilityAndSpan {
#[suggestion(message = "This is a message", code = "This is suggested code")] #[suggestion(message = "This is a message", code = "This is suggested code")]
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
@ -226,7 +274,7 @@ struct SuggestWithDuplicateApplicabilityAndSpan {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct WrongKindOfAnnotation { struct WrongKindOfAnnotation {
#[label("wrong kind of annotation for label")] #[label("wrong kind of annotation for label")]
//~^ ERROR invalid annotation list `#[label(...)]` //~^ ERROR invalid annotation list `#[label(...)]`
@ -234,8 +282,7 @@ struct WrongKindOfAnnotation {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
#[message = "Something something else"]
struct OptionsInErrors { struct OptionsInErrors {
#[label = "Label message"] #[label = "Label message"]
label: Option<Span>, label: Option<Span>,
@ -244,11 +291,11 @@ struct OptionsInErrors {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0456"] #[error(code = "E0456", slug = "foo")]
struct MoveOutOfBorrowError<'tcx> { struct MoveOutOfBorrowError<'tcx> {
name: Ident, name: Ident,
ty: Ty<'tcx>, ty: Ty<'tcx>,
#[message = "cannot move {ty} out of borrow"] #[message]
#[label = "cannot move out of borrow"] #[label = "cannot move out of borrow"]
span: Span, span: Span,
#[label = "`{ty}` first borrowed here"] #[label = "`{ty}` first borrowed here"]
@ -258,9 +305,9 @@ struct MoveOutOfBorrowError<'tcx> {
} }
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error = "E0123"] #[error(code = "E0123", slug = "foo")]
struct ErrorWithLifetime<'a> { struct ErrorWithLifetime<'a> {
#[message = "Some message that references {name}"] #[label = "Some message that references {name}"]
span: Span, span: Span,
name: &'a str, name: &'a str,
} }

View file

@ -1,7 +1,7 @@
error: `#[derive(SessionDiagnostic)]` can only be used on structs 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 | |
LL | | enum SessionDiagnosticOnEnum { LL | | enum SessionDiagnosticOnEnum {
LL | | Foo, LL | | Foo,
@ -9,95 +9,221 @@ LL | | Bar,
LL | | } LL | | }
| |_^ | |_^
error: `#[label = ...]` is not a valid `SessionDiagnostic` struct attribute error: `#[error = ...]` is not a valid `SessionDiagnostic` struct attribute
--> $DIR/session-derive-errors.rs:43:1 --> $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 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"] LL | #[suggestion = "this is the wrong kind of attribute"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `error` specified multiple times 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: `warning` specified when `error` was already specified
--> $DIR/session-derive-errors.rs:98:1
|
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: `lint` specified when `error` was already specified error: `slug` specified multiple times
--> $DIR/session-derive-errors.rs:64:10 --> $DIR/session-derive-errors.rs:107:46
| |
LL | #[lint = "some_useful_lint"] 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 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` error: the `#[message]` attribute can only be applied to fields of type `Span`
--> $DIR/session-derive-errors.rs:101:5 --> $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 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 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)] LL | #[derive(SessionDiagnostic)]
| ----------------- in this derive macro expansion | ----------------- in this derive macro expansion
LL | #[error = "E0123"] LL | #[error(code = "E0123", slug = "foo")]
| - because of this opening brace | - ^ expected `'}'` in format string
LL | #[message = "This is missing a closing brace: {name"] | |
| ^ expected `'}'` in format string | because of this opening brace
| |
= note: if you intended to print `{`, you can escape it using `{{` = 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) = 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 error: invalid format string: unmatched `}` found
--> $DIR/session-derive-errors.rs:125:1 --> $DIR/session-derive-errors.rs:173:20
| |
LL | #[derive(SessionDiagnostic)] LL | #[derive(SessionDiagnostic)]
| ----------------- in this derive macro expansion | ----------------- in this derive macro expansion
LL | #[error = "E0123"] LL | #[error(code = "E0123", slug = "foo")]
LL | #[message = "This is missing an opening brace: name}"]
| ^ unmatched `}` in format string | ^ unmatched `}` in format string
| |
= note: if you intended to print `}`, you can escape it using `}}` = 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) = 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` error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
--> $DIR/session-derive-errors.rs:144:5 --> $DIR/session-derive-errors.rs:192:5
| |
LL | #[label = "See here"] LL | #[label = "See here"]
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: `nonsense` is not a valid key for `#[suggestion(...)]` 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")] LL | #[suggestion(nonsense = "This is nonsense")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `msg` is not a valid key for `#[suggestion(...)]` 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")] LL | #[suggestion(msg = "This is a suggestion")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing suggestion message 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")] 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 = "...")]` = help: provide a suggestion message using `#[suggestion(message = "...")]`
error: wrong field type for suggestion 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 | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | | LL | |
@ -115,7 +241,7 @@ LL | | suggestion: Applicability,
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, 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` 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 | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | | LL | |
@ -123,7 +249,7 @@ LL | | suggestion: (Span, Span, Applicability),
| |___________________________________________^ | |___________________________________________^
error: type of field annotated with `#[suggestion(...)]` contains more than one 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 | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | | LL | |
@ -131,10 +257,22 @@ LL | | suggestion: (Applicability, Applicability, Span),
| |____________________________________________________^ | |____________________________________________________^
error: invalid annotation list `#[label(...)]` 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")] 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