about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-11-14 14:47:14 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2021-02-07 20:08:45 +0300
commitdbdbd30bf2cb0d48c8bbce83c2458592664dbb18 (patch)
tree92877e16f45e3cf927ffc4296e0f90c48ec036f5
parentae00b62ceb7eaf1f02f5289ab233bf7e0e8060d5 (diff)
downloadrust-dbdbd30bf2cb0d48c8bbce83c2458592664dbb18.tar.gz
rust-dbdbd30bf2cb0d48c8bbce83c2458592664dbb18.zip
expand/resolve: Turn `#[derive]` into a regular macro attribute
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml1
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs132
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs44
-rw-r--r--compiler/rustc_expand/src/expand.rs339
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs94
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_lint/src/context.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs50
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_resolve/src/lib.rs3
-rw-r--r--compiler/rustc_resolve/src/macros.rs145
-rw-r--r--library/core/src/macros/mod.rs8
-rw-r--r--library/core/src/prelude/v1.rs5
-rw-r--r--library/std/src/prelude/v1.rs5
-rw-r--r--src/rustdoc-json-types/lib.rs30
-rw-r--r--src/test/run-make-fulldeps/simd-ffi/simd.rs5
-rw-r--r--src/test/ui/derives/derive-deadlock.rs6
-rw-r--r--src/test/ui/derives/derive-deadlock.stderr10
-rw-r--r--src/test/ui/derives/derive-multiple-with-packed.rs10
-rw-r--r--src/test/ui/derives/deriving-meta-empty-trait-list.rs4
-rw-r--r--src/test/ui/derives/deriving-meta-empty-trait-list.stderr15
-rw-r--r--src/test/ui/derives/issue-36617.rs3
-rw-r--r--src/test/ui/derives/issue-36617.stderr15
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-derive.rs1
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-derive.stderr22
-rw-r--r--src/test/ui/issues/issue-49934-errors.rs9
-rw-r--r--src/test/ui/issues/issue-49934-errors.stderr13
-rw-r--r--src/test/ui/issues/issue-49934.rs17
-rw-r--r--src/test/ui/issues/issue-49934.stderr31
-rw-r--r--src/test/ui/macros/builtin-std-paths-fail.stderr44
-rw-r--r--src/test/ui/malformed/issue-69341-malformed-derive-inert.rs5
-rw-r--r--src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr21
-rw-r--r--src/test/ui/malformed/malformed-derive-entry.stderr2
-rw-r--r--src/test/ui/malformed/malformed-special-attrs.stderr4
-rw-r--r--src/test/ui/proc-macro/attribute-after-derive.rs28
-rw-r--r--src/test/ui/proc-macro/attribute-after-derive.stdout148
-rw-r--r--src/test/ui/proc-macro/attribute-order-restricted.rs14
-rw-r--r--src/test/ui/proc-macro/attribute-order-restricted.stderr8
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.rs2
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.stderr27
-rw-r--r--src/test/ui/proc-macro/derive-helper-vs-legacy.rs12
-rw-r--r--src/test/ui/proc-macro/derive-multiple-with-packed.rs11
-rw-r--r--src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs4
-rw-r--r--src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr19
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.rs3
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stderr15
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stdout728
-rw-r--r--src/test/ui/proc-macro/proc-macro-attributes.rs8
-rw-r--r--src/test/ui/proc-macro/proc-macro-attributes.stderr67
-rw-r--r--src/test/ui/proc-macro/reserved-macro-names.rs6
-rw-r--r--src/test/ui/proc-macro/reserved-macro-names.stderr8
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.rs7
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.stderr31
-rw-r--r--src/test/ui/span/macro-ty-params.rs2
-rw-r--r--src/test/ui/span/macro-ty-params.stderr2
58 files changed, 1249 insertions, 1008 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9cabdb3edf6..6f29120455e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3582,6 +3582,7 @@ dependencies = [
  "rustc_errors",
  "rustc_expand",
  "rustc_feature",
+ "rustc_lexer",
  "rustc_parse",
  "rustc_parse_format",
  "rustc_session",
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index c397a854126..eb022b5b2b1 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -15,6 +15,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_lexer = { path = "../rustc_lexer" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
new file mode 100644
index 00000000000..fad64858ce3
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -0,0 +1,132 @@
+use rustc_ast::{self as ast, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_errors::{struct_span_err, Applicability};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
+use rustc_expand::config::StripUnconfigured;
+use rustc_feature::AttributeTemplate;
+use rustc_parse::validate_attr;
+use rustc_session::Session;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+crate struct Expander;
+
+impl MultiItemModifier for Expander {
+    fn expand(
+        &self,
+        ecx: &mut ExtCtxt<'_>,
+        span: Span,
+        meta_item: &ast::MetaItem,
+        item: Annotatable,
+    ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
+        let sess = ecx.sess;
+        if report_bad_target(sess, &item, span) {
+            // We don't want to pass inappropriate targets to derive macros to avoid
+            // follow up errors, all other errors below are recoverable.
+            return ExpandResult::Ready(vec![item]);
+        }
+
+        let template =
+            AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
+        let attr = ecx.attribute(meta_item.clone());
+        validate_attr::check_builtin_attribute(&sess.parse_sess, &attr, sym::derive, template);
+
+        let derives: Vec<_> = attr
+            .meta_item_list()
+            .unwrap_or_default()
+            .into_iter()
+            .filter_map(|nested_meta| match nested_meta {
+                NestedMetaItem::MetaItem(meta) => Some(meta),
+                NestedMetaItem::Literal(lit) => {
+                    // Reject `#[derive("Debug")]`.
+                    report_unexpected_literal(sess, &lit);
+                    None
+                }
+            })
+            .map(|meta| {
+                // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the paths.
+                report_path_args(sess, &meta);
+                meta.path
+            })
+            .collect();
+
+        // FIXME: Try to cache intermediate results to avoid collecting same paths multiple times.
+        match ecx.resolver.resolve_derives(ecx.current_expansion.id, derives, ecx.force_mode) {
+            Ok(()) => {
+                let mut visitor =
+                    StripUnconfigured { sess, features: ecx.ecfg.features, modified: false };
+                let mut item = visitor.fully_configure(item);
+                if visitor.modified {
+                    // Erase the tokens if cfg-stripping modified the item
+                    // This will cause us to synthesize fake tokens
+                    // when `nt_to_tokenstream` is called on this item.
+                    match &mut item {
+                        Annotatable::Item(item) => item,
+                        Annotatable::Stmt(stmt) => match &mut stmt.kind {
+                            StmtKind::Item(item) => item,
+                            _ => unreachable!(),
+                        },
+                        _ => unreachable!(),
+                    }
+                    .tokens = None;
+                }
+                ExpandResult::Ready(vec![item])
+            }
+            Err(Indeterminate) => ExpandResult::Retry(item),
+        }
+    }
+}
+
+fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
+    let item_kind = match item {
+        Annotatable::Item(item) => Some(&item.kind),
+        Annotatable::Stmt(stmt) => match &stmt.kind {
+            StmtKind::Item(item) => Some(&item.kind),
+            _ => None,
+        },
+        _ => None,
+    };
+
+    let bad_target =
+        !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
+    if bad_target {
+        struct_span_err!(
+            sess,
+            span,
+            E0774,
+            "`derive` may only be applied to structs, enums and unions",
+        )
+        .emit();
+    }
+    bad_target
+}
+
+fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
+    let help_msg = match lit.token.kind {
+        token::Str if rustc_lexer::is_ident(&lit.token.symbol.as_str()) => {
+            format!("try using `#[derive({})]`", lit.token.symbol)
+        }
+        _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
+    };
+    struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
+        .help(&help_msg)
+        .emit();
+}
+
+fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
+    let report_error = |title, action| {
+        let span = meta.span.with_lo(meta.path.span.hi());
+        sess.struct_span_err(span, title)
+            .span_suggestion(span, action, String::new(), Applicability::MachineApplicable)
+            .emit();
+    };
+    match meta.kind {
+        MetaItemKind::Word => {}
+        MetaItemKind::List(..) => report_error(
+            "traits in `#[derive(...)]` don't accept arguments",
+            "remove the arguments",
+        ),
+        MetaItemKind::NameValue(..) => {
+            report_error("traits in `#[derive(...)]` don't accept values", "remove the value")
+        }
+    }
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 59844b6c692..9a3c914337c 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -27,6 +27,7 @@ mod cfg_accessible;
 mod compile_error;
 mod concat;
 mod concat_idents;
+mod derive;
 mod deriving;
 mod env;
 mod format;
@@ -88,6 +89,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     register_attr! {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
+        derive: derive::Expander,
         global_allocator: global_allocator::expand,
         test: test::expand_test,
         test_case: test::expand_test_case,
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 08543d1622a..35ddb1fb9bc 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -141,7 +141,7 @@ impl Annotatable {
     }
 
     crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
-        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
+        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::Yes)
     }
 
     pub fn expect_item(self) -> P<ast::Item> {
@@ -234,25 +234,6 @@ impl Annotatable {
             _ => panic!("expected variant"),
         }
     }
-
-    pub fn derive_allowed(&self) -> bool {
-        match *self {
-            Annotatable::Stmt(ref stmt) => match stmt.kind {
-                ast::StmtKind::Item(ref item) => matches!(
-                    item.kind,
-                    ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..)
-                ),
-                _ => false,
-            },
-            Annotatable::Item(ref item) => match item.kind {
-                ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
-                    true
-                }
-                _ => false,
-            },
-            _ => false,
-        }
-    }
 }
 
 /// Result of an expansion that may need to be retried.
@@ -854,12 +835,6 @@ impl SyntaxExtension {
     }
 }
 
-/// Result of resolving a macro invocation.
-pub enum InvocationRes {
-    Single(Lrc<SyntaxExtension>),
-    DeriveContainer(Vec<Lrc<SyntaxExtension>>),
-}
-
 /// Error type that denotes indeterminacy.
 pub struct Indeterminate;
 
@@ -885,16 +860,29 @@ pub trait ResolverExpand {
         invoc: &Invocation,
         eager_expansion_root: ExpnId,
         force: bool,
-    ) -> Result<InvocationRes, Indeterminate>;
+    ) -> Result<Lrc<SyntaxExtension>, Indeterminate>;
 
     fn check_unused_macros(&mut self);
 
     /// Some parent node that is close enough to the given macro call.
