From b49fbc9432bdad5f1db59391600b56a6d5fbede9 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sat, 14 Nov 2020 14:47:14 +0300
Subject: [PATCH 1/8] expand: Tell built-in macros whether we are currently in
 forced expansion mode

---
 .../src/cfg_accessible.rs                     | 11 ++--
 compiler/rustc_expand/src/base.rs             |  7 ++-
 compiler/rustc_expand/src/expand.rs           | 54 ++++++++++---------
 .../cfg_accessible-stuck.rs                   |  2 +-
 .../cfg_accessible-stuck.stderr               |  8 +--
 5 files changed, 42 insertions(+), 40 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 75f4b077640d4..09ed1af345675 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -1,7 +1,7 @@
 //! Implementation of the `#[cfg_accessible(path)]` attribute macro.
 
 use rustc_ast as ast;
-use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
 use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_span::symbol::sym;
@@ -31,7 +31,7 @@ impl MultiItemModifier for Expander {
     fn expand(
         &self,
         ecx: &mut ExtCtxt<'_>,
-        _span: Span,
+        span: Span,
         meta_item: &ast::MetaItem,
         item: Annotatable,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
@@ -49,11 +49,14 @@ impl MultiItemModifier for Expander {
             None => return ExpandResult::Ready(Vec::new()),
         };
 
-        let failure_msg = "cannot determine whether the path is accessible or not";
         match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
             Ok(true) => ExpandResult::Ready(vec![item]),
             Ok(false) => ExpandResult::Ready(Vec::new()),
-            Err(_) => ExpandResult::Retry(item, failure_msg.into()),
+            Err(Indeterminate) if ecx.force_mode => {
+                ecx.span_err(span, "cannot determine whether the path is accessible or not");
+                ExpandResult::Ready(vec![item])
+            }
+            Err(Indeterminate) => ExpandResult::Retry(item),
         }
     }
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index b435def87ac84..91617f2df9cb7 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -251,8 +251,7 @@ pub enum ExpandResult<T, U> {
     /// Expansion produced a result (possibly dummy).
     Ready(T),
     /// Expansion could not produce a result and needs to be retried.
-    /// The string is an explanation that will be printed if we are stuck in an infinite retry loop.
-    Retry(U, String),
+    Retry(U),
 }
 
 // `meta_item` is the attribute, and `item` is the item being modified.
@@ -919,6 +918,9 @@ pub struct ExtCtxt<'a> {
     pub root_path: PathBuf,
     pub resolver: &'a mut dyn ResolverExpand,
     pub current_expansion: ExpansionData,
+    /// Error recovery mode entered when expansion is stuck
+    /// (or during eager expansion, but that's a hack).
+    pub force_mode: bool,
     pub expansions: FxHashMap<Span, Vec<String>>,
     /// Called directly after having parsed an external `mod foo;` in expansion.
     pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
@@ -945,6 +947,7 @@ impl<'a> ExtCtxt<'a> {
                 directory_ownership: DirectoryOwnership::Owned { relative: None },
                 prior_type_ascription: None,
             },
+            force_mode: false,
             expansions: FxHashMap::default(),
         }
     }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 1b31bd6a30510..a0ecc41661799 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -404,6 +404,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     // Recursively expand all macro invocations in this AST fragment.
     pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
         let orig_expansion_data = self.cx.current_expansion.clone();
+        let orig_force_mode = self.cx.force_mode;
         self.cx.current_expansion.depth = 0;
 
         // Collect all macro invocations and replace them with placeholders.
@@ -432,6 +433,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 invocations = mem::take(&mut undetermined_invocations);
                 force = !mem::replace(&mut progress, false);
+                if force && self.monotonic {
+                    self.cx.sess.delay_span_bug(
+                        invocations.last().unwrap().0.span(),
+                        "expansion entered force mode without producing any errors",
+                    );
+                }
                 continue;
             };
 
@@ -460,18 +467,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
             let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
