Skip to content

Commit 2647a48

Browse files
committed
macros: reuse SetOnce trait in diagnostic derive
`SetOnce` trait was introduced in the subdiagnostic derive to simplify the code a little bit, re-use it in the diagnostic derive too. Signed-off-by: David Wood <[email protected]>
1 parent 36a396c commit 2647a48

File tree

3 files changed

+102
-96
lines changed

3 files changed

+102
-96
lines changed

compiler/rustc_macros/src/diagnostics/diagnostic.rs

Lines changed: 11 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use crate::diagnostics::error::{
55
SessionDiagnosticDeriveError,
66
};
77
use crate::diagnostics::utils::{
8-
option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, FieldInfo, HasFieldMap,
8+
option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, FieldInfo,
9+
HasFieldMap, SetOnce,
910
};
1011
use proc_macro2::TokenStream;
1112
use quote::{format_ident, quote};
@@ -240,7 +241,7 @@ struct SessionDiagnosticDeriveBuilder {
240241
slug: Option<(String, proc_macro::Span)>,
241242
/// Error codes are a optional part of the struct attribute - this is only set to detect
242243
/// multiple specifications.
243-
code: Option<proc_macro::Span>,
244+
code: Option<(String, proc_macro::Span)>,
244245
}
245246

246247
impl HasFieldMap for SessionDiagnosticDeriveBuilder {
@@ -306,7 +307,7 @@ impl SessionDiagnosticDeriveBuilder {
306307
diag.help("only `error` and `warning` are valid attributes")
307308
}),
308309
};
309-
self.set_kind_once(kind, span)?;
310+
self.kind.set_once((kind, span));
310311

311312
let mut tokens = Vec::new();
312313
for nested_attr in nested {
@@ -321,12 +322,17 @@ impl SessionDiagnosticDeriveBuilder {
321322
// Struct attributes are only allowed to be applied once, and the diagnostic
322323
// changes will be set in the initialisation code.
323324
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
325+
let span = s.span().unwrap();
324326
match nested_name.as_str() {
325327
"slug" => {
326-
self.set_slug_once(s.value(), s.span().unwrap());
328+
self.slug.set_once((s.value(), span));
327329
}
328330
"code" => {
329-
tokens.push(self.set_code_once(s.value(), s.span().unwrap()));
331+
self.code.set_once((s.value(), span));
332+
let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v));
333+
tokens.push(quote! {
334+
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
335+
});
330336
}
331337
_ => invalid_nested_attr(attr, &nested_attr)
332338
.help("only `slug` and `code` are valid nested attributes")
@@ -340,61 +346,6 @@ impl SessionDiagnosticDeriveBuilder {
340346
Ok(tokens.drain(..).collect())
341347
}
342348

343-
#[must_use]
344-
fn set_kind_once(
345-
&mut self,
346-
kind: SessionDiagnosticKind,
347-
span: proc_macro::Span,
348-
) -> Result<(), SessionDiagnosticDeriveError> {
349-
match self.kind {
350-
None => {
351-
self.kind = Some((kind, span));
352-
Ok(())
353-
}
354-
Some((prev_kind, prev_span)) => {
355-
let existing = prev_kind.descr();
356-
let current = kind.descr();
357-
358-
let msg = if current == existing {
359-
format!("`{}` specified multiple times", existing)
360-
} else {
361-
format!("`{}` specified when `{}` was already specified", current, existing)
362-
};
363-
throw_span_err!(span, &msg, |diag| diag
364-
.span_note(prev_span, "previously specified here"));
365-
}
366-
}
367-
}
368-
369-
fn set_code_once(&mut self, code: String, span: proc_macro::Span) -> TokenStream {
370-
match self.code {
371-
None => {
372-
self.code = Some(span);
373-
}
374-
Some(prev_span) => {
375-
span_err(span, "`code` specified multiple times")
376-
.span_note(prev_span, "previously specified here")
377-
.emit();
378-
}
379-
}
380-
381-
let diag = &self.diag;
382-
quote! { #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); }
383-
}
384-
385-
fn set_slug_once(&mut self, slug: String, span: proc_macro::Span) {
386-
match self.slug {
387-
None => {
388-
self.slug = Some((slug, span));
389-
}
390-
Some((_, prev_span)) => {
391-
span_err(span, "`slug` specified multiple times")
392-
.span_note(prev_span, "previously specified here")
393-
.emit();
394-
}
395-
}
396-
}
397-
398349
fn generate_field_attr_code(
399350
&mut self,
400351
attr: &syn::Attribute,

src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,28 @@ struct WrongPlaceField {
9090

9191
#[derive(SessionDiagnostic)]
9292
#[error(code = "E0123", slug = "foo")]
93-
#[error(code = "E0456", slug = "bar")] //~ ERROR `error` specified multiple times
93+
#[error(code = "E0456", slug = "bar")]
94+
//~^ ERROR specified multiple times
95+
//~^^ ERROR specified multiple times
96+
//~^^^ ERROR specified multiple times
9497
struct ErrorSpecifiedTwice {}
9598

9699
#[derive(SessionDiagnostic)]
97100
#[error(code = "E0123", slug = "foo")]
98101
#[warning(code = "E0293", slug = "bar")]
99-
//~^ ERROR `warning` specified when `error` was already specified
102+
//~^ ERROR specified multiple times
103+
//~^^ ERROR specified multiple times
104+
//~^^^ ERROR specified multiple times
100105
struct WarnSpecifiedAfterError {}
101106

102107
#[derive(SessionDiagnostic)]
103-
#[error(code = "E0456", code = "E0457", slug = "bar")] //~ ERROR `code` specified multiple times
108+
#[error(code = "E0456", code = "E0457", slug = "bar")]
109+
//~^ ERROR specified multiple times
104110
struct CodeSpecifiedTwice {}
105111

106112
#[derive(SessionDiagnostic)]
107-
#[error(code = "E0456", slug = "foo", slug = "bar")] //~ ERROR `slug` specified multiple times
113+
#[error(code = "E0456", slug = "foo", slug = "bar")]
114+
//~^ ERROR specified multiple times
108115
struct SlugSpecifiedTwice {}
109116

110117
#[derive(SessionDiagnostic)]

0 commit comments

Comments
 (0)