about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-10 21:50:46 +0000
committerbors <bors@rust-lang.org>2023-04-10 21:50:46 +0000
commit194a0bb5d6fbdd36e0df58b4698311bb8fed6bca (patch)
tree6c3419ffdd07c011177621862badf4991e6b8ffd
parent88fb1b922b047981fc0cfc62aa1418b4361ae72e (diff)
parent668a62984ac51a09987c5b1a7c1589814f7a95d4 (diff)
downloadrust-194a0bb5d6fbdd36e0df58b4698311bb8fed6bca.tar.gz
rust-194a0bb5d6fbdd36e0df58b4698311bb8fed6bca.zip
Auto merge of #109638 - NotStirred:suggest/non-derive, r=davidtwco
Add suggestion to remove `derive()` if invoked macro is non-derive

Adds to the existing `expected derive macro, found {}` error message:
```
help: remove the surrounding "derive()":
  --> $DIR/macro-path-prelude-fail-4.rs:1:3
   |
LL | #[derive(inline)]
   |   ^^^^^^^      ^
```

This suggestion will either fix the issue, in the case that the macro was valid, or provide a better error message if not

Not ready for merge yet, as the highlighted span is only valid for trivial formatting. Is there a nice way to get the parent span of the macro path within `smart_resolve_macro_path`?

Closes #109589
-rw-r--r--compiler/rustc_resolve/messages.ftl10
-rw-r--r--compiler/rustc_resolve/src/errors.rs27
-rw-r--r--compiler/rustc_resolve/src/macros.rs30
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-4.stderr8
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-5.rs10
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-5.stderr30
-rw-r--r--tests/ui/proc-macro/macro-namespace-reserved-2.stderr16
-rw-r--r--tests/ui/tool-attributes/tool-attributes-misplaced-2.stderr8
8 files changed, 133 insertions, 6 deletions
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<RemoveSurroundingDerive>,
+    #[subdiagnostic]
+    pub(crate) add_as_non_derive: Option<AddAsNonDerive<'a>>,
+}
+
+#[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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         };
         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