1
Fork 0

macros: optional error codes

In an effort to make it easier to port diagnostics to
`SessionDiagnostic` (for translation) and since translation slugs could
replace error codes, make error codes optional in the
`SessionDiagnostic` derive.

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-03-31 09:21:42 +01:00
parent 70ee0c96fc
commit 72dec56028
3 changed files with 21 additions and 34 deletions

View file

@ -229,38 +229,30 @@ impl<'a> SessionDiagnosticDerive<'a> {
let span = ast.span().unwrap(); let span = ast.span().unwrap();
let (diag, sess) = (&builder.diag, &builder.sess); let (diag, sess) = (&builder.diag, &builder.sess);
let init = match (builder.kind, builder.slug, builder.code) { let init = match (builder.kind, builder.slug) {
(None, _, _) => { (None, _) => {
span_err(span, "diagnostic kind not specified") span_err(span, "diagnostic kind not specified")
.help("use the `#[error(...)]` attribute to create an error") .help("use the `#[error(...)]` attribute to create an error")
.emit(); .emit();
return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
} }
(Some((kind, _)), None, _) => { (Some((kind, _)), None) => {
span_err(span, "`slug` not specified") span_err(span, "`slug` not specified")
.help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr())) .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr()))
.emit(); .emit();
return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
} }
(Some((kind, _)), _, None) => { (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
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( let mut #diag = #sess.struct_err(
rustc_errors::DiagnosticMessage::fluent(#slug), rustc_errors::DiagnosticMessage::fluent(#slug),
rustc_errors::DiagnosticId::Error(#code.to_string())
); );
} }
} }
(Some((SessionDiagnosticKind::Warn, _)), Some((slug, _)), Some((code, _))) => { (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
quote! { quote! {
let mut #diag = #sess.struct_warn_with_code( let mut #diag = #sess.struct_warn(
rustc_errors::DiagnosticMessage::fluent(#slug), rustc_errors::DiagnosticMessage::fluent(#slug),
rustc_errors::DiagnosticId::Error(#code.to_string())
); );
} }
} }
@ -363,9 +355,9 @@ struct SessionDiagnosticDeriveBuilder<'a> {
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
/// has the actual diagnostic message. /// has the actual diagnostic message.
slug: Option<(String, proc_macro::Span)>, slug: Option<(String, proc_macro::Span)>,
/// Error codes are a mandatory part of the struct attribute. Slugs may replace error codes /// Error codes are a optional part of the struct attribute - this is only set to detect
/// in future but it is desirable to mandate error codes until such a time. /// multiple specifications.
code: Option<(String, proc_macro::Span)>, code: Option<proc_macro::Span>,
} }
impl<'a> SessionDiagnosticDeriveBuilder<'a> { impl<'a> SessionDiagnosticDeriveBuilder<'a> {
@ -403,6 +395,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
}; };
self.set_kind_once(kind, span)?; self.set_kind_once(kind, span)?;
let mut tokens = Vec::new();
for attr in nested { for attr in nested {
let span = attr.span().unwrap(); let span = attr.span().unwrap();
let meta = match attr { let meta = match attr {
@ -427,7 +420,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
self.set_slug_once(s.value(), s.span().unwrap()); self.set_slug_once(s.value(), s.span().unwrap());
} }
"code" => { "code" => {
self.set_code_once(s.value(), s.span().unwrap()); tokens.push(self.set_code_once(s.value(), s.span().unwrap()));
} }
other => { other => {
let diag = span_err( let diag = span_err(
@ -475,7 +468,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
} }
} }
Ok(quote! {}) Ok(tokens.drain(..).collect())
} }
#[must_use] #[must_use]
@ -504,17 +497,20 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
} }
} }
fn set_code_once(&mut self, code: String, span: proc_macro::Span) { fn set_code_once(&mut self, code: String, span: proc_macro::Span) -> proc_macro2::TokenStream {
match self.code { match self.code {
None => { None => {
self.code = Some((code, span)); self.code = Some(span);
} }
Some((_, prev_span)) => { Some(prev_span) => {
span_err(span, "`code` specified multiple times") span_err(span, "`code` specified multiple times")
.span_note(prev_span, "previously specified here") .span_note(prev_span, "previously specified here")
.emit(); .emit();
} }
} }
let diag = &self.diag;
quote! { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }
} }
fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) { fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) {

View file

@ -115,7 +115,7 @@ struct KindNotProvided {} //~ ERROR diagnostic kind not specified
struct SlugNotProvided {} struct SlugNotProvided {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]
#[error(slug = "foo")] //~ ERROR `code` not specified #[error(slug = "foo")]
struct CodeNotProvided {} struct CodeNotProvided {}
#[derive(SessionDiagnostic)] #[derive(SessionDiagnostic)]

View file

@ -147,15 +147,6 @@ LL | | struct SlugNotProvided {}
| |
= help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
error: `code` not specified
--> $DIR/session-derive-errors.rs:118:1
|
LL | / #[error(slug = "foo")]
LL | | struct CodeNotProvided {}
| |_________________________^
|
= help: use the `#[error(code = "...")]` attribute to set this diagnostic's error code
error: the `#[primary_span]` attribute can only be applied to fields of type `Span` error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
--> $DIR/session-derive-errors.rs:124:5 --> $DIR/session-derive-errors.rs:124:5
| |
@ -285,6 +276,6 @@ LL | #[derive(SessionDiagnostic)]
| |
= 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: aborting due to 35 previous errors error: aborting due to 34 previous errors
For more information about this error, try `rustc --explain E0599`. For more information about this error, try `rustc --explain E0599`.