+            self.cx.force_mode = force;
 
             // FIXME(jseyfried): Refactor out the following logic
             let (expanded_fragment, new_invocations) = match res {
                 InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
                     ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
-                    ExpandResult::Retry(invoc, explanation) => {
+                    ExpandResult::Retry(invoc) => {
                         if force {
-                            // We are stuck, stop retrying and produce a dummy fragment.
-                            let span = invoc.span();
-                            self.cx.span_err(span, &explanation);
-                            let fragment = invoc.fragment_kind.dummy(span);
-                            self.collect_invocations(fragment, &[])
+                            self.cx.span_bug(
+                                invoc.span(),
+                                "expansion entered force mode but is still stuck",
+                            );
                         } else {
                             // Cannot expand, will retry this invocation later.
                             undetermined_invocations
@@ -526,6 +533,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
 
         self.cx.current_expansion = orig_expansion_data;
+        self.cx.force_mode = orig_force_mode;
 
         // Finally incorporate all the expanded macros into the input AST fragment.
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
@@ -735,20 +743,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         Ok(meta) => {
                             let items = match expander.expand(self.cx, span, &meta, item) {
                                 ExpandResult::Ready(items) => items,
-                                ExpandResult::Retry(item, explanation) => {
+                                ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
-                                    return ExpandResult::Retry(
-                                        Invocation {
-                                            kind: InvocationKind::Attr {
-                                                attr,
-                                                item,
-                                                derives,
-                                                after_derive,
-                                            },
-                                            ..invoc
+                                    return ExpandResult::Retry(Invocation {
+                                        kind: InvocationKind::Attr {
+                                            attr,
+                                            item,
+                                            derives,
+                                            after_derive,
                                         },
-                                        explanation,
-                                    );
+                                        ..invoc
+                                    });
                                 }
                             };
                             fragment_kind.expect_from_annotatables(items)
@@ -781,15 +786,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
                     let items = match expander.expand(self.cx, span, &meta, item) {
                         ExpandResult::Ready(items) => items,
-                        ExpandResult::Retry(item, explanation) => {
+                        ExpandResult::Retry(item) => {
                             // Reassemble the original invocation for retrying.
-                            return ExpandResult::Retry(
-                                Invocation {
-                                    kind: InvocationKind::Derive { path: meta.path, item },
-                                    ..invoc
-                                },
-                                explanation,
-                            );
+                            return ExpandResult::Retry(Invocation {
+                                kind: InvocationKind::Derive { path: meta.path, item },
+                                ..invoc
+                            });
                         }
                     };
                     fragment_kind.expect_from_annotatables(items)
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
index 8bc93fa324378..50504a44c9518 100644
--- a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
+++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs
@@ -1,6 +1,6 @@
 #![feature(cfg_accessible)]
 
-#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not
+#[cfg_accessible(Z)] // OK, recovered after the other `cfg_accessible` produces an error.
 struct S;
 
 #[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not
diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
index 9641441a819b0..33af7d62548ec 100644
--- a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
+++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr
@@ -4,11 +4,5 @@ error: cannot determine whether the path is accessible or not
 LL | #[cfg_accessible(S)]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: cannot determine whether the path is accessible or not
-  --> $DIR/cfg_accessible-stuck.rs:3:1
-   |
-LL | #[cfg_accessible(Z)]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 

From e7ee4d66ce2f2727f9b27e14d3e1ff917eff3d6e Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:43:23 +0300
Subject: [PATCH 2/8] expand: Move `fully_configure` to `config.rs`

---
 compiler/rustc_expand/src/config.rs | 45 +++++++++++++++++++++++++++++
 compiler/rustc_expand/src/expand.rs | 42 ---------------------------
 2 files changed, 45 insertions(+), 42 deletions(-)

diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index cccbdf778edcc..563783c5b795d 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -1,5 +1,7 @@
 //! Conditional compilation stripping.
 
+use crate::base::Annotatable;
+
 use rustc_ast::attr::HasAttrs;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
@@ -496,6 +498,49 @@ impl<'a> StripUnconfigured<'a> {
     pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) {
         fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg));
     }
+
+    pub fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
+        // Since the item itself has already been configured by the InvocationCollector,
+        // we know that fold result vector will contain exactly one element
+        match item {
+            Annotatable::Item(item) => Annotatable::Item(self.flat_map_item(item).pop().unwrap()),
+            Annotatable::TraitItem(item) => {
+                Annotatable::TraitItem(self.flat_map_trait_item(item).pop().unwrap())
+            }
+            Annotatable::ImplItem(item) => {
+                Annotatable::ImplItem(self.flat_map_impl_item(item).pop().unwrap())
+            }
+            Annotatable::ForeignItem(item) => {
+                Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
+            }
+            Annotatable::Stmt(stmt) => {
+                Annotatable::Stmt(stmt.map(|stmt| self.flat_map_stmt(stmt).pop().unwrap()))
+            }
+            Annotatable::Expr(mut expr) => Annotatable::Expr({
+                self.visit_expr(&mut expr);
+                expr
+            }),
+            Annotatable::Arm(arm) => Annotatable::Arm(self.flat_map_arm(arm).pop().unwrap()),
+            Annotatable::Field(field) => {
+                Annotatable::Field(self.flat_map_field(field).pop().unwrap())
+            }
+            Annotatable::FieldPat(fp) => {
+                Annotatable::FieldPat(self.flat_map_field_pattern(fp).pop().unwrap())
+            }
+            Annotatable::GenericParam(param) => {
+                Annotatable::GenericParam(self.flat_map_generic_param(param).pop().unwrap())
+            }
+            Annotatable::Param(param) => {
+                Annotatable::Param(self.flat_map_param(param).pop().unwrap())
+            }
+            Annotatable::StructField(sf) => {
+                Annotatable::StructField(self.flat_map_struct_field(sf).pop().unwrap())
+            }
+            Annotatable::Variant(v) => {
+                Annotatable::Variant(self.flat_map_variant(v).pop().unwrap())
+            }
+        }
+    }
 }
 
 impl<'a> MutVisitor for StripUnconfigured<'a> {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index a0ecc41661799..c4dcdd28817b3 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -609,48 +609,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         (fragment, invocations)
     }
 
-    fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
-        let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features };
-        // Since the item itself has already been configured by the InvocationCollector,
-        // we know that fold result vector will contain exactly one element
-        match item {
-            Annotatable::Item(item) => Annotatable::Item(cfg.flat_map_item(item).pop().unwrap()),
-            Annotatable::TraitItem(item) => {
-                Annotatable::TraitItem(cfg.flat_map_trait_item(item).pop().unwrap())
-            }
-            Annotatable::ImplItem(item) => {
-                Annotatable::ImplItem(cfg.flat_map_impl_item(item).pop().unwrap())
-            }
-            Annotatable::ForeignItem(item) => {
-                Annotatable::ForeignItem(cfg.flat_map_foreign_item(item).pop().unwrap())
-            }
-            Annotatable::Stmt(stmt) => {
-                Annotatable::Stmt(stmt.map(|stmt| cfg.flat_map_stmt(stmt).pop().unwrap()))
-            }
-            Annotatable::Expr(mut expr) => Annotatable::Expr({
-                cfg.visit_expr(&mut expr);
-                expr
-            }),
-            Annotatable::Arm(arm) => Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap()),
-            Annotatable::Field(field) => {
-                Annotatable::Field(cfg.flat_map_field(field).pop().unwrap())
-            }
-            Annotatable::FieldPat(fp) => {
-                Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap())
-            }
-            Annotatable::GenericParam(param) => {
-                Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap())
-            }
-            Annotatable::Param(param) => {
-                Annotatable::Param(cfg.flat_map_param(param).pop().unwrap())
-            }
-            Annotatable::StructField(sf) => {
-                Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap())
-            }
-            Annotatable::Variant(v) => Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap()),
-        }
-    }
-
     fn error_recursion_limit_reached(&mut self) {
         let expn_data = self.cx.current_expansion.id.expn_data();
         let suggested_limit = self.cx.ecfg.recursion_limit * 2;

From 69894ce9ac337e51730519e071c94a4bb9c926f2 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:45:10 +0300
Subject: [PATCH 3/8] resolve: Introduce a separate `NonMacroAttrKind` for
 legacy derive helpers

---
 compiler/rustc_hir/src/def.rs             | 11 +++++++--
 compiler/rustc_resolve/src/diagnostics.rs |  2 +-
 compiler/rustc_resolve/src/macros.rs      | 28 +++++++++--------------
 3 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 298cfcc254c86..4ede9d67b741f 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -39,6 +39,9 @@ pub enum NonMacroAttrKind {
     Tool,
     /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
     DeriveHelper,
+    /// Single-segment custom attribute registered by a derive macro
+    /// but used before that derive macro was expanded (deprecated).
+    DeriveHelperCompat,
     /// Single-segment custom attribute registered with `#[register_attr]`.
     Registered,
 }
@@ -370,7 +373,9 @@ impl NonMacroAttrKind {
         match self {
             NonMacroAttrKind::Builtin => "built-in attribute",
             NonMacroAttrKind::Tool => "tool attribute",
-            NonMacroAttrKind::DeriveHelper => "derive helper attribute",
+            NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => {
+                "derive helper attribute"
+            }
             NonMacroAttrKind::Registered => "explicitly registered attribute",
         }
     }
@@ -385,7 +390,9 @@ impl NonMacroAttrKind {
     /// Users of some attributes cannot mark them as used, so they are considered always used.
     pub fn is_used(self) -> bool {
         match self {
-            NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper => true,
+            NonMacroAttrKind::Tool
+            | NonMacroAttrKind::DeriveHelper
+            | NonMacroAttrKind::DeriveHelperCompat => true,
             NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
         }
     }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index acd88af1806ca..2cca1a6ee5979 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -609,7 +609,7 @@ impl<'a> Resolver<'a> {
                     }
                 }
                 Scope::DeriveHelpersCompat => {
-                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
                     if filter_fn(res) {
                         for derive in parent_scope.derives {
                             let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 21e43be20456b..7b46b5fda042c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -568,10 +568,9 @@ impl<'a> Resolver<'a> {
             struct Flags: u8 {
                 const MACRO_RULES          = 1 << 0;
                 const MODULE               = 1 << 1;
-                const DERIVE_HELPER_COMPAT = 1 << 2;
-                const MISC_SUGGEST_CRATE   = 1 << 3;
-                const MISC_SUGGEST_SELF    = 1 << 4;
-                const MISC_FROM_PRELUDE    = 1 << 5;
+                const MISC_SUGGEST_CRATE   = 1 << 2;
+                const MISC_SUGGEST_SELF    = 1 << 3;
+                const MISC_FROM_PRELUDE    = 1 << 4;
             }
         }
 
@@ -646,14 +645,11 @@ impl<'a> Resolver<'a> {
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
-                                        let binding = (
-                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                            ty::Visibility::Public,
+                                        result = ok(
+                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
                                             derive.span,
-                                            ExpnId::root(),
-                                        )
-                                            .to_name_binding(this.arenas);
-                                        result = Ok((binding, Flags::DERIVE_HELPER_COMPAT));
+                                            this.arenas,
+                                        );
                                         break;
                                     }
                                 }
@@ -799,17 +795,15 @@ impl<'a> Resolver<'a> {
                             let (res, innermost_res) = (binding.res(), innermost_binding.res());
                             if res != innermost_res {
                                 let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
-                                let is_derive_helper_compat = |res, flags: Flags| {
-                                    res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper)
-                                        && flags.contains(Flags::DERIVE_HELPER_COMPAT)
-                                };
+                                let derive_helper_compat =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
 
                                 let ambiguity_error_kind = if is_import {
                                     Some(AmbiguityKind::Import)
                                 } else if innermost_res == builtin || res == builtin {
                                     Some(AmbiguityKind::BuiltinAttr)
-                                } else if is_derive_helper_compat(innermost_res, innermost_flags)
-                                    || is_derive_helper_compat(res, flags)
+                                } else if innermost_res == derive_helper_compat
+                                    || res == derive_helper_compat
                                 {
                                     Some(AmbiguityKind::DeriveHelper)
                                 } else if innermost_flags.contains(Flags::MACRO_RULES)

From 68f94e94ed3d80d768d0d107049f02fb99716dbe Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:49:20 +0300
Subject: [PATCH 4/8] resolve: Centralize some error reporting for unexpected
 macro resolutions

---
 compiler/rustc_expand/src/expand.rs           |  41 +++--
 compiler/rustc_resolve/src/macros.rs          |  98 ++++++----
 src/test/ui/attrs-resolution-errors.rs        |  10 +-
 src/test/ui/attrs-resolution-errors.stderr    |  30 +--
 src/test/ui/proc-macro/proc-macro-gates.rs    |   4 +-
 .../ui/proc-macro/proc-macro-gates.stderr     |  12 +-
 src/test/ui/proc-macro/proc-macro-gates2.rs   |   4 +-
 .../ui/proc-macro/proc-macro-gates2.stderr    |  12 +-
 .../param-attrs-builtin-attrs.rs              |  20 +-
 .../param-attrs-builtin-attrs.stderr          |  60 +++---
 .../proc-macro-cannot-be-used.rs              |  58 +++---
 .../proc-macro-cannot-be-used.stderr          | 174 +++++++++---------
 src/test/ui/span/issue-36530.rs               |   2 +-
 src/test/ui/span/issue-36530.stderr           |   6 +-
 14 files changed, 278 insertions(+), 253 deletions(-)

diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c4dcdd28817b3..d4a83b8099058 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -209,6 +209,28 @@ impl AstFragmentKind {
         self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
     }
 
+    /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
+    pub fn supports_macro_expansion(self) -> bool {
+        match self {
+            AstFragmentKind::OptExpr
+            | AstFragmentKind::Expr
+            | AstFragmentKind::Pat
+            | AstFragmentKind::Ty
+            | AstFragmentKind::Stmts
+            | AstFragmentKind::Items
+            | AstFragmentKind::TraitItems
+            | AstFragmentKind::ImplItems
+            | AstFragmentKind::ForeignItems => true,
+            AstFragmentKind::Arms
+            | AstFragmentKind::Fields
+            | AstFragmentKind::FieldPats
+            | AstFragmentKind::GenericParams
+            | AstFragmentKind::Params
+            | AstFragmentKind::StructFields
+            | AstFragmentKind::Variants => false,
+        }
+    }
+
     fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
         self,
         items: I,
@@ -1014,7 +1036,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         attrs: &mut Vec<ast::Attribute>,
         after_derive: &mut bool,
     ) -> Option<ast::Attribute> {
-        let attr = attrs
+        attrs
             .iter()
             .position(|a| {
                 if a.has_name(sym::derive) {
@@ -1022,22 +1044,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 }
                 !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
             })
-            .map(|i| attrs.remove(i));
-        if let Some(attr) = &attr {
-            if !self.cx.ecfg.custom_inner_attributes()
-                && attr.style == ast::AttrStyle::Inner
-                && !attr.has_name(sym::test)
-            {
-                feature_err(
-                    &self.cx.sess.parse_sess,
-                    sym::custom_inner_attributes,
-                    attr.span,
-                    "non-builtin inner attributes are unstable",
-                )
-                .emit();
-            }
-        }
-        attr
+            .map(|i| attrs.remove(i))
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 7b46b5fda042c..b1ea2d73786ae 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,24 +12,24 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
 use rustc_expand::compile_declarative_macro;
-use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
+use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id;
 use rustc_middle::middle::stability;
 use rustc_middle::ty;
 use rustc_session::lint::builtin::UNUSED_MACROS;
+use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind};
+use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-
-use rustc_data_structures::sync::Lrc;
-use rustc_span::hygiene::{AstPass, MacroKind};
 use std::cell::Cell;
 use std::{mem, ptr};
 
@@ -241,15 +241,20 @@ impl<'a> ResolverExpand for Resolver<'a> {
             }
         };
 
-        let (path, kind, derives, after_derive) = match invoc.kind {
+        let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
             InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
                 &attr.get_normal_item().path,
                 MacroKind::Attr,
+                attr.style == ast::AttrStyle::Inner,
                 self.arenas.alloc_ast_paths(derives),
                 after_derive,
             ),
-            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false),
-            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false),
+            InvocationKind::Bang { ref mac, .. } => {
+                (&mac.path, MacroKind::Bang, false, &[][..], false)
+            }
+            InvocationKind::Derive { ref path, .. } => {
+                (path, MacroKind::Derive, false, &[][..], false)
+            }
             InvocationKind::DeriveContainer { ref derives, .. } => {
                 // Block expansion of the container until we resolve all derives in it.
                 // This is required for two reasons:
@@ -299,8 +304,17 @@ impl<'a> ResolverExpand for Resolver<'a> {
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
         let parent_scope = &ParentScope { derives, ..parent_scope };
+        let require_inert = !invoc.fragment_kind.supports_macro_expansion();
         let node_id = self.lint_node_id(eager_expansion_root);
-        let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?;
+        let (ext, res) = self.smart_resolve_macro_path(
+            path,
+            kind,
+            require_inert,
+            inner_attr,
+            parent_scope,
+            node_id,
+            force,
+        )?;
 
         let span = invoc.span();
         invoc_id.set_expn_data(ext.expn_data(
@@ -318,29 +332,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
         }
 
-        match invoc.fragment_kind {
-            AstFragmentKind::Arms
-            | AstFragmentKind::Fields
-            | AstFragmentKind::FieldPats
-            | AstFragmentKind::GenericParams
-            | AstFragmentKind::Params
-            | AstFragmentKind::StructFields
-            | AstFragmentKind::Variants => {
-                if let Res::Def(..) = res {
-                    self.session.span_err(
-                        span,
-                        &format!(
-                            "expected an inert attribute, found {} {}",
-                            res.article(),
-                            res.descr()
-                        ),
-                    );
-                    return Ok(InvocationRes::Single(self.dummy_ext(kind)));
-                }
-            }
-            _ => {}
-        }
-
         Ok(InvocationRes::Single(ext))
     }
 
@@ -403,10 +394,14 @@ impl<'a> ResolverExpand for Resolver<'a> {
 
 impl<'a> Resolver<'a> {
     /// Resolve macro path with error reporting and recovery.
+    /// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions
+    /// for better error recovery.
     fn smart_resolve_macro_path(
         &mut self,
         path: &ast::Path,
         kind: MacroKind,
+        require_inert: bool,
+        inner_attr: bool,
         parent_scope: &ParentScope<'a>,
         node_id: NodeId,
         force: bool,
@@ -414,7 +409,6 @@ impl<'a> Resolver<'a> {
         let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
         {
             Ok((Some(ext), res)) => (ext, res),
-            // Use dummy syntax extensions for unresolved macros for better recovery.
             Ok((None, res)) => (self.dummy_ext(kind), res),
             Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
             Err(Determinacy::Undetermined) => return Err(Indeterminate),
@@ -451,19 +445,43 @@ impl<'a> Resolver<'a> {
 
         self.check_stability_and_deprecation(&ext, path, node_id);
 
-        Ok(if ext.macro_kind() != kind {
-            let expected = kind.descr_expected();
+        let unexpected_res = if ext.macro_kind() != kind {
+            Some((kind.article(), kind.descr_expected()))
+        } else if require_inert && matches!(res, Res::Def(..)) {
+            Some(("a", "non-macro attribute"))
+        } else {
+            None
+        };
+        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.session
                 .struct_span_err(path.span, &msg)
-                .span_label(path.span, format!("not {} {}", kind.article(), expected))
+                .span_label(path.span, format!("not {} {}", article, expected))
                 .emit();
-            // Use dummy syntax extensions for unexpected macro kinds for better recovery.
-            (self.dummy_ext(kind), Res::Err)
-        } else {
-            (ext, res)
-        })
+            return Ok((self.dummy_ext(kind), Res::Err));
+        }
+
+        // We are trying to avoid reporting this error if other related errors were reported.
+        if inner_attr
+            && !self.session.features_untracked().custom_inner_attributes
+            && path != &sym::test
+            && res != Res::Err
+        {
+            feature_err(
+                &self.session.parse_sess,
+                sym::custom_inner_attributes,
+                path.span,
+                match res {
+                    Res::Def(..) => "inner macro attributes are unstable",
+                    Res::NonMacroAttr(..) => "custom inner attributes are unstable",
+                    _ => unreachable!(),
+                },
+            )
+            .emit();
+        }
+
+        Ok((ext, res))
     }
 
     pub fn resolve_macro_path(
diff --git a/src/test/ui/attrs-resolution-errors.rs b/src/test/ui/attrs-resolution-errors.rs
index a38b3cfa6665e..8770fb1ded8eb 100644
--- a/src/test/ui/attrs-resolution-errors.rs
+++ b/src/test/ui/attrs-resolution-errors.rs
@@ -1,12 +1,12 @@
 enum FooEnum {
     #[test]
-    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
     Bar(i32),
 }
 
 struct FooStruct {
     #[test]
-    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
     bar: i32,
 }
 
@@ -21,20 +21,20 @@ fn main() {
     match foo_struct {
         FooStruct {
             #[test] bar
-            //~^ ERROR expected an inert attribute, found an attribute macro
+            //~^ ERROR expected non-macro attribute, found attribute macro
         } => {}
     }
 
     match 1 {
         0 => {}
         #[test]
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         _ => {}
     }
 
     let _another_foo_strunct = FooStruct {
         #[test]
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         bar: 1,
     };
 }
diff --git a/src/test/ui/attrs-resolution-errors.stderr b/src/test/ui/attrs-resolution-errors.stderr
index 31f2a74edb333..883f96e5c1931 100644
--- a/src/test/ui/attrs-resolution-errors.stderr
+++ b/src/test/ui/attrs-resolution-errors.stderr
@@ -1,32 +1,32 @@
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/attrs-resolution-errors.rs:2:5
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/attrs-resolution-errors.rs:2:7
    |
 LL |     #[test]
-   |     ^^^^^^^
+   |       ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/attrs-resolution-errors.rs:8:5
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/attrs-resolution-errors.rs:8:7
    |
 LL |     #[test]
-   |     ^^^^^^^
+   |       ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/attrs-resolution-errors.rs:23:13
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/attrs-resolution-errors.rs:23:15
    |
 LL |             #[test] bar
-   |             ^^^^^^^
+   |               ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/attrs-resolution-errors.rs:30:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/attrs-resolution-errors.rs:30:11
    |
 LL |         #[test]
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/attrs-resolution-errors.rs:36:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/attrs-resolution-errors.rs:36:11
    |
 LL |         #[test]
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs
index b3b677fa7ffed..4c72ecbfc03a8 100644
--- a/src/test/ui/proc-macro/proc-macro-gates.rs
+++ b/src/test/ui/proc-macro/proc-macro-gates.rs
@@ -7,11 +7,11 @@
 extern crate test_macros;
 
 fn _test_inner() {
-    #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable
+    #![empty_attr] //~ ERROR: inner macro attributes are unstable
 }
 
 mod _test2_inner {
-    #![empty_attr] //~ ERROR: non-builtin inner attributes are unstable
+    #![empty_attr] //~ ERROR: inner macro attributes are unstable
 }
 
 #[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported
diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr
index c034349553177..33a808037eea5 100644
--- a/src/test/ui/proc-macro/proc-macro-gates.stderr
+++ b/src/test/ui/proc-macro/proc-macro-gates.stderr
@@ -1,17 +1,17 @@
-error[E0658]: non-builtin inner attributes are unstable
-  --> $DIR/proc-macro-gates.rs:10:5
+error[E0658]: inner macro attributes are unstable
+  --> $DIR/proc-macro-gates.rs:10:8
    |
 LL |     #![empty_attr]
-   |     ^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
    |
    = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
    = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
 
-error[E0658]: non-builtin inner attributes are unstable
-  --> $DIR/proc-macro-gates.rs:14:5
+error[E0658]: inner macro attributes are unstable
+  --> $DIR/proc-macro-gates.rs:14:8
    |
 LL |     #![empty_attr]
-   |     ^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
    |
    = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
    = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
diff --git a/src/test/ui/proc-macro/proc-macro-gates2.rs b/src/test/ui/proc-macro/proc-macro-gates2.rs
index 2fd5efd71f041..38fbd4733d5cb 100644
--- a/src/test/ui/proc-macro/proc-macro-gates2.rs
+++ b/src/test/ui/proc-macro/proc-macro-gates2.rs
@@ -10,11 +10,11 @@ extern crate test_macros;
 // should either require a feature gate or not be allowed on stable.
 
 fn _test6<#[empty_attr] T>() {}
-//~^ ERROR: expected an inert attribute, found an attribute macro
+//~^ ERROR: expected non-macro attribute, found attribute macro
 
 fn _test7() {
     match 1 {
-        #[empty_attr] //~ ERROR: expected an inert attribute, found an attribute macro
+        #[empty_attr] //~ ERROR: expected non-macro attribute, found attribute macro
         0 => {}
         _ => {}
     }
diff --git a/src/test/ui/proc-macro/proc-macro-gates2.stderr b/src/test/ui/proc-macro/proc-macro-gates2.stderr
index fd271da61553a..64df34e7ce390 100644
--- a/src/test/ui/proc-macro/proc-macro-gates2.stderr
+++ b/src/test/ui/proc-macro/proc-macro-gates2.stderr
@@ -1,14 +1,14 @@
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-gates2.rs:12:11
+error: expected non-macro attribute, found attribute macro `empty_attr`
+  --> $DIR/proc-macro-gates2.rs:12:13
    |
 LL | fn _test6<#[empty_attr] T>() {}
-   |           ^^^^^^^^^^^^^
+   |             ^^^^^^^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-gates2.rs:17:9
+error: expected non-macro attribute, found attribute macro `empty_attr`
+  --> $DIR/proc-macro-gates2.rs:17:11
    |
 LL |         #[empty_attr]
-   |         ^^^^^^^^^^^^^
+   |           ^^^^^^^^^^ not a non-macro attribute
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
index bf09171c9a12a..6403b3f55c40c 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
@@ -3,7 +3,7 @@ extern "C" {
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -19,7 +19,7 @@ type FnType = fn(
     /// Foo
     //~^ ERROR documentation comments cannot be applied to function
     #[test] a: u32,
-    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
@@ -34,7 +34,7 @@ pub fn foo(
     /// Foo
     //~^ ERROR documentation comments cannot be applied to function
     #[test] a: u32,
-    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
     /// Bar
     //~^ ERROR documentation comments cannot be applied to function
     #[must_use]
@@ -54,7 +54,7 @@ impl SelfStruct {
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -69,7 +69,7 @@ impl SelfStruct {
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -90,7 +90,7 @@ impl RefStruct {
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -109,7 +109,7 @@ trait RefTrait {
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -124,7 +124,7 @@ trait RefTrait {
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -144,7 +144,7 @@ impl RefTrait for RefStruct {
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: i32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Baz
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
@@ -161,7 +161,7 @@ fn main() {
         /// Foo
         //~^ ERROR documentation comments cannot be applied to function
         #[test] a: u32,
-        //~^ ERROR expected an inert attribute, found an attribute macro
+        //~^ ERROR expected non-macro attribute, found attribute macro
         /// Bar
         //~^ ERROR documentation comments cannot be applied to function
         #[must_use]
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
index 4d0349e8765f0..edca8cea68d72 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
@@ -1,62 +1,62 @@
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:5:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:5:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:21:5
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:21:7
    |
 LL |     #[test] a: u32,
-   |     ^^^^^^^
+   |       ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:36:5
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:36:7
    |
 LL |     #[test] a: u32,
-   |     ^^^^^^^
+   |       ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:56:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:56:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:71:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:71:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:92:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:92:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:111:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:111:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:126:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:126:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:146:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:146:11
    |
 LL |         #[test] a: i32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:163:9
+error: expected non-macro attribute, found attribute macro `test`
+  --> $DIR/param-attrs-builtin-attrs.rs:163:11
    |
 LL |         #[test] a: u32,
-   |         ^^^^^^^
+   |           ^^^^ not a non-macro attribute
 
 error: documentation comments cannot be applied to function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:3:9
diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
index be9085d5878cb..fcfa610ec8554 100644
--- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
+++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
@@ -8,58 +8,58 @@ use ident_mac::id;
 struct W(u8);
 
 extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
-//~^ ERROR expected an inert attribute, found an attribute macro
-//~| ERROR expected an inert attribute, found an attribute macro
+//~^ ERROR expected non-macro attribute, found attribute macro
+//~| ERROR expected non-macro attribute, found attribute macro
 
 unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
-//~^ ERROR expected an inert attribute, found an attribute macro
+//~^ ERROR expected non-macro attribute, found attribute macro
 
 type Alias = extern "C" fn(#[id] u8, #[id] ...);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
 
 fn free(#[id] arg1: u8) {
-    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
     let lam = |#[id] W(x), #[id] y: usize| ();
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
 }
 
 impl W {
     fn inherent1(#[id] self, #[id] arg1: u8) {}
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn inherent2(#[id] &self, #[id] arg1: u8) {}
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
 }
 
 trait A {
     fn trait1(#[id] self, #[id] arg1: u8);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn trait2(#[id] &self, #[id] arg1: u8);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
-    //~^ ERROR expected an inert attribute, found an attribute macro
-    //~| ERROR expected an inert attribute, found an attribute macro
+    //~^ ERROR expected non-macro attribute, found attribute macro
+    //~| ERROR expected non-macro attribute, found attribute macro
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
index 1cc3c3d82281b..38c5050f3428d 100644
--- a/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
+++ b/src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
@@ -1,176 +1,176 @@
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:10:21
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:10:23
    |
 LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
-   |                     ^^^^^
+   |                       ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:10:38
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:10:40
    |
 LL | extern "C" { fn ffi(#[id] arg1: i32, #[id] ...); }
-   |                                      ^^^^^
+   |                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:14:38
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:14:40
    |
 LL | unsafe extern "C" fn cvar(arg1: i32, #[id] mut args: ...) {}
-   |                                      ^^^^^
+   |                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:17:28
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:17:30
    |
 LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
-   |                            ^^^^^
+   |                              ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:17:38
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:17:40
    |
 LL | type Alias = extern "C" fn(#[id] u8, #[id] ...);
-   |                                      ^^^^^
+   |                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:21:9
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:21:11
    |
 LL | fn free(#[id] arg1: u8) {
-   |         ^^^^^
+   |           ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:23:16
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:23:18
    |
 LL |     let lam = |#[id] W(x), #[id] y: usize| ();
-   |                ^^^^^
+   |                  ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:23:28
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:23:30
    |
 LL |     let lam = |#[id] W(x), #[id] y: usize| ();
-   |                            ^^^^^
+   |                              ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:29:18
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:29:20
    |
 LL |     fn inherent1(#[id] self, #[id] arg1: u8) {}
-   |                  ^^^^^
+   |                    ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:29:30
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:29:32
    |
 LL |     fn inherent1(#[id] self, #[id] arg1: u8) {}
-   |                              ^^^^^
+   |                                ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:32:18
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:32:20
    |
 LL |     fn inherent2(#[id] &self, #[id] arg1: u8) {}
-   |                  ^^^^^
+   |                    ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:32:31
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:32:33
    |
 LL |     fn inherent2(#[id] &self, #[id] arg1: u8) {}
-   |                               ^^^^^
+   |                                 ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:35:22
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:35:24
    |
 LL |     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
-   |                      ^^^^^
+   |                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:35:42
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:35:44
    |
 LL |     fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
-   |                                          ^^^^^
+   |                                            ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:38:22
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:38:24
    |
 LL |     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
-   |                      ^^^^^
+   |                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:38:45
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:38:47
    |
 LL |     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
-   |                                             ^^^^^
+   |                                               ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:41:38
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:41:40
    |
 LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
-   |                                      ^^^^^
+   |                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:41:54
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:41:56
    |
 LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
-   |                                                      ^^^^^
+   |                                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:47:15
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:47:17
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
-   |               ^^^^^
+   |                 ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:47:27
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:47:29
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
-   |                           ^^^^^
+   |                             ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:50:15
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:50:17
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
-   |               ^^^^^
+   |                 ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:50:28
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:50:30
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
-   |                            ^^^^^
+   |                              ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:53:19
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:53:21
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
-   |                   ^^^^^
+   |                     ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:53:39
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:53:41
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
-   |                                       ^^^^^
+   |                                         ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:56:19
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:56:21
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
-   |                   ^^^^^
+   |                     ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:56:42
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:56:44
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
-   |                                          ^^^^^
+   |                                            ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:56:58
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:56:60
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
-   |                                                          ^^^^^
+   |                                                            ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:60:38
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:60:40
    |
 LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
-   |                                      ^^^^^
+   |                                        ^^ not a non-macro attribute
 
-error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:60:54
+error: expected non-macro attribute, found attribute macro `id`
+  --> $DIR/proc-macro-cannot-be-used.rs:60:56
    |
 LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
-   |                                                      ^^^^^
+   |                                                        ^^ not a non-macro attribute
 
 error: aborting due to 29 previous errors
 
diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs
index 4776740d8de90..70e04bf7ee6e8 100644
--- a/src/test/ui/span/issue-36530.rs
+++ b/src/test/ui/span/issue-36530.rs
@@ -6,7 +6,7 @@
 
 #[foo]
 mod foo {
-    #![foo] //~ ERROR non-builtin inner attributes are unstable
+    #![foo] //~ ERROR custom inner attributes are unstable
 }
 
 fn main() {}
diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr
index 79b12590fc538..a998d7217a13f 100644
--- a/src/test/ui/span/issue-36530.stderr
+++ b/src/test/ui/span/issue-36530.stderr
@@ -1,8 +1,8 @@
-error[E0658]: non-builtin inner attributes are unstable
-  --> $DIR/issue-36530.rs:9:5
+error[E0658]: custom inner attributes are unstable
+  --> $DIR/issue-36530.rs:9:8
    |
 LL |     #![foo]
-   |     ^^^^^^^
+   |        ^^^
    |
    = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
    = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable

From dfb690eaa93fabc6a61b24f2a8e4ad7f2c3689a7 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:50:16 +0300
Subject: [PATCH 5/8] resolve/expand: Misc cleanup

---
 compiler/rustc_expand/src/base.rs       |  4 +++-
 compiler/rustc_expand/src/expand.rs     |  3 ---
 compiler/rustc_parse/src/parser/attr.rs | 13 ++++++-------
 compiler/rustc_resolve/src/macros.rs    |  6 +-----
 4 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 91617f2df9cb7..1c76c31e1a7ff 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -888,8 +888,10 @@ pub trait ResolverExpand {
     /// Some parent node that is close enough to the given macro call.
     fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId;
 
+    // Resolver interfaces for specific built-in macros.
+    /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
     fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
-    fn add_derive_copy(&mut self, expn_id: ExpnId);
+    /// Path resolution logic for `#[cfg_accessible(path)]`.
     fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
 }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index d4a83b8099058..f4b66b354208a 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1797,7 +1797,4 @@ impl<'feat> ExpansionConfig<'feat> {
     fn proc_macro_hygiene(&self) -> bool {
         self.features.map_or(false, |features| features.proc_macro_hygiene)
     }
-    fn custom_inner_attributes(&self) -> bool {
-        self.features.map_or(false, |features| features.custom_inner_attributes)
-    }
 }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 3738fbaeac84f..41985757b57af 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -312,14 +312,13 @@ impl<'a> Parser<'a> {
 }
 
 pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
+    // One of the attributes may either itself be a macro, or apply derive macros (`derive`),
+    // or expand to macro attributes (`cfg_attr`).
     attrs.iter().any(|attr| {
-        if let Some(ident) = attr.ident() {
+        attr.ident().map_or(true, |ident| {
             ident.name == sym::derive
-            // This might apply a custom attribute/derive
-            || ident.name == sym::cfg_attr
-            || !rustc_feature::is_builtin_attr_name(ident.name)
-        } else {
-            true
-        }
+                || ident.name == sym::cfg_attr
+                || !rustc_feature::is_builtin_attr_name(ident.name)
+        })
     })
 }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b1ea2d73786ae..1ee96f81e4fab 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -286,7 +286,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
                                     ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
                                 );
                                 if ext.is_derive_copy {
-                                    self.add_derive_copy(invoc_id);
+                                    self.containers_deriving_copy.insert(invoc_id);
                                 }
                                 ext
                             }
@@ -351,10 +351,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
         self.containers_deriving_copy.contains(&expn_id)
     }
 
-    fn add_derive_copy(&mut self, expn_id: ExpnId) {
-        self.containers_deriving_copy.insert(expn_id);
-    }
-
     // The function that implements the resolution logic of `#[cfg_accessible(path)]`.
     // Returns true if the path can certainly be resolved in one of three namespaces,
     // returns false if the path certainly cannot be resolved in any of the three namespaces.

From ec547202b4fa11cd351b29d076391d2913364fc6 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:51:52 +0300
Subject: [PATCH 6/8] expand: Cleanup attribute collection in invocation
 collector

---
 compiler/rustc_expand/src/expand.rs | 180 ++++++----------------------
 1 file changed, 39 insertions(+), 141 deletions(-)

diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f4b66b354208a..22334a63988dc 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1016,11 +1016,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn collect_attr(
         &mut self,
-        attr: Option<ast::Attribute>,
-        derives: Vec<Path>,
+        (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
         item: Annotatable,
         kind: AstFragmentKind,
-        after_derive: bool,
     ) -> AstFragment {
         self.collect(
             kind,
@@ -1048,10 +1046,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn classify_item(
+    fn take_first_attr(
         &mut self,
         item: &mut impl HasAttrs,
-    ) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool) {
+    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
         let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
 
         item.visit_attrs(|mut attrs| {
@@ -1059,23 +1057,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             traits = collect_derives(&mut self.cx, &mut attrs);
         });
 
-        (attr, traits, after_derive)
+        if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
     }
 
-    /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
+    /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
     /// to the unused-attributes lint (making it an error on statements and expressions
     /// is a breaking change)
-    fn classify_nonitem(
+    fn take_first_attr_no_derive(
         &mut self,
         nonitem: &mut impl HasAttrs,
-    ) -> (Option<ast::Attribute>, /* after_derive */ bool) {
+    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
         let (mut attr, mut after_derive) = (None, false);
 
         nonitem.visit_attrs(|mut attrs| {
             attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
         });
 
-        (attr, after_derive)
+        attr.map(|attr| (Some(attr), Vec::new(), after_derive))
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1119,23 +1117,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         visit_clobber(expr.deref_mut(), |mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            // ignore derives so they remain unused
-            let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
-            if let Some(ref attr_value) = attr {
+            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
                 // Collect the invoc regardless of whether or not attributes are permitted here
                 // expansion will eat the attribute so it won't error later.
-                self.cfg.maybe_emit_expr_attr_err(attr_value);
+                attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
-                    .collect_attr(
-                        attr,
-                        vec![],
-                        Annotatable::Expr(P(expr)),
-                        AstFragmentKind::Expr,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
                     .make_expr()
                     .into_inner();
             }
@@ -1153,16 +1142,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
         let mut arm = configure!(self, arm);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut arm);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut arm) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Arm(arm),
-                    AstFragmentKind::Arms,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
                 .make_arms();
         }
 
@@ -1172,16 +1154,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
         let mut field = configure!(self, field);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut field);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut field) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Field(field),
-                    AstFragmentKind::Fields,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Field(field), AstFragmentKind::Fields)
                 .make_fields();
         }
 
@@ -1191,16 +1166,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
         let mut fp = configure!(self, fp);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut fp);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut fp) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::FieldPat(fp),
-                    AstFragmentKind::FieldPats,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::FieldPat(fp), AstFragmentKind::FieldPats)
                 .make_field_patterns();
         }
 
@@ -1210,16 +1178,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
         let mut p = configure!(self, p);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut p);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut p) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Param(p),
-                    AstFragmentKind::Params,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
                 .make_params();
         }
 
@@ -1229,16 +1190,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
         let mut sf = configure!(self, sf);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut sf);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut sf) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::StructField(sf),
-                    AstFragmentKind::StructFields,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::StructField(sf), AstFragmentKind::StructFields)
                 .make_struct_fields();
         }
 
@@ -1248,16 +1202,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
         let mut variant = configure!(self, variant);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut variant);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut variant) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Variant(variant),
-                    AstFragmentKind::Variants,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
                 .make_variants();
         }
 
@@ -1269,20 +1216,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         expr.filter_map(|mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            // Ignore derives so they remain unused.
-            let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
-            if let Some(ref attr_value) = attr {
-                self.cfg.maybe_emit_expr_attr_err(attr_value);
+            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
+                attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr));
 
                 return self
-                    .collect_attr(
-                        attr,
-                        vec![],
-                        Annotatable::Expr(P(expr)),
-                        AstFragmentKind::OptExpr,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
                     .make_opt_expr()
                     .map(|expr| expr.into_inner());
             }
@@ -1321,25 +1259,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let (attr, derives, after_derive) = if stmt.is_item() {
-                // FIXME: Handle custom attributes on statements (#15701)
-                (None, vec![], false)
-            } else {
-                // ignore derives on non-item statements so it falls through
-                // to the unused-attributes lint
-                let (attr, after_derive) = self.classify_nonitem(&mut stmt);
-                (attr, vec![], after_derive)
-            };
+            // FIXME: Handle custom attributes on statements (#15701).
+            let attr =
+                if stmt.is_item() { None } else { self.take_first_attr_no_derive(&mut stmt) };
 
-            if attr.is_some() || !derives.is_empty() {
+            if let Some(attr) = attr {
                 return self
-                    .collect_attr(
-                        attr,
-                        derives,
-                        Annotatable::Stmt(P(stmt)),
-                        AstFragmentKind::Stmts,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
                     .make_stmts();
             }
         }
@@ -1379,16 +1305,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Item(item),
-                    AstFragmentKind::Items,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
                 .make_items();
         }
 
@@ -1482,16 +1401,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::TraitItem(item),
-                    AstFragmentKind::TraitItems,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
                 .make_trait_items();
         }
 
@@ -1512,16 +1424,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::ImplItem(item),
-                    AstFragmentKind::ImplItems,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
                 .make_impl_items();
         }
 
@@ -1562,16 +1467,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         &mut self,
         mut foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
-        let (attr, traits, after_derive) = self.classify_item(&mut foreign_item);
-
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut foreign_item) {
             return self
                 .collect_attr(
                     attr,
-                    traits,
                     Annotatable::ForeignItem(foreign_item),
                     AstFragmentKind::ForeignItems,
-                    after_derive,
                 )
                 .make_foreign_items();
         }
@@ -1606,15 +1507,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     ) -> SmallVec<[ast::GenericParam; 1]> {
         let mut param = configure!(self, param);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut param);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut param) {
             return self
                 .collect_attr(
                     attr,
-                    traits,
                     Annotatable::GenericParam(param),
                     AstFragmentKind::GenericParams,
-                    after_derive,
                 )
                 .make_generic_params();
         }

From cd2177f3de22f54d7e71eea1e270f4e424394fc7 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:54:19 +0300
Subject: [PATCH 7/8] expand: Stop derive expansion un unexpected targets early

Collect derive placeholders using `collect` instead of `push`
---
 compiler/rustc_expand/src/expand.rs           | 60 +++++++++++--------
 src/test/ui/issues/issue-36617.rs             |  1 -
 src/test/ui/issues/issue-36617.stderr         | 10 +---
 src/test/ui/issues/issue-49934-errors.rs      |  2 -
 src/test/ui/issues/issue-49934-errors.stderr  | 16 +----
 .../issue-69341-malformed-derive-inert.rs     |  1 -
 .../issue-69341-malformed-derive-inert.stderr | 10 +---
 .../ui/span/issue-43927-non-ADT-derive.rs     |  3 -
 .../ui/span/issue-43927-non-ADT-derive.stderr | 26 +-------
 9 files changed, 41 insertions(+), 88 deletions(-)

diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 22334a63988dc..c2240aabd884b 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -492,6 +492,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             self.cx.force_mode = force;
 
             // FIXME(jseyfried): Refactor out the following logic
+            let fragment_kind = invoc.fragment_kind;
             let (expanded_fragment, new_invocations) = match res {
                 InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
                     ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
@@ -512,36 +513,45 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 InvocationRes::DeriveContainer(_exts) => {
                     // FIXME: Consider using the derive resolutions (`_exts`) immediately,
                     // instead of enqueuing the derives to be resolved again later.
-                    let (derives, item) = match invoc.kind {
+                    let (derives, mut item) = match invoc.kind {
                         InvocationKind::DeriveContainer { derives, item } => (derives, item),
                         _ => unreachable!(),
                     };
-                    if !item.derive_allowed() {
+                    let (item, derive_placeholders) = if !item.derive_allowed() {
                         self.error_derive_forbidden_on_non_adt(&derives, &item);
-                    }
+                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+                        (item, Vec::new())
+                    } else {
+                        let mut item = StripUnconfigured {
+                            sess: self.cx.sess,
+                            features: self.cx.ecfg.features,
+                        }
+                        .fully_configure(item);
+                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+
+                        invocations.reserve(derives.len());
+                        let derive_placeholders = derives
+                            .into_iter()
+                            .map(|path| {
+                                let expn_id = ExpnId::fresh(None);
+                                invocations.push((
+                                    Invocation {
+                                        kind: InvocationKind::Derive { path, item: item.clone() },
+                                        fragment_kind,
+                                        expansion_data: ExpansionData {
+                                            id: expn_id,
+                                            ..self.cx.current_expansion.clone()
+                                        },
+                                    },
+                                    None,
+                                ));
+                                NodeId::placeholder_from_expn_id(expn_id)
+                            })
+                            .collect::<Vec<_>>();
+                        (item, derive_placeholders)
+                    };
 
-                    let mut item = self.fully_configure(item);
-                    item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-
-                    let mut derive_placeholders = Vec::with_capacity(derives.len());
-                    invocations.reserve(derives.len());
-                    for path in derives {
-                        let expn_id = ExpnId::fresh(None);
-                        derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
-                        invocations.push((
-                            Invocation {
-                                kind: InvocationKind::Derive { path, item: item.clone() },
-                                fragment_kind: invoc.fragment_kind,
-                                expansion_data: ExpansionData {
-                                    id: expn_id,
-                                    ..invoc.expansion_data.clone()
-                                },
-                            },
-                            None,
-                        ));
-                    }
-                    let fragment =
-                        invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item));
+                    let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
                     self.collect_invocations(fragment, &derive_placeholders)
                 }
             };
diff --git a/src/test/ui/issues/issue-36617.rs b/src/test/ui/issues/issue-36617.rs
index 58f44f42524bc..1102f3c4640a1 100644
--- a/src/test/ui/issues/issue-36617.rs
+++ b/src/test/ui/issues/issue-36617.rs
@@ -1,5 +1,4 @@
 #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
                  //~| ERROR cannot determine resolution for the derive macro `Copy`
-                 //~| ERROR cannot determine resolution for the derive macro `Copy`
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr
index 586dcf2cea675..dc6ef16925913 100644
--- a/src/test/ui/issues/issue-36617.stderr
+++ b/src/test/ui/issues/issue-36617.stderr
@@ -12,14 +12,6 @@ LL | #![derive(Copy)]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: cannot determine resolution for the derive macro `Copy`
-  --> $DIR/issue-36617.rs:1:11
-   |
-LL | #![derive(Copy)]
-   |           ^^^^
-   |
-   = note: import resolution is stuck, try simplifying macro imports
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/issues/issue-49934-errors.rs b/src/test/ui/issues/issue-49934-errors.rs
index 6fa5f01ffd926..bf95f8fa7e1ec 100644
--- a/src/test/ui/issues/issue-49934-errors.rs
+++ b/src/test/ui/issues/issue-49934-errors.rs
@@ -1,10 +1,8 @@
 fn foo<#[derive(Debug)] T>() {
 //~^ ERROR `derive` may only be applied to structs, enums and unions
-//~| ERROR expected an inert attribute, found a derive macro
     match 0 {
         #[derive(Debug)]
         //~^ ERROR `derive` may only be applied to structs, enums and unions
-        //~| ERROR expected an inert attribute, found a derive macro
         _ => (),
     }
 }
diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr
index 3befb38a20882..71cd2d3034243 100644
--- a/src/test/ui/issues/issue-49934-errors.stderr
+++ b/src/test/ui/issues/issue-49934-errors.stderr
@@ -4,24 +4,12 @@ error[E0774]: `derive` may only be applied to structs, enums and unions
 LL | fn foo<#[derive(Debug)] T>() {
    |        ^^^^^^^^^^^^^^^^
 
-error: expected an inert attribute, found a derive macro
-  --> $DIR/issue-49934-errors.rs:1:17
-   |
-LL | fn foo<#[derive(Debug)] T>() {
-   |                 ^^^^^
-
 error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-49934-errors.rs:5:9
+  --> $DIR/issue-49934-errors.rs:4:9
    |
 LL |         #[derive(Debug)]
    |         ^^^^^^^^^^^^^^^^
 
-error: expected an inert attribute, found a derive macro
-  --> $DIR/issue-49934-errors.rs:5:18
-   |
-LL |         #[derive(Debug)]
-   |                  ^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
index 24692f7cf52e1..1fd7cddc7c937 100644
--- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
@@ -4,7 +4,6 @@ struct CLI {
     #[derive(parse())]
     //~^ ERROR traits in `#[derive(...)]` don't accept arguments
     //~| ERROR cannot find derive macro `parse` in this scope
-    //~| ERROR cannot find derive macro `parse` in this scope
     path: (),
     //~^ ERROR `derive` may only be applied to structs, enums and unions
 }
diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
index c4532a375a75e..db40ce0753045 100644
--- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
@@ -5,7 +5,7 @@ LL |     #[derive(parse())]
    |                   ^^ help: remove the arguments
 
 error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-69341-malformed-derive-inert.rs:8:5
+  --> $DIR/issue-69341-malformed-derive-inert.rs:7:5
    |
 LL |     path: (),
    |     ^^^^^^^^
@@ -16,12 +16,6 @@ error: cannot find derive macro `parse` in this scope
 LL |     #[derive(parse())]
    |              ^^^^^
 
-error: cannot find derive macro `parse` in this scope
-  --> $DIR/issue-69341-malformed-derive-inert.rs:4:14
-   |
-LL |     #[derive(parse())]
-   |              ^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.rs b/src/test/ui/span/issue-43927-non-ADT-derive.rs
index 89b8eba1e95e7..8f1599a5abcb0 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.rs
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.rs
@@ -5,9 +5,6 @@
 //~| ERROR cannot determine resolution for the derive macro `Debug`
 //~| ERROR cannot determine resolution for the derive macro `PartialEq`
 //~| ERROR cannot determine resolution for the derive macro `Eq`
-//~| ERROR cannot determine resolution for the derive macro `Debug`
-//~| ERROR cannot determine resolution for the derive macro `PartialEq`
-//~| ERROR cannot determine resolution for the derive macro `Eq`
 struct DerivedOn;
 
 fn main() {}
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
index b160a4e5877d5..85beac535c965 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
@@ -28,30 +28,6 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: cannot determine resolution for the derive macro `Eq`
-  --> $DIR/issue-43927-non-ADT-derive.rs:3:29
-   |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
-   |                             ^^
-   |
-   = note: import resolution is stuck, try simplifying macro imports
-
-error: cannot determine resolution for the derive macro `PartialEq`
-  --> $DIR/issue-43927-non-ADT-derive.rs:3:18
-   |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
-   |                  ^^^^^^^^^
-   |
-   = note: import resolution is stuck, try simplifying macro imports
-
-error: cannot determine resolution for the derive macro `Debug`
-  --> $DIR/issue-43927-non-ADT-derive.rs:3:11
-   |
-LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
-   |           ^^^^^
-   |
-   = note: import resolution is stuck, try simplifying macro imports
-
-error: aborting due to 7 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0774`.

From d575aa4d580676eac7c02092ca94e5cfa421b288 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Thu, 19 Nov 2020 01:55:59 +0300
Subject: [PATCH 8/8] expand: Mark some dead code in derive expansion as
 unreachable

---
 .../src/deriving/generic/mod.rs               | 15 ++-------
 .../rustc_builtin_macros/src/deriving/mod.rs  |  8 +----
 compiler/rustc_expand/src/expand.rs           |  3 --
 compiler/rustc_expand/src/proc_macro.rs       | 33 ++-----------------
 4 files changed, 5 insertions(+), 54 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 0642edff6b678..a767de53dae1f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -407,13 +407,7 @@ impl<'a> TraitDef<'a> {
                             _ => false,
                         })
                     }
-                    _ => {
-                        // Non-ADT derive is an error, but it should have been
-                        // set earlier; see
-                        // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
-                        // librustc_expand/base.rs:Annotatable::derive_allowed()
-                        return;
-                    }
+                    _ => unreachable!(),
                 };
                 let container_id = cx.current_expansion.id.expn_data().parent;
                 let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
@@ -475,12 +469,7 @@ impl<'a> TraitDef<'a> {
                 );
                 push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
             }
-            _ => {
-                // Non-Item derive is an error, but it should have been
-                // set earlier; see
-                // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
-                // librustc_expand/base.rs:Annotatable::derive_allowed()
-            }
+            _ => unreachable!(),
         }
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index bf95093492880..72d94af4694ab 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -98,13 +98,7 @@ fn inject_impl_of_structural_trait(
 ) {
     let item = match *item {
         Annotatable::Item(ref item) => item,
-        _ => {
-            // Non-Item derive is an error, but it should have been
-            // set earlier; see
-            // librustc_expand/expand.rs:MacroExpander::fully_expand_fragment()
-            // librustc_expand/base.rs:Annotatable::derive_allowed()
-            return;
-        }
+        _ => unreachable!(),
     };
 
     let generics = match item.kind {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c2240aabd884b..5be2fee8b38fa 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -767,9 +767,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             InvocationKind::Derive { path, item } => match ext {
                 SyntaxExtensionKind::Derive(expander)
                 | SyntaxExtensionKind::LegacyDerive(expander) => {
-                    if !item.derive_allowed() {
-                        return ExpandResult::Ready(fragment_kind.dummy(span));
-                    }
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 4c95f19b96dc6..dea167740edca 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -75,38 +75,9 @@ impl MultiItemModifier for ProcMacroDerive {
         item: Annotatable,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let item = match item {
-            Annotatable::Arm(..)
-            | Annotatable::Field(..)
-            | Annotatable::FieldPat(..)
-            | Annotatable::GenericParam(..)
-            | Annotatable::Param(..)
-            | Annotatable::StructField(..)
-            | Annotatable::Variant(..) => panic!("unexpected annotatable"),
-            Annotatable::Item(item) => item,
-            Annotatable::ImplItem(_)
-            | Annotatable::TraitItem(_)
-            | Annotatable::ForeignItem(_)
-            | Annotatable::Stmt(_)
-            | Annotatable::Expr(_) => {
-                ecx.span_err(
-                    span,
-                    "proc-macro derives may only be applied to a struct, enum, or union",
-                );
-                return ExpandResult::Ready(Vec::new());
-            }
+            Annotatable::Item(item) => token::NtItem(item),
+            _ => unreachable!(),
         };
-        match item.kind {
-            ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) => {}
-            _ => {
-                ecx.span_err(
-                    span,
-                    "proc-macro derives may only be applied to a struct, enum, or union",
-                );
-                return ExpandResult::Ready(Vec::new());
-            }
-        }
-
-        let item = token::NtItem(item);
         let input = if item.pretty_printing_compatibility_hack() {
             TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
         } else {