diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 2199ceee532..2628f247c54 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -213,3 +213,13 @@ resolve_tool_module_imported = 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 07aaaa1eb7f..afa796cb645 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -481,3 +481,30 @@ pub(crate) struct ToolModuleImported { #[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) add_as_non_derive: 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 AddAsNonDerive<'a> { + pub(crate) macro_path: &'a str, +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 48707d37a10..22b014c0651 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::{AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -543,12 +544,29 @@ 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); - self.tcx - .sess - .struct_span_err(path.span, &msg) - .span_label(path.span, format!("not {} {}", article, expected)) - .emit(); + + 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() if the macro isn't Derive + if !path.span.from_expansion() + && kind == MacroKind::Derive + && ext.macro_kind() != MacroKind::Derive + { + err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); + err.add_as_non_derive = Some(AddAsNonDerive { 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 dfd6818b678..81c6722b56a 100644 --- a/tests/ui/macros/macro-path-prelude-fail-4.stderr +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -3,6 +3,14 @@ error: expected derive macro, found built-in attribute `inline` | LL | #[derive(inline)] | ^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-4.rs:1:10 + | +LL | #[derive(inline)] + | ^^^^^^ + = help: add as non-Derive macro + `#[inline]` error: aborting due to previous error diff --git a/tests/ui/macros/macro-path-prelude-fail-5.rs b/tests/ui/macros/macro-path-prelude-fail-5.rs new file mode 100644 index 00000000000..b82b6bc7878 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-5.rs @@ -0,0 +1,10 @@ +#[derive(Clone, Debug)] // OK +struct S; + +#[derive(Debug, inline)] //~ ERROR expected derive macro, found built-in attribute `inline` +struct T; + +#[derive(inline, Debug)] //~ ERROR expected derive macro, found built-in attribute `inline` +struct U; + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-fail-5.stderr b/tests/ui/macros/macro-path-prelude-fail-5.stderr new file mode 100644 index 00000000000..105c59db674 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-5.stderr @@ -0,0 +1,30 @@ +error: expected derive macro, found built-in attribute `inline` + --> $DIR/macro-path-prelude-fail-5.rs:4:17 + | +LL | #[derive(Debug, inline)] + | ^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-5.rs:4:17 + | +LL | #[derive(Debug, inline)] + | ^^^^^^ + = help: add as non-Derive macro + `#[inline]` + +error: expected derive macro, found built-in attribute `inline` + --> $DIR/macro-path-prelude-fail-5.rs:7:10 + | +LL | #[derive(inline, Debug)] + | ^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/macro-path-prelude-fail-5.rs:7:10 + | +LL | #[derive(inline, Debug)] + | ^^^^^^ + = help: add as non-Derive macro + `#[inline]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index 633a6c6a0d3..b9effe7cf21 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -57,6 +57,14 @@ 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()` + --> $DIR/macro-namespace-reserved-2.rs:53:10 + | +LL | #[derive(my_macro_attr)] + | ^^^^^^^^^^^^^ + = help: add as non-Derive macro + `#[my_macro_attr]` error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:56:10 @@ -87,6 +95,14 @@ error: expected derive macro, found macro `crate::my_macro` | LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ not a derive macro + | +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 + `#[crate::my_macro]` error: cannot find macro `my_macro_attr` in this scope --> $DIR/macro-namespace-reserved-2.rs:28:5 diff --git a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr index 6d0f826e621..06696b548d4 100644 --- a/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -3,6 +3,14 @@ error: expected derive macro, found tool attribute `rustfmt::skip` | LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ not a derive macro + | +help: remove from the surrounding `derive()` + --> $DIR/tool-attributes-misplaced-2.rs:1:10 + | +LL | #[derive(rustfmt::skip)] + | ^^^^^^^^^^^^^ + = help: add as non-Derive macro + `#[rustfmt::skip]` error: expected macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:5:5