-    fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId;
+    fn lint_node_id(&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;
+    /// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
+    fn resolve_derives(
+        &mut self,
+        expn_id: ExpnId,
+        derives: Vec<ast::Path>,
+        force: bool,
+    ) -> Result<(), Indeterminate>;
+    /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`
+    /// back from resolver.
+    fn take_derive_resolutions(
+        &mut self,
+        expn_id: ExpnId,
+    ) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>>;
     /// 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 5fdb7fc5915..870b5c92d89 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,24 +1,26 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
 use crate::configure;
-use crate::hygiene::{ExpnData, ExpnKind, SyntaxContext};
+use crate::hygiene::SyntaxContext;
 use crate::mbe::macro_rules::annotate_err_with_kind;
 use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
 use crate::placeholders::{placeholder, PlaceholderExpander};
-use crate::proc_macro::collect_derives;
 
+use rustc_ast as ast;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
-use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
+use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs};
+use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem};
+use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{struct_span_err, Applicability, PResult};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
 use rustc_parse::validate_attr;
@@ -302,20 +304,11 @@ pub enum InvocationKind {
         item: Annotatable,
         // Required for resolving derive helper attributes.
         derives: Vec<Path>,
-        // We temporarily report errors for attribute macros placed after derives
-        after_derive: bool,
     },
     Derive {
         path: Path,
         item: Annotatable,
     },
-    /// "Invocation" that contains all derives from an item,
-    /// broken into multiple `Derive` invocations when expanded.
-    /// FIXME: Find a way to remove it.
-    DeriveContainer {
-        derives: Vec<Path>,
-        item: Annotatable,
-    },
 }
 
 impl InvocationKind {
@@ -328,7 +321,6 @@ impl InvocationKind {
         match self {
             InvocationKind::Attr { item: Annotatable::StructField(field), .. }
             | InvocationKind::Derive { item: Annotatable::StructField(field), .. }
-            | InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
                 if field.ident.is_none() =>
             {
                 Some(field.vis.clone())
@@ -344,7 +336,6 @@ impl Invocation {
             InvocationKind::Bang { span, .. } => *span,
             InvocationKind::Attr { attr, .. } => attr.span,
             InvocationKind::Derive { path, .. } => path.span,
-            InvocationKind::DeriveContainer { item, .. } => item.span(),
         }
     }
 }
@@ -446,7 +437,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
-            let (invoc, res) = if let Some(invoc) = invocations.pop() {
+            let (invoc, ext) = if let Some(invoc) = invocations.pop() {
                 invoc
             } else {
                 self.resolve_imports();
@@ -464,8 +455,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 continue;
             };
 
-            let res = match res {
-                Some(res) => res,
+            let ext = match ext {
+                Some(ext) => ext,
                 None => {
                     let eager_expansion_root = if self.monotonic {
                         invoc.expansion_data.id
@@ -477,7 +468,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         eager_expansion_root,
                         force,
                     ) {
-                        Ok(res) => res,
+                        Ok(ext) => ext,
                         Err(Indeterminate) => {
                             // Cannot resolve, will retry this invocation later.
                             undetermined_invocations.push((invoc, None));
@@ -491,86 +482,78 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             self.cx.current_expansion = invoc.expansion_data.clone();
             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, &[]),
-                    ExpandResult::Retry(invoc) => {
-                        if force {
-                            self.cx.span_bug(
-                                invoc.span(),
-                                "expansion entered force mode but is still stuck",
-                            );
-                        } else {
-                            // Cannot expand, will retry this invocation later.
-                            undetermined_invocations
-                                .push((invoc, Some(InvocationRes::Single(ext))));
-                            continue;
-                        }
-                    }
-                },
-                InvocationRes::DeriveContainer(_exts) => {
-                    // FIXME: Consider using the derive resolutions (`_exts`) immediately,
-                    // instead of enqueuing the derives to be resolved again later.
-                    let (derives, mut item) = match invoc.kind {
-                        InvocationKind::DeriveContainer { derives, item } => (derives, item),
-                        _ => unreachable!(),
-                    };
-                    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 visitor = StripUnconfigured {
-                            sess: self.cx.sess,
-                            features: self.cx.ecfg.features,
-                            modified: false,
-                        };
-                        let mut item = visitor.fully_configure(item);
-                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-                        if visitor.modified && !derives.is_empty() {
-                            // Erase the tokens if cfg-stripping modified the item
-                            // This will cause us to synthesize fake tokens
-                            // when `nt_to_tokenstream` is called on this item.
-                            match &mut item {
-                                Annotatable::Item(item) => item.tokens = None,
-                                Annotatable::Stmt(stmt) => {
-                                    if let StmtKind::Item(item) = &mut stmt.kind {
-                                        item.tokens = None
-                                    } else {
-                                        panic!("Unexpected stmt {:?}", stmt);
-                                    }
-                                }
-                                _ => panic!("Unexpected annotatable {:?}", item),
+            let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) {
+                ExpandResult::Ready(fragment) => {
+                    let derive_placeholders = self
+                        .cx
+                        .resolver
+                        .take_derive_resolutions(expn_id)
+                        .map(|derives| {
+                            enum AnnotatableRef<'a> {
+                                Item(&'a P<ast::Item>),
+                                Stmt(&'a ast::Stmt),
                             }
-                        }
+                            let item = match &fragment {
+                                AstFragment::Items(items) => match &items[..] {
+                                    [item] => AnnotatableRef::Item(item),
+                                    _ => unreachable!(),
+                                },
+                                AstFragment::Stmts(stmts) => match &stmts[..] {
+                                    [stmt] => AnnotatableRef::Stmt(stmt),
+                                    _ => unreachable!(),
+                                },
+                                _ => unreachable!(),
+                            };
 
-                        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()
+                            invocations.reserve(derives.len());
+                            derives
+                                .into_iter()
+                                .map(|(_exts, path)| {
+                                    // FIXME: Consider using the derive resolutions (`_exts`)
+                                    // instead of enqueuing the derives to be resolved again later.
+                                    let expn_id = ExpnId::fresh(None);
+                                    invocations.push((
+                                        Invocation {
+                                            kind: InvocationKind::Derive {
+                                                path,
+                                                item: match item {
+                                                    AnnotatableRef::Item(item) => {
+                                                        Annotatable::Item(item.clone())
+                                                    }
+                                                    AnnotatableRef::Stmt(stmt) => {
+                                                        Annotatable::Stmt(P(stmt.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)
-                    };
+                                        None,
+                                    ));
+                                    NodeId::placeholder_from_expn_id(expn_id)
+                                })
+                                .collect::<Vec<_>>()
+                        })
+                        .unwrap_or_default();
 
-                    let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
                     self.collect_invocations(fragment, &derive_placeholders)
                 }
+                ExpandResult::Retry(invoc) => {
+                    if force {
+                        self.cx.span_bug(
+                            invoc.span(),
+                            "expansion entered force mode but is still stuck",
+                        );
+                    } else {
+                        // Cannot expand, will retry this invocation later.
+                        undetermined_invocations.push((invoc, Some(ext)));
+                        continue;
+                    }
+                }
             };
 
             progress = true;
@@ -596,29 +579,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         fragment_with_placeholders
     }
 
-    fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
-        let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
-        let span = attr.map_or(item.span(), |attr| attr.span);
-        let mut err = struct_span_err!(
-            self.cx.sess,
-            span,
-            E0774,
-            "`derive` may only be applied to structs, enums and unions",
-        );
-        if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr {
-            let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::<Vec<_>>();
-            let suggestion = format!("#[derive({})]", trait_list.join(", "));
-            err.span_suggestion(
-                span,
-                "try an outer attribute",
-                suggestion,
-                // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
-                Applicability::MaybeIncorrect,
-            );
-        }
-        err.emit();
-    }
-
     fn resolve_imports(&mut self) {
         if self.monotonic {
             self.cx.resolver.resolve_imports();
@@ -633,7 +593,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         &mut self,
         mut fragment: AstFragment,
         extra_placeholders: &[NodeId],
-    ) -> (AstFragment, Vec<(Invocation, Option<InvocationRes>)>) {
+    ) -> (AstFragment, Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>) {
         // Resolve `$crate`s in the fragment for pretty-printing.
         self.cx.resolver.resolve_dollar_crates();
 
@@ -733,7 +693,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext {
+            InvocationKind::Attr { attr, mut item, derives } => match ext {
                 SyntaxExtensionKind::Attr(expander) => {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
@@ -764,12 +724,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
                                     return ExpandResult::Retry(Invocation {
-                                        kind: InvocationKind::Attr {
-                                            attr,
-                                            item,
-                                            derives,
-                                            after_derive,
-                                        },
+                                        kind: InvocationKind::Attr { attr, item, derives },
                                         ..invoc
                                     });
                                 }
@@ -813,7 +768,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::DeriveContainer { .. } => unreachable!(),
         })
     }
 
@@ -1011,29 +965,13 @@ pub fn ensure_complete_parse<'a>(
 struct InvocationCollector<'a, 'b> {
     cx: &'a mut ExtCtxt<'b>,
     cfg: StripUnconfigured<'a>,
-    invocations: Vec<(Invocation, Option<InvocationRes>)>,
+    invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
     monotonic: bool,
 }
 
 impl<'a, 'b> InvocationCollector<'a, 'b> {
     fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
-        // Expansion data for all the collected invocations is set upon their resolution,
-        // with exception of the derive container case which is not resolved and can get
-        // its expansion data immediately.
-        let expn_data = match &kind {
-            InvocationKind::DeriveContainer { item, .. } => {
-                let mut expn_data = ExpnData::default(
-                    ExpnKind::Macro(MacroKind::Attr, sym::derive),
-                    item.span(),
-                    self.cx.sess.parse_sess.edition,
-                    None,
-                );
-                expn_data.parent = self.cx.current_expansion.id;
-                Some(expn_data)
-            }
-            _ => None,
-        };
-        let expn_id = ExpnId::fresh(expn_data);
+        let expn_id = ExpnId::fresh(None);
         let vis = kind.placeholder_visibility();
         self.invocations.push((
             Invocation {
@@ -1061,64 +999,44 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn collect_attr(
         &mut self,
-        (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
+        (attr, derives): (ast::Attribute, Vec<Path>),
         item: Annotatable,
         kind: AstFragmentKind,
     ) -> AstFragment {
-        self.collect(
-            kind,
-            match attr {
-                Some(attr) => InvocationKind::Attr { attr, item, derives, after_derive },
-                None => InvocationKind::DeriveContainer { derives, item },
-            },
-        )
-    }
-
-    fn find_attr_invoc(
-        &self,
-        attrs: &mut Vec<ast::Attribute>,
-        after_derive: &mut bool,
-    ) -> Option<ast::Attribute> {
-        attrs
-            .iter()
-            .position(|a| {
-                if a.has_name(sym::derive) {
-                    *after_derive = true;
-                }
-                !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
-            })
-            .map(|i| attrs.remove(i))
-    }
-
-    /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn take_first_attr(
-        &mut self,
-        item: &mut impl HasAttrs,
-    ) -> 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| {
-            attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
-            traits = collect_derives(&mut self.cx, &mut attrs);
-        });
-
-        if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
+        self.collect(kind, InvocationKind::Attr { attr, item, derives })
     }
 
-    /// 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 take_first_attr_no_derive(
-        &mut self,
-        nonitem: &mut impl HasAttrs,
-    ) -> 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);
+    /// If `item` is an attribute invocation, remove the attribute and return it together with
+    /// derives following it. We have to collect the derives in order to resolve legacy derive
+    /// helpers (helpers written before derives that introduce them).
+    fn take_first_attr(&mut self, item: &mut impl HasAttrs) -> Option<(ast::Attribute, Vec<Path>)> {
+        let mut attr = None;
+
+        item.visit_attrs(|attrs| {
+            attr = attrs
+                .iter()
+                .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+                .map(|attr_pos| {
+                    let attr = attrs.remove(attr_pos);
+                    let following_derives = attrs[attr_pos..]
+                        .iter()
+                        .filter(|a| a.has_name(sym::derive))
+                        .flat_map(|a| a.meta_item_list().unwrap_or_default())
+                        .filter_map(|nested_meta| match nested_meta {
+                            NestedMetaItem::MetaItem(ast::MetaItem {
+                                kind: MetaItemKind::Word,
+                                path,
+                                ..
+                            }) => Some(path),
+                            _ => None,
+                        })
+                        .collect();
+
+                    (attr, following_derives)
+                })
         });
 
-        attr.map(|attr| (Some(attr), Vec::new(), after_derive))
+        attr
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1132,17 +1050,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         for attr in attrs.iter() {
             rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
             validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
-
-            // macros are expanded before any lint passes so this warning has to be hardcoded
-            if attr.has_name(sym::derive) {
-                self.cx
-                    .parse_sess()
-                    .span_diagnostic
-                    .struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
-                    .note("this may become a hard error in a future release")
-                    .emit();
-            }
-
             if attr.doc_str().is_some() {
                 self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
                     &UNUSED_DOC_COMMENTS,
@@ -1162,12 +1069,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         visit_clobber(expr.deref_mut(), |mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
+            if let Some(attr) = self.take_first_attr(&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.
-                if let Some(attr) = attr.0.as_ref() {
-                    self.cfg.maybe_emit_expr_attr_err(attr)
-                }
+                self.cfg.maybe_emit_expr_attr_err(&attr.0);
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
@@ -1263,10 +1168,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         expr.filter_map(|mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
-                if let Some(attr) = attr.0.as_ref() {
-                    self.cfg.maybe_emit_expr_attr_err(attr)
-                }
+            if let Some(attr) = self.take_first_attr(&mut expr) {
+                self.cfg.maybe_emit_expr_attr_err(&attr.0);
 
                 return self
                     .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
@@ -1308,15 +1211,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let attr = if stmt.is_item() {
-                self.take_first_attr(&mut stmt)
-            } else {
-                // Ignore derives on non-item statements for backwards compatibility.
-                // This will result in a unused attribute warning
-                self.take_first_attr_no_derive(&mut stmt)
-            };
-
-            if let Some(attr) = attr {
+            if let Some(attr) = self.take_first_attr(&mut stmt) {
                 return self
                     .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
                     .make_stmts();
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 6779734cfc1..8cbaa7c945a 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -1,16 +1,14 @@
 use crate::base::{self, *};
 use crate::proc_macro_server;
 
+use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
-use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
-use rustc_lexer::is_ident;
+use rustc_errors::ErrorReported;
 use rustc_parse::nt_to_tokenstream;
 use rustc_parse::parser::ForceCollect;
-use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 
 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
@@ -142,91 +140,3 @@ impl MultiItemModifier for ProcMacroDerive {
         ExpandResult::Ready(items)
     }
 }
-
-crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
-    let mut result = Vec::new();
-    attrs.retain(|attr| {
-        if !attr.has_name(sym::derive) {
-            return true;
-        }
-
-        // 1) First let's ensure that it's a meta item.
-        let nmis = match attr.meta_item_list() {
-            None => {
-                cx.struct_span_err(attr.span, "malformed `derive` attribute input")
-                    .span_suggestion(
-                        attr.span,
-                        "missing traits to be derived",
-                        "#[derive(Trait1, Trait2, ...)]".to_owned(),
-                        Applicability::HasPlaceholders,
-                    )
-                    .emit();
-                return false;
-            }
-            Some(x) => x,
-        };
-
-        let mut error_reported_filter_map = false;
-        let mut error_reported_map = false;
-        let traits = nmis
-            .into_iter()
-            // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
-            .filter_map(|nmi| match nmi {
-                NestedMetaItem::Literal(lit) => {
-                    error_reported_filter_map = true;
-                    let mut err = struct_span_err!(
-                        cx.sess,
-                        lit.span,
-                        E0777,
-                        "expected path to a trait, found literal",
-                    );
-                    let token = lit.token.to_string();
-                    if token.starts_with('"')
-                        && token.len() > 2
-                        && is_ident(&token[1..token.len() - 1])
-                    {
-                        err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
-                    } else {
-                        err.help("for example, write `#[derive(Debug)]` for `Debug`");
-                    }
-                    err.emit();
-                    None
-                }
-                NestedMetaItem::MetaItem(mi) => Some(mi),
-            })
-            // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
-            // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
-            // In this case we can still at least determine that the user
-            // wanted this trait to be derived, so let's keep it.
-            .map(|mi| {
-                let mut traits_dont_accept = |title, action| {
-                    error_reported_map = true;
-                    let sp = mi.span.with_lo(mi.path.span.hi());
-                    cx.struct_span_err(sp, title)
-                        .span_suggestion(
-                            sp,
-                            action,
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                };
-                match &mi.kind {
-                    MetaItemKind::List(..) => traits_dont_accept(
-                        "traits in `#[derive(...)]` don't accept arguments",
-                        "remove the arguments",
-                    ),
-                    MetaItemKind::NameValue(..) => traits_dont_accept(
-                        "traits in `#[derive(...)]` don't accept values",
-                        "remove the value",
-                    ),
-                    MetaItemKind::Word => {}
-                }
-                mi.path
-            });
-
-        result.extend(traits);
-        !error_reported_filter_map && !error_reported_map
-    });
-    result
-}
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 3ed5320da73..ac50703b544 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -188,7 +188,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
 
     // Macros:
