diff options
| author | David Wood <david.wood@huawei.com> | 2022-03-31 12:10:00 +0100 |
|---|---|---|
| committer | David Wood <david.wood@huawei.com> | 2022-04-05 07:01:03 +0100 |
| commit | b40ee88a28938891dd40d35a635d13373c3011cb (patch) | |
| tree | 205667c818313077c5df996c430293376daeb726 | |
| parent | a88717cef051b8ebbed0e74c57fc0a714bd893dc (diff) | |
| download | rust-b40ee88a28938891dd40d35a635d13373c3011cb.tar.gz rust-b40ee88a28938891dd40d35a635d13373c3011cb.zip | |
macros: note/help in `SessionDiagnostic` derive
Signed-off-by: David Wood <david.wood@huawei.com>
| -rw-r--r-- | compiler/rustc_macros/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/session_diagnostic.rs | 52 | ||||
| -rw-r--r-- | src/test/ui-fulldeps/session-derive-errors.rs | 88 | ||||
| -rw-r--r-- | src/test/ui-fulldeps/session-derive-errors.stderr | 26 |
4 files changed, 158 insertions, 10 deletions
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 67b56d2e9db..3589860eb0e 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -66,6 +66,8 @@ decl_derive!( // struct attributes warning, error, + note, + help, // field attributes skip_arg, primary_span, diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index efbffabbd03..c7ee72907b5 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -362,18 +362,52 @@ struct 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`. + /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates + /// diagnostic builder calls for setting error code and creating note/help messages. fn generate_structure_code( &mut self, attr: &syn::Attribute, ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> { let span = attr.span().unwrap(); + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + let meta = attr.parse_meta()?; + + if matches!(name, "help" | "note") + && matches!(meta, syn::Meta::Path(_) | syn::Meta::NameValue(_)) + { + let diag = &self.diag; + let slug = match &self.slug { + Some((slug, _)) => slug.as_str(), + None => throw_span_err!( + span, + &format!( + "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`", + name, + match meta { + syn::Meta::Path(_) => "", + syn::Meta::NameValue(_) => " = ...", + _ => unreachable!(), + } + ) + ), + }; + let id = match meta { + syn::Meta::Path(..) => quote! { #name }, + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + quote! { #s } + } + _ => unreachable!(), + }; + let fn_name = proc_macro2::Ident::new(name, attr.span()); + + return Ok(quote! { + #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id)); + }); + } - let nested = match attr.parse_meta()? { + let nested = match meta { syn::Meta::List(syn::MetaList { nested, .. }) => nested, syn::Meta::Path(..) => throw_span_err!( span, @@ -385,7 +419,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ), }; - let kind = match name.as_str() { + let kind = match name { "error" => SessionDiagnosticKind::Error, "warning" => SessionDiagnosticKind::Warn, other => throw_span_err!( @@ -579,9 +613,9 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { #diag.set_span(*#field_binding); }) } - "label" => { + "label" | "note" | "help" => { self.report_error_if_not_applied_to_span(attr, info)?; - Ok(self.add_subdiagnostic(field_binding, name, "label")) + Ok(self.add_subdiagnostic(field_binding, name, name)) } other => throw_span_err!( attr.span().unwrap(), @@ -589,7 +623,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> { ), }, syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name { - "label" => { + "label" | "note" | "help" => { self.report_error_if_not_applied_to_span(attr, info)?; Ok(self.add_subdiagnostic(field_binding, name, &s.value())) } diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs index 68f24f1f685..a3ae3c9a14d 100644 --- a/src/test/ui-fulldeps/session-derive-errors.rs +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -339,3 +339,91 @@ struct ArgFieldWithSkip { #[skip_arg] other: Hello, } + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedNote { + #[note] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedNoteCustom { + #[note = "bar"] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[note] +struct ErrorWithNote { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[note = "bar"] +struct ErrorWithNoteCustom { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedHelp { + #[help] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +struct ErrorWithSpannedHelpCustom { + #[help = "bar"] + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[help] +struct ErrorWithHelp { + val: String, +} + +#[derive(SessionDiagnostic)] +#[error(code = "E0123", slug = "foo")] +#[help = "bar"] +struct ErrorWithHelpCustom { + val: String, +} + +#[derive(SessionDiagnostic)] +#[help] +//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithHelpWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[help = "bar"] +//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithHelpCustomWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[note] +//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithNoteWrongOrder { + val: String, +} + +#[derive(SessionDiagnostic)] +#[note = "bar"] +//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` +#[error(code = "E0123", slug = "foo")] +struct ErrorWithNoteCustomWrongOrder { + val: String, +} diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr index 902bc785ce7..dc8e807cea3 100644 --- a/src/test/ui-fulldeps/session-derive-errors.stderr +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -249,6 +249,30 @@ error: invalid annotation list `#[label(...)]` LL | #[label("bar")] | ^^^^^^^^^^^^ +error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:400:1 + | +LL | #[help] + | ^^^^^^^ + +error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:408:1 + | +LL | #[help = "bar"] + | ^^^^^^^^^^^^^^^ + +error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:416:1 + | +LL | #[note] + | ^^^^^^^ + +error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` + --> $DIR/session-derive-errors.rs:424:1 + | +LL | #[note = "bar"] + | ^^^^^^^^^^^^^^^ + error: cannot find attribute `nonsense` in this scope --> $DIR/session-derive-errors.rs:51:3 | @@ -272,6 +296,6 @@ LL | #[derive(SessionDiagnostic)] | = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 34 previous errors +error: aborting due to 38 previous errors For more information about this error, try `rustc --explain E0599`. |
