Skip to content

Commit b40ee88

Browse files
committed
macros: note/help in SessionDiagnostic derive
Signed-off-by: David Wood <david.wood@huawei.com>
1 parent a88717c commit b40ee88

File tree

4 files changed

+158
-10
lines changed

4 files changed

+158
-10
lines changed

compiler/rustc_macros/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ decl_derive!(
6666
// struct attributes
6767
warning,
6868
error,
69+
note,
70+
help,
6971
// field attributes
7072
skip_arg,
7173
primary_span,

compiler/rustc_macros/src/session_diagnostic.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -362,18 +362,52 @@ struct SessionDiagnosticDeriveBuilder<'a> {
362362

363363
impl<'a> SessionDiagnosticDeriveBuilder<'a> {
364364
/// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
365-
/// attributes like `#[error(..)#`, such as the diagnostic kind, slug and code.
366-
///
367-
/// Returns a `proc_macro2::TokenStream` so that the `Err(..)` variant can be transformed into
368-
/// the same type via `to_compile_error`.
365+
/// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates
366+
/// diagnostic builder calls for setting error code and creating note/help messages.
369367
fn generate_structure_code(
370368
&mut self,
371369
attr: &syn::Attribute,
372370
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
373371
let span = attr.span().unwrap();
372+
374373
let name = attr.path.segments.last().unwrap().ident.to_string();
374+
let name = name.as_str();
375+
let meta = attr.parse_meta()?;
376+
377+
if matches!(name, "help" | "note")
378+
&& matches!(meta, syn::Meta::Path(_) | syn::Meta::NameValue(_))
379+
{
380+
let diag = &self.diag;
381+
let slug = match &self.slug {
382+
Some((slug, _)) => slug.as_str(),
383+
None => throw_span_err!(
384+
span,
385+
&format!(
386+
"`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`",
387+
name,
388+
match meta {
389+
syn::Meta::Path(_) => "",
390+
syn::Meta::NameValue(_) => " = ...",
391+
_ => unreachable!(),
392+
}
393+
)
394+
),
395+
};
396+
let id = match meta {
397+
syn::Meta::Path(..) => quote! { #name },
398+
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
399+
quote! { #s }
400+
}
401+
_ => unreachable!(),
402+
};
403+
let fn_name = proc_macro2::Ident::new(name, attr.span());
404+
405+
return Ok(quote! {
406+
#diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
407+
});
408+
}
375409

376-
let nested = match attr.parse_meta()? {
410+
let nested = match meta {
377411
syn::Meta::List(syn::MetaList { nested, .. }) => nested,
378412
syn::Meta::Path(..) => throw_span_err!(
379413
span,
@@ -385,7 +419,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
385419
),
386420
};
387421

388-
let kind = match name.as_str() {
422+
let kind = match name {
389423
"error" => SessionDiagnosticKind::Error,
390424
"warning" => SessionDiagnosticKind::Warn,
391425
other => throw_span_err!(
@@ -579,17 +613,17 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
579613
#diag.set_span(*#field_binding);
580614
})
581615
}
582-
"label" => {
616+
"label" | "note" | "help" => {
583617
self.report_error_if_not_applied_to_span(attr, info)?;
584-
Ok(self.add_subdiagnostic(field_binding, name, "label"))
618+
Ok(self.add_subdiagnostic(field_binding, name, name))
585619
}
586620
other => throw_span_err!(
587621
attr.span().unwrap(),
588622
&format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other)
589623
),
590624
},
591625
syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name {
592-
"label" => {
626+
"label" | "note" | "help" => {
593627
self.report_error_if_not_applied_to_span(attr, info)?;
594628
Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
595629
}

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,91 @@ struct ArgFieldWithSkip {
339339
#[skip_arg]
340340
other: Hello,
341341
}
342+
343+
#[derive(SessionDiagnostic)]
344+
#[error(code = "E0123", slug = "foo")]
345+
struct ErrorWithSpannedNote {
346+
#[note]
347+
span: Span,
348+
}
349+
350+
#[derive(SessionDiagnostic)]
351+
#[error(code = "E0123", slug = "foo")]
352+
struct ErrorWithSpannedNoteCustom {
353+
#[note = "bar"]
354+
span: Span,
355+
}
356+
357+
#[derive(SessionDiagnostic)]
358+
#[error(code = "E0123", slug = "foo")]
359+
#[note]
360+
struct ErrorWithNote {
361+
val: String,
362+
}
363+
364+
#[derive(SessionDiagnostic)]
365+
#[error(code = "E0123", slug = "foo")]
366+
#[note = "bar"]
367+
struct ErrorWithNoteCustom {
368+
val: String,
369+
}
370+
371+
#[derive(SessionDiagnostic)]
372+
#[error(code = "E0123", slug = "foo")]
373+
struct ErrorWithSpannedHelp {
374+
#[help]
375+
span: Span,
376+
}
377+
378+
#[derive(SessionDiagnostic)]
379+
#[error(code = "E0123", slug = "foo")]
380+
struct ErrorWithSpannedHelpCustom {
381+
#[help = "bar"]
382+
span: Span,
383+
}
384+
385+
#[derive(SessionDiagnostic)]
386+
#[error(code = "E0123", slug = "foo")]
387+
#[help]
388+
struct ErrorWithHelp {
389+
val: String,
390+
}
391+
392+
#[derive(SessionDiagnostic)]
393+
#[error(code = "E0123", slug = "foo")]
394+
#[help = "bar"]
395+
struct ErrorWithHelpCustom {
396+
val: String,
397+
}
398+
399+
#[derive(SessionDiagnostic)]
400+
#[help]
401+
//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
402+
#[error(code = "E0123", slug = "foo")]
403+
struct ErrorWithHelpWrongOrder {
404+
val: String,
405+
}
406+
407+
#[derive(SessionDiagnostic)]
408+
#[help = "bar"]
409+
//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
410+
#[error(code = "E0123", slug = "foo")]
411+
struct ErrorWithHelpCustomWrongOrder {
412+
val: String,
413+
}
414+
415+
#[derive(SessionDiagnostic)]
416+
#[note]
417+
//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
418+
#[error(code = "E0123", slug = "foo")]
419+
struct ErrorWithNoteWrongOrder {
420+
val: String,
421+
}
422+
423+
#[derive(SessionDiagnostic)]
424+
#[note = "bar"]
425+
//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
426+
#[error(code = "E0123", slug = "foo")]
427+
struct ErrorWithNoteCustomWrongOrder {
428+
val: String,
429+
}

src/test/ui-fulldeps/session-derive-errors.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,30 @@ error: invalid annotation list `#[label(...)]`
249249
LL | #[label("bar")]
250250
| ^^^^^^^^^^^^
251251

252+
error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]`
253+
--> $DIR/session-derive-errors.rs:400:1
254+
|
255+
LL | #[help]
256+
| ^^^^^^^
257+
258+
error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]`
259+
--> $DIR/session-derive-errors.rs:408:1
260+
|
261+
LL | #[help = "bar"]
262+
| ^^^^^^^^^^^^^^^
263+
264+
error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]`
265+
--> $DIR/session-derive-errors.rs:416:1
266+
|
267+
LL | #[note]
268+
| ^^^^^^^
269+
270+
error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]`
271+
--> $DIR/session-derive-errors.rs:424:1
272+
|
273+
LL | #[note = "bar"]
274+
| ^^^^^^^^^^^^^^^
275+
252276
error: cannot find attribute `nonsense` in this scope
253277
--> $DIR/session-derive-errors.rs:51:3
254278
|
@@ -272,6 +296,6 @@ LL | #[derive(SessionDiagnostic)]
272296
|
273297
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
274298

275-
error: aborting due to 34 previous errors
299+
error: aborting due to 38 previous errors
276300

277301
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)