diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 817bb83ed78..07865044f05 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -209,3 +209,13 @@ resolve_indeterminate = resolve_module_only = visibility must resolve to a module + +resolve_macro_expected_found = + expected {$expected}, found {$found} `{$macro_path}` + +resolve_remove_surrounding_derive = + remove from the surrounding `derive()` + +resolve_add_as_non_derive = + add as non-Derive macro + `#[{$macro_path}]` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 867363f4246..ff44ccb265a 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -472,3 +472,30 @@ pub(crate) struct ExpectedFound { #[derive(Diagnostic)] #[diag(resolve_module_only)] pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); + +#[derive(Diagnostic, Default)] +#[diag(resolve_macro_expected_found)] +pub(crate) struct MacroExpectedFound<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) found: &'a str, + pub(crate) expected: &'a str, + pub(crate) macro_path: &'a str, + #[subdiagnostic] + pub(crate) remove_surrounding_derive: Option, + #[subdiagnostic] + pub(crate) remove_surrounding_derive_help: Option>, +} + +#[derive(Subdiagnostic)] +#[help(resolve_remove_surrounding_derive)] +pub(crate) struct RemoveSurroundingDerive { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[help(resolve_add_as_non_derive)] +pub(crate) struct RemoveAddAsNonDerive<'a> { + pub(crate) macro_path: &'a str, +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ed479d289d7..b2e23721295 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,6 +1,7 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. +use crate::errors::{MacroExpectedFound, RemoveAddAsNonDerive, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -543,21 +544,30 @@ fn smart_resolve_macro_path( }; if let Some((article, expected)) = unexpected_res { let path_str = pprust::path_to_string(path); - let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); - let mut err = self.tcx.sess.struct_span_err(path.span, &msg); - err.span_label(path.span, format!("not {} {}", article, expected)); + let mut err = MacroExpectedFound { + span: path.span, + expected, + found: res.descr(), + macro_path: &path_str, + ..Default::default() // Subdiagnostics default to None + }; - // Suggest moving the macro out of the derive() as the macro isn't Derive + // Suggest moving the macro out of the derive() if the macro isn't Derive if !path.span.from_expansion() && kind == MacroKind::Derive && ext.macro_kind() != MacroKind::Derive { - err.span_help(path.span, "remove from the surrounding `derive()`"); - err.help(format!("add as non-Derive macro\n`#[{}]`", path_str)); + err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); + err.remove_surrounding_derive_help = + Some(RemoveAddAsNonDerive { macro_path: &path_str }); } + let mut err = self.tcx.sess.create_err(err); + err.span_label(path.span, format!("not {} {}", article, expected)); + err.emit(); + return Ok((self.dummy_ext(kind), Res::Err)); } diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr index 0dd67e6726c..81c6722b56a 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -4,12 +4,12 @@ error: expected derive macro, found built-in attribute `inline` LL | #[derive(inline)] | ^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] | ^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[inline]` error: aborting due to previous error diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index d0f829b5091..b9effe7cf21 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -58,12 +58,12 @@ error: expected derive macro, found attribute macro `my_macro_attr` LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-namespace-reserved-2.rs:53:10 | LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[my_macro_attr]` error: can't use a procedural macro from the same crate that defines it @@ -96,12 +96,12 @@ error: expected derive macro, found macro `crate::my_macro` LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/macro-namespace-reserved-2.rs:50:10 | LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[crate::my_macro]` error: cannot find macro `my_macro_attr` in this scope diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index b1ecd528938..06696b548d4 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -4,12 +4,12 @@ error: expected derive macro, found tool attribute `rustfmt::skip` LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ not a derive macro | -help: Remove from the surrounding `derive()` +help: remove from the surrounding `derive()` --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ - = help: Add as non-Derive macro + = help: add as non-Derive macro `#[rustfmt::skip]` error: expected macro, found tool attribute `rustfmt::skip`