-    ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
     ungated!(automatically_derived, Normal, template!(Word)),
     // FIXME(#14407)
     ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 58a9064b919..254220839aa 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -636,6 +636,9 @@ pub trait LintContext: Sized {
                     db.span_label(span, "ABI should be specified here");
                     db.help(&format!("the default ABI is {}", default_abi.name()));
                 }
+                BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
+                    db.span_label(span, "the attribute is introduced here");
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index da62ad3a6b1..f0a5ea150b7 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1,12 +1,11 @@
 // ignore-tidy-filelength
+
 //! Some lints that are built in to the compiler.
 //!
 //! These are the built-in lints that are emitted direct in the main
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
 
-// ignore-tidy-filelength
-
 use crate::{declare_lint, declare_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
@@ -2922,6 +2921,52 @@ declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `legacy_derive_helpers` lint detects derive helper attributes
+    /// that are used before they are introduced.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs extern crate)
+    /// #[serde(rename_all = "camelCase")]
+    /// #[derive(Deserialize)]
+    /// struct S { /* fields */ }
+    /// ```
+    ///
+    /// produces:
+    ///
+    /// ```text
+    /// warning: derive helper attribute is used before it is introduced
+    ///   --> $DIR/legacy-derive-helpers.rs:1:3
+    ///    |
+    ///  1 | #[serde(rename_all = "camelCase")]
+    ///    |   ^^^^^
+    /// ...
+    ///  2 | #[derive(Deserialize)]
+    ///    |          ----------- the attribute is introduced here
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Attributes like this work for historical reasons, but attribute expansion works in
+    /// left-to-right order in general, so, to resolve `#[serde]`, compiler has to try to "look
+    /// into the future" at not yet expanded part of the item , but such attempts are not always
+    /// reliable.
+    ///
+    /// To fix the warning place the helper attribute after its corresponding derive.
+    /// ```rust,ignore (needs extern crate)
+    /// #[derive(Deserialize)]
+    /// #[serde(rename_all = "camelCase")]
+    /// struct S { /* fields */ }
+    /// ```
+    pub LEGACY_DERIVE_HELPERS,
+    Warn,
+    "detects derive helper attributes that are used before they are introduced",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>",
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3012,6 +3057,7 @@ declare_lint_pass! {
         MISSING_ABI,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
         DISJOINT_CAPTURE_DROP_REORDER,
+        LEGACY_DERIVE_HELPERS,
     ]
 }
 
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 9d60a51a0af..594e2cbd3ae 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -256,6 +256,7 @@ pub enum BuiltinLintDiagnostics {
     MissingAbi(Span, Abi),
     UnusedDocComment(Span),
     PatternsInFnsWithoutBody(Span, Ident),
+    LegacyDeriveHelpers(Span),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 1b26fb33370..523eb9dba35 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -306,13 +306,11 @@ 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`),
+    // One of the attributes may either itself be a macro,
     // or expand to macro attributes (`cfg_attr`).
     attrs.iter().any(|attr| {
         attr.ident().map_or(true, |ident| {
-            ident.name == sym::derive
-                || ident.name == sym::cfg_attr
-                || !rustc_feature::is_builtin_attr_name(ident.name)
+            ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
         })
     })
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 2be669a1726..819fabdd1f1 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -967,6 +967,8 @@ pub struct Resolver<'a> {
     output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
     /// Helper attributes that are in scope for the given expansion.
     helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
+    /// Resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
+    derive_resolutions: FxHashMap<ExpnId, Vec<(Lrc<SyntaxExtension>, ast::Path)>>,
 
     /// Avoid duplicated errors for "name already defined".
     name_already_seen: FxHashMap<Symbol, Span>,
@@ -1295,6 +1297,7 @@ impl<'a> Resolver<'a> {
             invocation_parent_scopes: Default::default(),
             output_macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
+            derive_resolutions: Default::default(),
             local_macro_def_scopes: FxHashMap::default(),
             name_already_seen: FxHashMap::default(),
             potentially_unused_imports: Vec::new(),
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d76db7c645a..6d3fde33f4d 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -14,8 +14,7 @@ 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};
-use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
@@ -24,7 +23,8 @@ use rustc_hir::def_id;
 use rustc_hir::PrimTy;
 use rustc_middle::middle::stability;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -227,7 +227,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
         invoc: &Invocation,
         eager_expansion_root: ExpnId,
         force: bool,
-    ) -> Result<InvocationRes, Indeterminate> {
+    ) -> Result<Lrc<SyntaxExtension>, Indeterminate> {
         let invoc_id = invoc.expansion_data.id;
         let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) {
             Some(parent_scope) => *parent_scope,
@@ -244,65 +244,15 @@ impl<'a> ResolverExpand for Resolver<'a> {
             }
         };
 
-        let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
-            InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
+        let (path, kind, inner_attr, derives) = match invoc.kind {
+            InvocationKind::Attr { ref attr, ref derives, .. } => (
                 &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, &[][..], 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:
-                // - Derive helper attributes are in scope for the item to which the `#[derive]`
-                //   is applied, so they have to be produced by the container's expansion rather
-                //   than by individual derives.
-                // - Derives in the container need to know whether one of them is a built-in `Copy`.
-                // FIXME: Try to avoid repeated resolutions for derives here and in expansion.
-                let mut exts = Vec::new();
-                let mut helper_attrs = Vec::new();
-                for path in derives {
-                    exts.push(
-                        match self.resolve_macro_path(
-                            path,
-                            Some(MacroKind::Derive),
-                            &parent_scope,
-                            true,
-                            force,
-                        ) {
-                            Ok((Some(ext), _)) => {
-                                let span = path
-                                    .segments
-                                    .last()
-                                    .unwrap()
-                                    .ident
-                                    .span
-                                    .normalize_to_macros_2_0();
-                                helper_attrs.extend(
-                                    ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
-                                );
-                                if ext.builtin_name == Some(sym::Copy) {
-                                    self.containers_deriving_copy.insert(invoc_id);
-                                }
-                                ext
-                            }
-                            Ok(_) | Err(Determinacy::Determined) => {
-                                self.dummy_ext(MacroKind::Derive)
-                            }
-                            Err(Determinacy::Undetermined) => return Err(Indeterminate),
-                        },
-                    )
-                }
-                self.helper_attrs.insert(invoc_id, helper_attrs);
-                return Ok(InvocationRes::DeriveContainer(exts));
-            }
+            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
+            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
         };
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
@@ -328,14 +278,11 @@ impl<'a> ResolverExpand for Resolver<'a> {
         ));
 
         if let Res::Def(_, _) = res {
-            if after_derive {
-                self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
-            }
             let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod;
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
         }
 
-        Ok(InvocationRes::Single(ext))
+        Ok(ext)
     }
 
     fn check_unused_macros(&mut self) {
@@ -344,7 +291,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
         }
     }
 
-    fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
+    fn lint_node_id(&self, expn_id: ExpnId) -> NodeId {
         // FIXME - make this more precise. This currently returns the NodeId of the
         // nearest closing item - we should try to return the closest parent of the ExpnId
         self.invocation_parents
@@ -356,6 +303,63 @@ impl<'a> ResolverExpand for Resolver<'a> {
         self.containers_deriving_copy.contains(&expn_id)
     }
 
+    fn resolve_derives(
+        &mut self,
+        expn_id: ExpnId,
+        derives: Vec<ast::Path>,
+        force: bool,
+    ) -> Result<(), Indeterminate> {
+        // Block expansion of the container until we resolve all derives in it.
+        // This is required for two reasons:
+        // - Derive helper attributes are in scope for the item to which the `#[derive]`
+        //   is applied, so they have to be produced by the container's expansion rather
+        //   than by individual derives.
+        // - Derives in the container need to know whether one of them is a built-in `Copy`.
+        // FIXME: Try to cache intermediate results to avoid resolving same derives multiple times.
+        let parent_scope = self.invocation_parent_scopes[&expn_id];
+        let mut exts = Vec::new();
+        let mut helper_attrs = Vec::new();
+        let mut has_derive_copy = false;
+        for path in derives {
+            exts.push((
+                match self.resolve_macro_path(
+                    &path,
+                    Some(MacroKind::Derive),
+                    &parent_scope,
+                    true,
+                    force,
+                ) {
+                    Ok((Some(ext), _)) => {
+                        let span =
+                            path.segments.last().unwrap().ident.span.normalize_to_macros_2_0();
+                        helper_attrs
+                            .extend(ext.helper_attrs.iter().map(|name| Ident::new(*name, span)));
+                        has_derive_copy |= ext.builtin_name == Some(sym::Copy);
+                        ext
+                    }
+                    Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
+                    Err(Determinacy::Undetermined) => return Err(Indeterminate),
+                },
+                path,
+            ))
+        }
+        self.derive_resolutions.insert(expn_id, exts);
+        self.helper_attrs.insert(expn_id, helper_attrs);
+        // Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
+        // has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
+        if has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
+            self.containers_deriving_copy.insert(expn_id);
+        }
+        Ok(())
+    }
+
+    fn take_derive_resolutions(
+        &mut self,
+        expn_id: ExpnId,
+    ) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>> {
+        self.derive_resolutions.remove(&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.
@@ -818,6 +822,8 @@ impl<'a> Resolver<'a> {
                                 let is_builtin = |res| {
                                     matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
                                 };
+                                let derive_helper =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
                                 let derive_helper_compat =
                                     Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
 
@@ -826,7 +832,7 @@ impl<'a> Resolver<'a> {
                                 } else if is_builtin(innermost_res) || is_builtin(res) {
                                     Some(AmbiguityKind::BuiltinAttr)
                                 } else if innermost_res == derive_helper_compat
-                                    || res == derive_helper_compat
+                                    || res == derive_helper_compat && innermost_res != derive_helper
                                 {
                                     Some(AmbiguityKind::DeriveHelper)
                                 } else if innermost_flags.contains(Flags::MACRO_RULES)
@@ -992,6 +998,15 @@ impl<'a> Resolver<'a> {
                     let res = binding.res();
                     let seg = Segment::from_ident(ident);
                     check_consistency(self, &[seg], ident.span, kind, initial_res, res);
+                    if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
+                        self.lint_buffer.buffer_lint_with_diagnostic(
+                            LEGACY_DERIVE_HELPERS,
+                            self.lint_node_id(parent_scope.expansion),
+                            ident.span,
+                            "derive helper attribute is used before it is introduced",
+                            BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span),
+                        );
+                    }
                 }
                 Err(..) => {
                     let expected = kind.descr_expected();
@@ -1078,7 +1093,7 @@ impl<'a> Resolver<'a> {
     crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
-        if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive {
+        if ident.name == sym::cfg || ident.name == sym::cfg_attr {
             let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                 self.session.span_err(
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 6a7e4b2ba25..7aaf5a5fd46 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1324,6 +1324,14 @@ pub(crate) mod builtin {
         (false) => {{ /* compiler built-in */ }};
     }
 
+    /// Attribute macro used to apply derive macros.
+    #[cfg(not(bootstrap))]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_builtin_macro]
+    pub macro derive($item:item) {
+        /* compiler built-in */
+    }
+
     /// Attribute macro applied to a function to turn it into a unit test.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(test, rustc_attrs)]
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index b4fff3d67b5..a1fbd8dec75 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -69,6 +69,11 @@ pub use crate::macros::builtin::{
     bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
 };
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
+#[doc(no_inline)]
+pub use crate::macros::builtin::derive;
+
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 26302d0ecf2..ef9aec54a4c 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -54,6 +54,11 @@ pub use core::prelude::v1::{
     bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
 };
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
+#[doc(hidden)]
+pub use core::prelude::v1::derive;
+
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index f4b8dc9a3ad..297fc95006b 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -96,8 +96,8 @@ pub struct Deprecation {
     pub note: Option<String>,
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum Visibility {
     Public,
     /// For the most part items are private by default. The exceptions are associated items of
@@ -112,8 +112,8 @@ pub enum Visibility {
     },
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum GenericArgs {
     /// <'a, 32, B: Copy, C = u32>
     AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
@@ -121,8 +121,8 @@ pub enum GenericArgs {
     Parenthesized { inputs: Vec<Type>, output: Option<Type> },
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum GenericArg {
     Lifetime(String),
     Type(Type),
@@ -144,8 +144,8 @@ pub struct TypeBinding {
     pub binding: TypeBindingKind,
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
     Equality(Type),
     Constraint(Vec<GenericBound>),
@@ -154,8 +154,8 @@ pub enum TypeBindingKind {
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Id(pub String);
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum ItemKind {
     Module,
     ExternCrate,
@@ -184,8 +184,8 @@ pub enum ItemKind {
     Keyword,
 }
 
-#[serde(untagged)]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(untagged)]
 pub enum ItemEnum {
     ModuleItem(Module),
     ExternCrateItem {
@@ -264,17 +264,17 @@ pub struct Enum {
     pub impls: Vec<Id>,
 }
 
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "variant_kind", content = "variant_inner")]
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub enum Variant {
     Plain,
     Tuple(Vec<Type>),
     Struct(Vec<Id>),
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum StructType {
     Plain,
     Tuple,
@@ -310,24 +310,24 @@ pub struct GenericParamDef {
     pub kind: GenericParamDefKind,
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum GenericParamDefKind {
     Lifetime,
     Type { bounds: Vec<GenericBound>, default: Option<Type> },
     Const(Type),
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
     RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
     EqPredicate { lhs: Type, rhs: Type },
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum GenericBound {
     TraitBound {
         #[serde(rename = "trait")]
@@ -339,17 +339,17 @@ pub enum GenericBound {
     Outlives(String),
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum TraitBoundModifier {
     None,
     Maybe,
     MaybeConst,
 }
 
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub enum Type {
     /// Structs, enums, and traits
     ResolvedPath {
@@ -448,8 +448,8 @@ pub struct Impl {
     pub blanket_impl: Option<Type>,
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub struct Import {
     /// The full path being imported.
     pub span: String,
@@ -468,8 +468,8 @@ pub struct ProcMacro {
     pub helpers: Vec<String>,
 }
 
-#[serde(rename_all = "snake_case")]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
 pub enum MacroKind {
     /// A bang macro `foo!()`.
     Bang,
diff --git a/src/test/run-make-fulldeps/simd-ffi/simd.rs b/src/test/run-make-fulldeps/simd-ffi/simd.rs
index 717da367fee..d11cfd77c5b 100644
--- a/src/test/run-make-fulldeps/simd-ffi/simd.rs
+++ b/src/test/run-make-fulldeps/simd-ffi/simd.rs
@@ -75,3 +75,8 @@ auto trait Freeze {}
 macro_rules! Copy {
     () => {};
 }
+#[macro_export]
+#[rustc_builtin_macro]
+macro_rules! derive {
+    () => {};
+}
diff --git a/src/test/ui/derives/derive-deadlock.rs b/src/test/ui/derives/derive-deadlock.rs
new file mode 100644
index 00000000000..0137b1e5bfb
--- /dev/null
+++ b/src/test/ui/derives/derive-deadlock.rs
@@ -0,0 +1,6 @@
+use std as derive;
+
+#[derive(Default)] //~ ERROR cannot determine resolution for the attribute macro `derive`
+struct S;
+
+fn main() {}
diff --git a/src/test/ui/derives/derive-deadlock.stderr b/src/test/ui/derives/derive-deadlock.stderr
new file mode 100644
index 00000000000..8d062491c6a
--- /dev/null
+++ b/src/test/ui/derives/derive-deadlock.stderr
@@ -0,0 +1,10 @@
+error: cannot determine resolution for the attribute macro `derive`
+  --> $DIR/derive-deadlock.rs:3:3
+   |
+LL | #[derive(Default)]
+   |   ^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/derives/derive-multiple-with-packed.rs b/src/test/ui/derives/derive-multiple-with-packed.rs
new file mode 100644
index 00000000000..e762ee357ca
--- /dev/null
+++ b/src/test/ui/derives/derive-multiple-with-packed.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#[derive(Clone, Copy)]
+#[derive(Debug)] // OK, even if `Copy` is in the different `#[derive]`
+#[repr(packed)]
+struct CacheRecordHeader {
+    field: u64,
+}
+
+fn main() {}
diff --git a/src/test/ui/derives/deriving-meta-empty-trait-list.rs b/src/test/ui/derives/deriving-meta-empty-trait-list.rs
index 4f2e31e8efb..0306ce717d0 100644
--- a/src/test/ui/derives/deriving-meta-empty-trait-list.rs
+++ b/src/test/ui/derives/deriving-meta-empty-trait-list.rs
@@ -1,6 +1,8 @@
+// check-pass
+
 #![deny(unused)]
 
-#[derive()] //~ ERROR unused attribute
+#[derive()] // OK
 struct _Bar;
 
 pub fn main() {}
diff --git a/src/test/ui/derives/deriving-meta-empty-trait-list.stderr b/src/test/ui/derives/deriving-meta-empty-trait-list.stderr
deleted file mode 100644
index 1fd7d58c86a..00000000000
--- a/src/test/ui/derives/deriving-meta-empty-trait-list.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: unused attribute
-  --> $DIR/deriving-meta-empty-trait-list.rs:3:1
-   |
-LL | #[derive()]
-   | ^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/deriving-meta-empty-trait-list.rs:1:9
-   |
-LL | #![deny(unused)]
-   |         ^^^^^^
-   = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/derives/issue-36617.rs b/src/test/ui/derives/issue-36617.rs
index 1102f3c4640..08fc82e91f6 100644
--- a/src/test/ui/derives/issue-36617.rs
+++ b/src/test/ui/derives/issue-36617.rs
@@ -1,4 +1,3 @@
-#![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
-                 //~| ERROR cannot determine resolution for the derive macro `Copy`
+#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
 
 fn main() {}
diff --git a/src/test/ui/derives/issue-36617.stderr b/src/test/ui/derives/issue-36617.stderr
index dc6ef169259..0716764b427 100644
--- a/src/test/ui/derives/issue-36617.stderr
+++ b/src/test/ui/derives/issue-36617.stderr
@@ -1,17 +1,10 @@
-error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-36617.rs:1:1
+error: cannot determine resolution for the attribute macro `derive`
+  --> $DIR/issue-36617.rs:1:4
    |
 LL | #![derive(Copy)]
-   | ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]`
-
-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 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-derive.rs b/src/test/ui/feature-gates/issue-43106-gating-of-derive.rs
index c5d9e0db4d3..5404b8c04bb 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-derive.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-derive.rs
@@ -6,6 +6,7 @@
 mod derive {
     mod inner { #![derive(Debug)] }
     //~^ ERROR `derive` may only be applied to structs, enums and unions
+    //~| ERROR inner macro attributes are unstable
 
     #[derive(Debug)]
     //~^ ERROR `derive` may only be applied to structs, enums and unions
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-derive.stderr
index ffec76f409e..9b1f4f46219 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-derive.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-derive.stderr
@@ -4,30 +4,40 @@ error[E0774]: `derive` may only be applied to structs, enums and unions
 LL | #[derive(Debug)]
    | ^^^^^^^^^^^^^^^^
 
+error[E0658]: inner macro attributes are unstable
+  --> $DIR/issue-43106-gating-of-derive.rs:7:20
+   |
+LL |     mod inner { #![derive(Debug)] }
+   |                    ^^^^^^
+   |
+   = 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[E0774]: `derive` may only be applied to structs, enums and unions
   --> $DIR/issue-43106-gating-of-derive.rs:7:17
    |
 LL |     mod inner { #![derive(Debug)] }
-   |                 ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]`
+   |                 ^^^^^^^^^^^^^^^^^
 
 error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-43106-gating-of-derive.rs:10:5
+  --> $DIR/issue-43106-gating-of-derive.rs:11:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
 
 error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-43106-gating-of-derive.rs:23:5
+  --> $DIR/issue-43106-gating-of-derive.rs:24:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
 
 error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-43106-gating-of-derive.rs:27:5
+  --> $DIR/issue-43106-gating-of-derive.rs:28:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0774`.
+Some errors have detailed explanations: E0658, E0774.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-49934-errors.rs b/src/test/ui/issues/issue-49934-errors.rs
index bf95f8fa7e1..dd14bac5e3a 100644
--- a/src/test/ui/issues/issue-49934-errors.rs
+++ b/src/test/ui/issues/issue-49934-errors.rs
@@ -1,11 +1,8 @@
-fn foo<#[derive(Debug)] T>() {
-//~^ ERROR `derive` may only be applied to structs, enums and unions
+fn foo<#[derive(Debug)] T>() { //~ ERROR expected non-macro attribute, found attribute macro
     match 0 {
-        #[derive(Debug)]
-        //~^ ERROR `derive` may only be applied to structs, enums and unions
+        #[derive(Debug)] //~ ERROR expected non-macro attribute, found attribute macro
         _ => (),
     }
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr
index 71cd2d30342..8c4c54170a1 100644
--- a/src/test/ui/issues/issue-49934-errors.stderr
+++ b/src/test/ui/issues/issue-49934-errors.stderr
@@ -1,15 +1,14 @@
-error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-49934-errors.rs:1:8
+error: expected non-macro attribute, found attribute macro `derive`
+  --> $DIR/issue-49934-errors.rs:1:10
    |
 LL | fn foo<#[derive(Debug)] T>() {
-   |        ^^^^^^^^^^^^^^^^
+   |          ^^^^^^ not a non-macro attribute
 
-error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-49934-errors.rs:4:9
+error: expected non-macro attribute, found attribute macro `derive`
+  --> $DIR/issue-49934-errors.rs:3:11
    |
 LL |         #[derive(Debug)]
-   |         ^^^^^^^^^^^^^^^^
+   |           ^^^^^^ not a non-macro attribute
 
 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.rs b/src/test/ui/issues/issue-49934.rs
index 5b253750db0..ec73e670634 100644
--- a/src/test/ui/issues/issue-49934.rs
+++ b/src/test/ui/issues/issue-49934.rs
@@ -1,7 +1,4 @@
-// check-pass
-
 #![feature(stmt_expr_attributes)]
-#![warn(unused_attributes)] //~ NOTE the lint level is defined here
 
 fn main() {
     // fold_stmt (Item)
@@ -10,26 +7,24 @@ fn main() {
     struct Foo;
 
     // fold_stmt (Mac)
-    #[derive(Debug)]
-    //~^ WARN `#[derive]` does nothing on macro invocations
-    //~| NOTE this may become a hard error in a future release
+    #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
     println!("Hello, world!");
 
     // fold_stmt (Semi)
-    #[derive(Debug)] //~ WARN unused attribute
+    #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
     "Hello, world!";
 
     // fold_stmt (Local)
-    #[derive(Debug)] //~ WARN unused attribute
+    #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
     let _ = "Hello, world!";
 
     // visit_expr
     let _ = #[derive(Debug)] "Hello, world!";
-    //~^ WARN unused attribute
+    //~^ ERROR `derive` may only be applied to structs, enums and unions
 
     let _ = [
         // filter_map_expr
-        #[derive(Debug)] //~ WARN unused attribute
-        "Hello, world!"
+        #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
+        "Hello, world!",
     ];
 }
diff --git a/src/test/ui/issues/issue-49934.stderr b/src/test/ui/issues/issue-49934.stderr
index 8a5596521ec..7746ad287ab 100644
--- a/src/test/ui/issues/issue-49934.stderr
+++ b/src/test/ui/issues/issue-49934.stderr
@@ -1,40 +1,33 @@
-warning: `#[derive]` does nothing on macro invocations
-  --> $DIR/issue-49934.rs:13:5
+error[E0774]: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934.rs:10:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
-   |
-   = note: this may become a hard error in a future release
 
-warning: unused attribute
-  --> $DIR/issue-49934.rs:19:5
+error[E0774]: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934.rs:14:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/issue-49934.rs:4:9
-   |
-LL | #![warn(unused_attributes)]
-   |         ^^^^^^^^^^^^^^^^^
 
-warning: unused attribute
-  --> $DIR/issue-49934.rs:23:5
+error[E0774]: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934.rs:18:5
    |
 LL |     #[derive(Debug)]
    |     ^^^^^^^^^^^^^^^^
 
-warning: unused attribute
-  --> $DIR/issue-49934.rs:27:13
+error[E0774]: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934.rs:22:13
    |
 LL |     let _ = #[derive(Debug)] "Hello, world!";
    |             ^^^^^^^^^^^^^^^^
 
-warning: unused attribute
-  --> $DIR/issue-49934.rs:32:9
+error[E0774]: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-49934.rs:27:9
    |
 LL |         #[derive(Debug)]
    |         ^^^^^^^^^^^^^^^^
 
-warning: 5 warnings emitted
+error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/macros/builtin-std-paths-fail.stderr b/src/test/ui/macros/builtin-std-paths-fail.stderr
index 9831e46ec30..4f1a76b0d6e 100644
--- a/src/test/ui/macros/builtin-std-paths-fail.stderr
+++ b/src/test/ui/macros/builtin-std-paths-fail.stderr
@@ -1,3 +1,15 @@
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:2:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
 error[E0433]: failed to resolve: could not find `bench` in `core`
   --> $DIR/builtin-std-paths-fail.rs:7:9
    |
@@ -23,28 +35,28 @@ LL | #[core::test]
    |         ^^^^ could not find `test` in `core`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:2:11
+  --> $DIR/builtin-std-paths-fail.rs:4:11
    |
 LL |     core::RustcDecodable,
    |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:4:11
+  --> $DIR/builtin-std-paths-fail.rs:2:11
    |
 LL |     core::RustcDecodable,
    |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
 
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:4:11
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:14:10
    |
-LL |     core::RustcDecodable,
-   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:2:11
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
    |
-LL |     core::RustcDecodable,
-   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
 error[E0433]: failed to resolve: could not find `bench` in `std`
   --> $DIR/builtin-std-paths-fail.rs:19:8
@@ -71,18 +83,6 @@ LL | #[std::test]
    |        ^^^^ could not find `test` in `std`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:14:10
-   |
-LL |     std::RustcDecodable,
-   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
-
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:16:10
-   |
-LL |     std::RustcDecodable,
-   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
-
-error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
   --> $DIR/builtin-std-paths-fail.rs:16:10
    |
 LL |     std::RustcDecodable,
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 1fd7cddc7c9..fc4c3f4e64b 100644
--- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
@@ -1,9 +1,6 @@
 fn main() {}
 
 struct CLI {
-    #[derive(parse())]
-    //~^ ERROR traits in `#[derive(...)]` don't accept arguments
-    //~| ERROR cannot find derive macro `parse` in this scope
+    #[derive(parse())] //~ ERROR expected non-macro attribute, found attribute macro
     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 db40ce07530..04f7ebe019e 100644
--- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
@@ -1,21 +1,8 @@
-error: traits in `#[derive(...)]` don't accept arguments
-  --> $DIR/issue-69341-malformed-derive-inert.rs:4:19
+error: expected non-macro attribute, found attribute macro `derive`
+  --> $DIR/issue-69341-malformed-derive-inert.rs:4:7
    |
 LL |     #[derive(parse())]
-   |                   ^^ help: remove the arguments
+   |       ^^^^^^ not a non-macro attribute
 
-error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-69341-malformed-derive-inert.rs:7:5
-   |
-LL |     path: (),
-   |     ^^^^^^^^
-
-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 3 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr
index 63be8f9ca14..365cc099e9d 100644
--- a/src/test/ui/malformed/malformed-derive-entry.stderr
+++ b/src/test/ui/malformed/malformed-derive-entry.stderr
@@ -14,7 +14,7 @@ error: malformed `derive` attribute input
   --> $DIR/malformed-derive-entry.rs:11:1
    |
 LL | #[derive]
-   | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
+   | ^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
 error[E0277]: the trait bound `Test1: Clone` is not satisfied
   --> $DIR/malformed-derive-entry.rs:1:10
diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr
index 6f535e03e6a..1764c3969cf 100644
--- a/src/test/ui/malformed/malformed-special-attrs.stderr
+++ b/src/test/ui/malformed/malformed-special-attrs.stderr
@@ -18,13 +18,13 @@ error: malformed `derive` attribute input
   --> $DIR/malformed-special-attrs.rs:7:1
    |
 LL | #[derive]
-   | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
+   | ^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
 error: malformed `derive` attribute input
   --> $DIR/malformed-special-attrs.rs:10:1
    |
 LL | #[derive = ""]
-   | ^^^^^^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
+   | ^^^^^^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/proc-macro/attribute-after-derive.rs b/src/test/ui/proc-macro/attribute-after-derive.rs
new file mode 100644
index 00000000000..0f0f27bff97
--- /dev/null
+++ b/src/test/ui/proc-macro/attribute-after-derive.rs
@@ -0,0 +1,28 @@
+// Macro attributes are allowed after `#[derive]` and
+// `#[derive]` fully configures the item for following attributes.
+
+// check-pass
+// compile-flags: -Z span-debug
+// aux-build: test-macros.rs
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+#[print_attr]
+#[derive(Print)]
+struct AttributeDerive {
+    #[cfg(FALSE)]
+    field: u8,
+}
+
+#[derive(Print)]
+#[print_attr]
+struct DeriveAttribute {
+    #[cfg(FALSE)]
+    field: u8,
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/attribute-after-derive.stdout b/src/test/ui/proc-macro/attribute-after-derive.stdout
new file mode 100644
index 00000000000..78c58c0a32f
--- /dev/null
+++ b/src/test/ui/proc-macro/attribute-after-derive.stdout
@@ -0,0 +1,148 @@
+PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field : u8, }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Punct {
+        ch: '#',
+        spacing: Alone,
+        span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "derive",
+                span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0),
+            },
+            Group {
+                delimiter: Parenthesis,
+                stream: TokenStream [
+                    Ident {
+                        ident: "Print",
+                        span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0),
+                    },
+                ],
+                span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0),
+            },
+        ],
+        span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
+    },
+    Ident {
+        ident: "AttributeDerive",
+        span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "cfg",
+                        span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "FALSE",
+                                span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
+                            },
+                        ],
+                        span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0),
+                    },
+                ],
+                span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0),
+            },
+            Ident {
+                ident: "field",
+                span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0),
+            },
+        ],
+        span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "struct",
+        span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
+    },
+    Ident {
+        ident: "AttributeDerive",
+        span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [],
+        span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
+    },
+]
+PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "struct",
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Ident {
+        ident: "DeriveAttribute",
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [],
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Punct {
+        ch: '#',
+        spacing: Alone,
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "print_attr",
+                span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+            },
+        ],
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Ident {
+        ident: "DeriveAttribute",
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [],
+        span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
+    },
+]
diff --git a/src/test/ui/proc-macro/attribute-order-restricted.rs b/src/test/ui/proc-macro/attribute-order-restricted.rs
deleted file mode 100644
index a3d4d23450c..00000000000
--- a/src/test/ui/proc-macro/attribute-order-restricted.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// aux-build:test-macros.rs
-
-#[macro_use]
-extern crate test_macros;
-
-#[identity_attr] // OK
-#[derive(Clone)]
-struct Before;
-
-#[derive(Clone)]
-#[identity_attr] //~ ERROR macro attributes must be placed before `#[derive]`
-struct After;
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/attribute-order-restricted.stderr b/src/test/ui/proc-macro/attribute-order-restricted.stderr
deleted file mode 100644
index 9ca8a443e40..00000000000
--- a/src/test/ui/proc-macro/attribute-order-restricted.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: macro attributes must be placed before `#[derive]`
-  --> $DIR/attribute-order-restricted.rs:11:1
-   |
-LL | #[identity_attr]
-   | ^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs
index 6147e96a74b..80d982d2504 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.rs
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs
@@ -17,6 +17,8 @@ macro_rules! gen_helper_use {
 }
 
 #[empty_helper] //~ ERROR `empty_helper` is ambiguous
+                //~| WARN derive helper attribute is used before it is introduced
+                //~| WARN this was previously accepted
 #[derive(Empty)]
 struct S {
     #[empty_helper] // OK, no ambiguity, derive helpers have highest priority
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
index f82f49aa775..a49df9f2d4a 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
@@ -1,17 +1,17 @@
 error: cannot use a derive helper attribute through an import
-  --> $DIR/derive-helper-shadowing.rs:40:15
+  --> $DIR/derive-helper-shadowing.rs:42:15
    |
 LL |             #[renamed]
    |               ^^^^^^^
    |
 note: the derive helper attribute imported here
-  --> $DIR/derive-helper-shadowing.rs:39:17
+  --> $DIR/derive-helper-shadowing.rs:41:17
    |
 LL |             use empty_helper as renamed;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `empty_helper` in this scope
-  --> $DIR/derive-helper-shadowing.rs:36:22
+  --> $DIR/derive-helper-shadowing.rs:38:22
    |
 LL |             #[derive(GenHelperUse)]
    |                      ^^^^^^^^^^^^
@@ -30,13 +30,13 @@ LL |             gen_helper_use!();
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
-  --> $DIR/derive-helper-shadowing.rs:24:13
+  --> $DIR/derive-helper-shadowing.rs:26:13
    |
 LL |         use empty_helper;
    |             ^^^^^^^^^^^^ ambiguous name
    |
 note: `empty_helper` could refer to the derive helper attribute defined here
-  --> $DIR/derive-helper-shadowing.rs:20:10
+  --> $DIR/derive-helper-shadowing.rs:22:10
    |
 LL | #[derive(Empty)]
    |          ^^^^^
@@ -54,7 +54,7 @@ LL | #[empty_helper]
    |   ^^^^^^^^^^^^ ambiguous name
    |
 note: `empty_helper` could refer to the derive helper attribute defined here
-  --> $DIR/derive-helper-shadowing.rs:20:10
+  --> $DIR/derive-helper-shadowing.rs:22:10
    |
 LL | #[derive(Empty)]
    |          ^^^^^
@@ -65,6 +65,19 @@ LL | use test_macros::empty_attr as empty_helper;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
 
-error: aborting due to 5 previous errors
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/derive-helper-shadowing.rs:19:3
+   |
+LL | #[empty_helper]
+   |   ^^^^^^^^^^^^
+...
+LL | #[derive(Empty)]
+   |          ----- the attribute is introduced here
+   |
+   = note: `#[warn(legacy_derive_helpers)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+error: aborting due to 5 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/proc-macro/derive-helper-vs-legacy.rs b/src/test/ui/proc-macro/derive-helper-vs-legacy.rs
new file mode 100644
index 00000000000..98836bcb893
--- /dev/null
+++ b/src/test/ui/proc-macro/derive-helper-vs-legacy.rs
@@ -0,0 +1,12 @@
+// check-pass
+// aux-build:test-macros.rs
+
+#[macro_use]
+extern crate test_macros;
+
+#[derive(Empty)]
+#[empty_helper] // OK, this is both derive helper and legacy derive helper
+#[derive(Empty)]
+struct S;
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/derive-multiple-with-packed.rs b/src/test/ui/proc-macro/derive-multiple-with-packed.rs
new file mode 100644
index 00000000000..23578aa0e9f
--- /dev/null
+++ b/src/test/ui/proc-macro/derive-multiple-with-packed.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#[derive(Clone, Copy)]
+#[derive(Debug)] // OK, even if `Copy` is in the different `#[derive]`
+#[derive(PartialEq)] // OK too
+#[repr(packed)]
+struct CacheRecordHeader {
+    field: u64,
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs
index 3a1c56efce8..40c42d82f68 100644
--- a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs
+++ b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.rs
@@ -4,8 +4,10 @@
 extern crate test_macros;
 use test_macros::empty_attr as empty_helper;
 
-#[derive(Empty)]
 #[empty_helper] //~ ERROR `empty_helper` is ambiguous
+                //~| WARN derive helper attribute is used before it is introduced
+                //~| WARN this was previously accepted
+#[derive(Empty)]
 struct S;
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
index 012fb105b12..ceb6d789785 100644
--- a/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
+++ b/src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
@@ -1,11 +1,11 @@
 error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/helper-attr-blocked-by-import-ambig.rs:8:3
+  --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
    |
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^ ambiguous name
    |
 note: `empty_helper` could refer to the derive helper attribute defined here
-  --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:10
+  --> $DIR/helper-attr-blocked-by-import-ambig.rs:10:10
    |
 LL | #[derive(Empty)]
    |          ^^^^^
@@ -16,6 +16,19 @@ LL | use test_macros::empty_attr as empty_helper;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
 
-error: aborting due to previous error
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
+   |
+LL | #[empty_helper]
+   |   ^^^^^^^^^^^^
+...
+LL | #[derive(Empty)]
+   |          ----- the attribute is introduced here
+   |
+   = note: `#[warn(legacy_derive_helpers)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs
index a051d23bac0..649e7318403 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs
@@ -13,7 +13,8 @@
 #[macro_use]
 extern crate test_macros;
 
-#[print_helper(a)]
+#[print_helper(a)] //~ WARN derive helper attribute is used before it is introduced
+                   //~| WARN this was previously accepted
 #[cfg_attr(not(FALSE), allow(dead_code))]
 #[print_attr]
 #[derive(Print)]
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
new file mode 100644
index 00000000000..5227da7d766
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
@@ -0,0 +1,15 @@
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/issue-75930-derive-cfg.rs:16:3
+   |
+LL | #[print_helper(a)]
+   |   ^^^^^^^^^^^^
+...
+LL | #[derive(Print)]
+   |          ----- the attribute is introduced here
+   |
+   = note: `#[warn(legacy_derive_helpers)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
index 5f513684cfa..19aa4dfb60e 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -26,77 +26,77 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:17:1: 17:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:18:1: 18:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "allow",
-                span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:29 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:18:24: 18:29 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "dead_code",
-                        span: $DIR/issue-75930-derive-cfg.rs:17:30: 17:39 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:18:30: 18:39 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:17:29: 17:40 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:18:29: 18:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:17:1: 17:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:18:1: 18:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "derive",
-                span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:9 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:20:3: 20:9 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "Print",
-                        span: $DIR/issue-75930-derive-cfg.rs:19:10: 19:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:20:10: 20:15 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:19:9: 19:16 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:20:9: 20:16 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:17 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:20:2: 20:17 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:20:3: 20:15 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:21:3: 21:15 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "b",
-                        span: $DIR/issue-75930-derive-cfg.rs:20:16: 20:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:21:16: 21:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:20:15: 20:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:21:15: 21:18 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:20:2: 20:19 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:21:2: 21:19 (#0),
     },
     Punct {
         ch: '#',
@@ -125,59 +125,59 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     },
     Ident {
         ident: "struct",
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:7 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 22:7 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/issue-75930-derive-cfg.rs:21:8: 21:11 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:8: 22:11 (#0),
     },
     Punct {
         ch: '<',
         spacing: Joint,
-        span: $DIR/issue-75930-derive-cfg.rs:21:11: 21:12 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:11: 22:12 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:12: 21:13 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:12: 22:13 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "cfg",
-                span: $DIR/issue-75930-derive-cfg.rs:21:14: 21:17 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:14: 22:17 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "FALSE",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:18: 21:23 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:18: 22:23 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:17: 21:24 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:17: 22:24 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:13: 21:25 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:13: 22:25 (#0),
     },
     Ident {
         ident: "A",
-        span: $DIR/issue-75930-derive-cfg.rs:21:26: 21:27 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:26: 22:27 (#0),
     },
     Punct {
         ch: ',',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:27: 21:28 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:27: 22:28 (#0),
     },
     Ident {
         ident: "B",
-        span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:30 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:29: 22:30 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:31 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:30: 22:31 (#0),
     },
     Group {
         delimiter: Brace,
@@ -185,128 +185,128 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:22:5: 22:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:5: 23:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg",
-                        span: $DIR/issue-75930-derive-cfg.rs:22:7: 22:10 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:23:7: 23:10 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "FALSE",
-                                span: $DIR/issue-75930-derive-cfg.rs:22:11: 22:16 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:23:11: 23:16 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:22:10: 22:17 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:23:10: 23:17 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:22:6: 22:18 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:6: 23:18 (#0),
             },
             Ident {
                 ident: "first",
-                span: $DIR/issue-75930-derive-cfg.rs:22:19: 22:24 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:19: 23:24 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:22:24: 22:25 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:24: 23:25 (#0),
             },
             Ident {
                 ident: "String",
-                span: $DIR/issue-75930-derive-cfg.rs:22:26: 22:32 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:26: 23:32 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:22:32: 22:33 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:23:32: 23:33 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:23:5: 23:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:5: 24:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg_attr",
-                        span: $DIR/issue-75930-derive-cfg.rs:23:7: 23:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:24:7: 24:15 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "FALSE",
-                                span: $DIR/issue-75930-derive-cfg.rs:23:16: 23:21 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:21 (#0),
                             },
                             Punct {
                                 ch: ',',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:23:21: 23:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:24:21: 24:22 (#0),
                             },
                             Ident {
                                 ident: "deny",
-                                span: $DIR/issue-75930-derive-cfg.rs:23:23: 23:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:24:23: 24:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "warnings",
-                                        span: $DIR/issue-75930-derive-cfg.rs:23:28: 23:36 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:24:28: 24:36 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:23:27: 23:37 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:24:27: 24:37 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:23:15: 23:38 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:38 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:23:6: 23:39 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:6: 24:39 (#0),
             },
             Ident {
                 ident: "second",
-                span: $DIR/issue-75930-derive-cfg.rs:23:40: 23:46 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:40: 24:46 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:23:46: 23:47 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:46: 24:47 (#0),
             },
             Ident {
                 ident: "bool",
-                span: $DIR/issue-75930-derive-cfg.rs:23:48: 23:52 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:48: 24:52 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:23:52: 23:53 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:24:52: 24:53 (#0),
             },
             Ident {
                 ident: "third",
-                span: $DIR/issue-75930-derive-cfg.rs:24:5: 24:10 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:25:5: 25:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:24:10: 24:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:25:10: 25:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/issue-75930-derive-cfg.rs:24:13: 24:15 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:25:13: 25:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:16 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:25:15: 25:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
@@ -314,145 +314,145 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:9: 25:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:26:9: 26:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/issue-75930-derive-cfg.rs:25:15: 25:20 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:26:15: 26:20 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:21 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:26:14: 26:21 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:25:10: 25:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:22 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:23: 25:29 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:26:23: 26:29 (#0),
                             },
                             Ident {
                                 ident: "Bar",
-                                span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:33 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:26:30: 26:33 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:25:33: 25:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:26:33: 26:34 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:26:9: 26:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:27:9: 27:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:27:11: 27:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:26:15: 26:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:27:19: 27:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:26:18: 26:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:27:18: 27:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:26:14: 26:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:27:14: 27:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:27:10: 27:27 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:26:28: 26:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:27:28: 27:34 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/issue-75930-derive-cfg.rs:26:35: 26:40 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:27:35: 27:40 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:26:40: 26:41 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:41 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:27:9: 27:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:9: 28:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:27:11: 27:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:28:11: 28:14 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:20 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:20 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:27:14: 27:21 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:28:14: 28:21 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:27:10: 27:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:22 (#0),
                             },
                             Ident {
                                 ident: "let",
-                                span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:26 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:23: 28:26 (#0),
                             },
                             Ident {
                                 ident: "a",
-                                span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:28 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:27: 28:28 (#0),
                             },
                             Punct {
                                 ch: '=',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:27:29: 27:30 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:29: 28:30 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "25",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:27:31: 27:33 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:31: 28:33 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:27:33: 27:34 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:28:33: 28:34 (#0),
                             },
                             Ident {
                                 ident: "match",
-                                span: $DIR/issue-75930-derive-cfg.rs:28:9: 28:14 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:29:9: 29:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:19 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -460,194 +460,194 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:13: 29:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:13: 30:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:29:19: 29:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:29:18: 29:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:27: 29:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:27: 30:31 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:32: 30:34 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:32: 30:34 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:35: 29:37 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:37 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:29:37: 29:38 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:30:37: 30:38 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:13: 30:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:13: 31:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg_attr",
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:23 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:23 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:24: 30:27 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:31:24: 31:27 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:33 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:31:28: 31:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:27: 30:34 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:31:27: 31:34 (#0),
                                                     },
                                                     Punct {
                                                         ch: ',',
                                                         spacing: Alone,
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:34: 30:35 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:31:34: 31:35 (#0),
                                                     },
                                                     Ident {
                                                         ident: "allow",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:36: 30:41 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:31:36: 31:41 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "warnings",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:30:42: 30:50 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:31:42: 31:50 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:30:41: 30:51 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:31:41: 31:51 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:30:23: 30:52 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:31:23: 31:52 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:53 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:14: 31:53 (#0),
                                     },
                                     Ident {
                                         ident: "false",
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:54: 30:59 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:54: 31:59 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:60: 31:62 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:60: 31:62 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:63: 30:65 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:63: 31:65 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:30:65: 30:66 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:31:65: 31:66 (#0),
                                     },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:13: 31:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:32:13: 32:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:17 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:31:18: 31:20 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:32:18: 32:20 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:28:20: 32:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:29:20: 33:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:32:10: 32:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:33:10: 33:11 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:34:9: 34:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:35:9: 35:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:11: 34:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:11: 35:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "should_be_removed",
-                                                span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:35:24: 35:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:42 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:35:23: 35:42 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:34:10: 34:43 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:35:10: 35:43 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:35:9: 35:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:36:9: 36:11 (#0),
                             },
                             Ident {
                                 ident: "removed_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:35:12: 35:22 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:36:12: 36:22 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:35:22: 35:24 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:36:22: 36:24 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -655,108 +655,108 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:36:13: 36:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:37:13: 37:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:36:14: 36:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:37:14: 37:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:36:16: 36:19 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:37:16: 37:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:36:20: 36:25 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:37:20: 37:25 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:36:19: 36:26 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:37:19: 37:26 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:36:15: 36:27 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:37:15: 37:27 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:35:25: 37:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:36:25: 38:10 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:9: 40:10 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:39:11: 39:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:40:11: 40:23 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "c",
-                                                span: $DIR/issue-75930-derive-cfg.rs:39:24: 39:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:40:24: 40:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:39:23: 39:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:40:23: 40:26 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:10: 39:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:10: 40:27 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:39:28: 39:29 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:28: 40:29 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:39:30: 39:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:40:30: 40:33 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:39:34: 39:37 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:40:34: 40:37 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:39:38: 39:43 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:40:38: 40:43 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:39:37: 39:44 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:40:37: 40:44 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:39:33: 39:45 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:40:33: 40:45 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:29: 39:46 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:29: 40:46 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:39:47: 39:49 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:47: 40:49 (#0),
                             },
                             Ident {
                                 ident: "kept_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:39:50: 39:57 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:50: 40:57 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:57: 39:59 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:57: 40:59 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -764,82 +764,82 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:41:13: 41:14 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:41:14: 41:15 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:41:16: 41:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:23 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:41:20: 41:23 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:40:24: 40:29 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:41:24: 41:29 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:40:23: 40:30 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:41:23: 41:30 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:31 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:41:19: 41:31 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:32 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:41:15: 41:32 (#0),
                                     },
                                     Ident {
                                         ident: "let",
-                                        span: $DIR/issue-75930-derive-cfg.rs:41:13: 41:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:42:13: 42:16 (#0),
                                     },
                                     Ident {
                                         ident: "my_val",
-                                        span: $DIR/issue-75930-derive-cfg.rs:41:17: 41:23 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:42:17: 42:23 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:41:24: 41:25 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:42:24: 42:25 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:41:26: 41:30 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:42:26: 42:30 (#0),
                                     },
                                     Punct {
                                         ch: ';',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:41:30: 41:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:42:30: 42:31 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:39:60: 42:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:40:60: 43:10 (#0),
                             },
                             Ident {
                                 ident: "enum",
-                                span: $DIR/issue-75930-derive-cfg.rs:44:9: 44:13 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:45:9: 45:13 (#0),
                             },
                             Ident {
                                 ident: "TupleEnum",
-                                span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:23 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:45:14: 45:23 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "Foo",
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:46:13: 46:16 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
@@ -847,166 +847,166 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:46:17: 46:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:47:17: 47:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:46:19: 46:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:47:19: 47:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:46:23: 46:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:47:23: 47:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:46:22: 46:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:47:22: 47:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:46:18: 46:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:47:18: 47:30 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:46:31: 46:33 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:47:31: 47:33 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:46:33: 46:34 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:47:33: 47:34 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:47:17: 47:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:48:17: 48:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:47:19: 47:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:48:19: 48:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:47:23: 47:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:48:23: 48:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:47:22: 47:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:48:22: 48:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:47:18: 47:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:48:18: 48:30 (#0),
                                             },
                                             Ident {
                                                 ident: "bool",
-                                                span: $DIR/issue-75930-derive-cfg.rs:47:31: 47:35 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:48:31: 48:35 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:47:35: 47:36 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:48:35: 48:36 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:48:17: 48:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:49:17: 49:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:48:19: 48:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:49:19: 49:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "not",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:48:23: 48:26 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:49:23: 49:26 (#0),
                                                             },
                                                             Group {
                                                                 delimiter: Parenthesis,
                                                                 stream: TokenStream [
                                                                     Ident {
                                                                         ident: "FALSE",
-                                                                        span: $DIR/issue-75930-derive-cfg.rs:48:27: 48:32 (#0),
+                                                                        span: $DIR/issue-75930-derive-cfg.rs:49:27: 49:32 (#0),
                                                                     },
                                                                 ],
-                                                                span: $DIR/issue-75930-derive-cfg.rs:48:26: 48:33 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:49:26: 49:33 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:48:22: 48:34 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:49:22: 49:34 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:48:18: 48:35 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:49:18: 49:35 (#0),
                                             },
                                             Ident {
                                                 ident: "i32",
-                                                span: $DIR/issue-75930-derive-cfg.rs:48:36: 48:39 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:49:36: 49:39 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:48:39: 48:40 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:49:39: 49:40 (#0),
                                             },
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:49:17: 49:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:50:17: 50:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:49:19: 49:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:50:19: 50:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:49:23: 49:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:50:23: 50:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:49:22: 49:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:50:22: 50:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:49:18: 49:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:50:18: 50:30 (#0),
                                             },
                                             Ident {
                                                 ident: "String",
-                                                span: $DIR/issue-75930-derive-cfg.rs:49:31: 49:37 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:50:31: 50:37 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:49:37: 49:38 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:50:37: 50:38 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:49:39: 49:41 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:50:39: 50:41 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:45:16: 50:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:46:16: 51:14 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:44:24: 51:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:45:24: 52:10 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:15 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:54:9: 54:15 (#0),
                             },
                             Ident {
                                 ident: "TupleStruct",
-                                span: $DIR/issue-75930-derive-cfg.rs:53:16: 53:27 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:27 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
@@ -1014,184 +1014,184 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:54:13: 54:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:55:15: 55:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:54:19: 54:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:55:19: 55:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:54:14: 54:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:26 (#0),
                                     },
                                     Ident {
                                         ident: "String",
-                                        span: $DIR/issue-75930-derive-cfg.rs:54:27: 54:33 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:55:27: 55:33 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:54:33: 54:34 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:55:33: 55:34 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:56:13: 56:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:55:15: 55:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:56:15: 56:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:55:19: 55:22 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:22 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:55:23: 55:28 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:56:23: 56:28 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:55:22: 55:29 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:56:22: 56:29 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:30 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:56:18: 56:30 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:56:14: 56:31 (#0),
                                     },
                                     Ident {
                                         ident: "i32",
-                                        span: $DIR/issue-75930-derive-cfg.rs:55:32: 55:35 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:56:32: 56:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:55:35: 55:36 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:56:35: 56:36 (#0),
                                     },
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:56:13: 56:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:57:13: 57:14 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:56:15: 56:18 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:57:15: 57:18 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:57:19: 57:24 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:56:18: 56:25 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:57:18: 57:25 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:56:14: 56:26 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:57:14: 57:26 (#0),
                                     },
                                     Ident {
                                         ident: "bool",
-                                        span: $DIR/issue-75930-derive-cfg.rs:56:27: 56:31 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:57:27: 57:31 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:56:31: 56:32 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:57:31: 57:32 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/issue-75930-derive-cfg.rs:57:13: 57:15 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:53:27: 58:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:54:27: 59:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:59:10: 59:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:61:9: 61:10 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:24:17: 61:6 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:25:17: 62:6 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:24:12: 61:7 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:25:12: 62:7 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:61:7: 61:8 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:62:7: 62:8 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:62:5: 62:6 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:63:5: 63:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_helper",
-                        span: $DIR/issue-75930-derive-cfg.rs:62:7: 62:19 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:63:7: 63:19 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "d",
-                                span: $DIR/issue-75930-derive-cfg.rs:62:20: 62:21 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:63:20: 63:21 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:22 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:63:19: 63:22 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:62:6: 62:23 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:63:6: 63:23 (#0),
             },
             Ident {
                 ident: "fourth",
-                span: $DIR/issue-75930-derive-cfg.rs:63:5: 63:11 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:64:5: 64:11 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:63:11: 63:12 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:64:11: 64:12 (#0),
             },
             Ident {
                 ident: "B",
-                span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:32: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:32: 65:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_helper(a)] struct Foo < B >
@@ -1211,141 +1211,141 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "allow",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "dead_code",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "b",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_helper",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "a",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Ident {
         ident: "Foo",
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Punct {
         ch: '<',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Ident {
         ident: "B",
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Punct {
         ch: '>',
         spacing: Alone,
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "second",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Ident {
                 ident: "bool",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Ident {
                 ident: "third",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                     Group {
                         delimiter: Brace,
@@ -1353,58 +1353,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "Inner",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "match",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1412,146 +1412,146 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "allow",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "warnings",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "false",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
                                         stream: TokenStream [],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "print_helper",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "c",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Punct {
                                 ch: '#',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Bracket,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "cfg",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "not",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "FALSE",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "kept_fn",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -1559,82 +1559,82 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Joint,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '!',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "let",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "my_val",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "true",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: ';',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "enum",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "TupleEnum",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "Foo",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
@@ -1642,69 +1642,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "cfg",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "not",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                             },
                                                             Group {
                                                                 delimiter: Parenthesis,
                                                                 stream: TokenStream [
                                                                     Ident {
                                                                         ident: "FALSE",
-                                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                                     },
                                                                 ],
-                                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Ident {
                                                 ident: "i32",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Punct {
                                                 ch: ',',
                                                 spacing: Alone,
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Ident {
                                                 ident: "u8",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "struct",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Ident {
                                 ident: "TupleStruct",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
@@ -1712,120 +1712,120 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                     Punct {
                                         ch: '#',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Group {
                                         delimiter: Bracket,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "cfg",
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                             Group {
                                                 delimiter: Parenthesis,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "not",
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "FALSE",
-                                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "i32",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                     Ident {
                                         ident: "u8",
-                                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                                     },
                                 ],
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_helper",
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "d",
-                                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                             },
                         ],
-                        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
                     },
                 ],
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Ident {
                 ident: "fourth",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Ident {
                 ident: "B",
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+                span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:21:1: 64:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.rs b/src/test/ui/proc-macro/proc-macro-attributes.rs
index 6401522bdf8..8d96381b9bd 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.rs
+++ b/src/test/ui/proc-macro/proc-macro-attributes.rs
@@ -4,10 +4,18 @@
 extern crate derive_b;
 
 #[B] //~ ERROR `B` is ambiguous
+     //~| WARN derive helper attribute is used before it is introduced
+     //~| WARN this was previously accepted
 #[C] //~ ERROR cannot find attribute `C` in this scope
 #[B(D)] //~ ERROR `B` is ambiguous
+        //~| WARN derive helper attribute is used before it is introduced
+        //~| WARN this was previously accepted
 #[B(E = "foo")] //~ ERROR `B` is ambiguous
+                //~| WARN derive helper attribute is used before it is introduced
+                //~| WARN this was previously accepted
 #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
+                       //~| WARN derive helper attribute is used before it is introduced
+                       //~| WARN this was previously accepted
 #[derive(B)]
 struct B;
 
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr
index 3ac93a74852..1ba04258df0 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.stderr
+++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr
@@ -1,5 +1,5 @@
 error: cannot find attribute `C` in this scope
-  --> $DIR/proc-macro-attributes.rs:7:3
+  --> $DIR/proc-macro-attributes.rs:9:3
    |
 LL | #[C]
    |   ^ help: a derive helper attribute with a similar name exists: `B`
@@ -11,7 +11,7 @@ LL | #[B]
    |   ^ ambiguous name
    |
 note: `B` could refer to the derive helper attribute defined here
-  --> $DIR/proc-macro-attributes.rs:11:10
+  --> $DIR/proc-macro-attributes.rs:19:10
    |
 LL | #[derive(B)]
    |          ^
@@ -22,13 +22,13 @@ LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/proc-macro-attributes.rs:8:3
+  --> $DIR/proc-macro-attributes.rs:10:3
    |
 LL | #[B(D)]
    |   ^ ambiguous name
    |
 note: `B` could refer to the derive helper attribute defined here
-  --> $DIR/proc-macro-attributes.rs:11:10
+  --> $DIR/proc-macro-attributes.rs:19:10
    |
 LL | #[derive(B)]
    |          ^
@@ -39,13 +39,13 @@ LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/proc-macro-attributes.rs:9:3
+  --> $DIR/proc-macro-attributes.rs:13:3
    |
 LL | #[B(E = "foo")]
    |   ^ ambiguous name
    |
 note: `B` could refer to the derive helper attribute defined here
-  --> $DIR/proc-macro-attributes.rs:11:10
+  --> $DIR/proc-macro-attributes.rs:19:10
    |
 LL | #[derive(B)]
    |          ^
@@ -56,13 +56,13 @@ LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/proc-macro-attributes.rs:10:3
+  --> $DIR/proc-macro-attributes.rs:16:3
    |
 LL | #[B(arbitrary tokens)]
    |   ^ ambiguous name
    |
 note: `B` could refer to the derive helper attribute defined here
-  --> $DIR/proc-macro-attributes.rs:11:10
+  --> $DIR/proc-macro-attributes.rs:19:10
    |
 LL | #[derive(B)]
    |          ^
@@ -72,6 +72,55 @@ note: `B` could also refer to the derive macro imported here
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/proc-macro-attributes.rs:6:3
+   |
+LL | #[B]
+   |   ^
+...
+LL | #[derive(B)]
+   |          - the attribute is introduced here
+   |
+   = note: `#[warn(legacy_derive_helpers)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/proc-macro-attributes.rs:10:3
+   |
+LL | #[B(D)]
+   |   ^
+...
+LL | #[derive(B)]
+   |          - the attribute is introduced here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/proc-macro-attributes.rs:13:3
+   |
+LL | #[B(E = "foo")]
+   |   ^
+...
+LL | #[derive(B)]
+   |          - the attribute is introduced here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/proc-macro-attributes.rs:16:3
+   |
+LL | #[B(arbitrary tokens)]
+   |   ^
+...
+LL | #[derive(B)]
+   |          - the attribute is introduced here
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+error: aborting due to 5 previous errors; 4 warnings emitted
 
 For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/proc-macro/reserved-macro-names.rs b/src/test/ui/proc-macro/reserved-macro-names.rs
index 9f56eccb7a6..c5e71a87dfb 100644
--- a/src/test/ui/proc-macro/reserved-macro-names.rs
+++ b/src/test/ui/proc-macro/reserved-macro-names.rs
@@ -17,9 +17,3 @@ pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
     //~^ ERROR name `cfg_attr` is reserved in attribute namespace
     input
 }
-
-#[proc_macro_attribute]
-pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
-    //~^ ERROR name `derive` is reserved in attribute namespace
-    input
-}
diff --git a/src/test/ui/proc-macro/reserved-macro-names.stderr b/src/test/ui/proc-macro/reserved-macro-names.stderr
index f871e43ce51..39bdd03be86 100644
--- a/src/test/ui/proc-macro/reserved-macro-names.stderr
+++ b/src/test/ui/proc-macro/reserved-macro-names.stderr
@@ -10,11 +10,5 @@ error: name `cfg_attr` is reserved in attribute namespace
 LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
    |        ^^^^^^^^
 
-error: name `derive` is reserved in attribute namespace
-  --> $DIR/reserved-macro-names.rs:22:8
-   |
-LL | pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
-   |        ^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
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 8f1599a5abc..840c12e16e1 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.rs
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.rs
@@ -1,10 +1,5 @@
-#![allow(dead_code)]
-
 #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
-//~^ ERROR `derive` may only be applied to structs, enums and unions
-//~| 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 attribute macro `derive`
 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 85beac535c9..9ef81c5150a 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
@@ -1,33 +1,10 @@
-error[E0774]: `derive` may only be applied to structs, enums and unions
-  --> $DIR/issue-43927-non-ADT-derive.rs:3:1
+error: cannot determine resolution for the attribute macro `derive`
+  --> $DIR/issue-43927-non-ADT-derive.rs:1:4
    |
 LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug, PartialEq, Eq)]`
-
-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: 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 `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: aborting due to 4 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0774`.
diff --git a/src/test/ui/span/macro-ty-params.rs b/src/test/ui/span/macro-ty-params.rs
index 713b9eb542c..0a93105b664 100644
--- a/src/test/ui/span/macro-ty-params.rs
+++ b/src/test/ui/span/macro-ty-params.rs
@@ -9,5 +9,5 @@ macro_rules! foo { () => () }
 fn main() {
     foo::<T>!(); //~ ERROR generic arguments in macro path
     foo::<>!(); //~ ERROR generic arguments in macro path
-    m!(Default<>); //~ ERROR generic arguments in macro path
+    m!(Default<>); //~ ERROR unexpected generic arguments in path
 }
diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr
index 21683b2fb86..138cd2598a1 100644
--- a/src/test/ui/span/macro-ty-params.stderr
+++ b/src/test/ui/span/macro-ty-params.stderr
@@ -10,7 +10,7 @@ error: generic arguments in macro path
 LL |     foo::<>!();
    |          ^^
 
-error: generic arguments in macro path
+error: unexpected generic arguments in path
   --> $DIR/macro-ty-params.rs:12:15
    |
 LL |     m!(Default<>);