about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs12
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs139
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs28
-rw-r--r--compiler/rustc_expand/messages.ftl27
-rw-r--r--compiler/rustc_expand/src/base.rs100
-rw-r--r--compiler/rustc_expand/src/errors.rs66
-rw-r--r--compiler/rustc_hir/src/hir.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs5
-rw-r--r--compiler/rustc_passes/src/check_attr.rs27
-rw-r--r--src/librustdoc/clean/mod.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr45
-rw-r--r--tests/ui/attributes/unsafe/proc-unsafe-attributes.rs1
-rw-r--r--tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr36
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs2
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr12
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs14
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr24
-rw-r--r--tests/ui/proc-macro/attribute.rs51
-rw-r--r--tests/ui/proc-macro/attribute.stderr152
-rw-r--r--tests/ui/proc-macro/invalid-attributes.rs24
-rw-r--r--tests/ui/proc-macro/invalid-attributes.stderr53
26 files changed, 520 insertions, 393 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 1e2576bef2c..610c93a253c 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -416,12 +416,24 @@ pub enum AttributeKind {
     /// Represents `#[pointee]`
     Pointee(Span),
 
+    /// Represents `#[proc_macro]`
+    ProcMacro(Span),
+
+    /// Represents `#[proc_macro_attribute]`
+    ProcMacroAttribute(Span),
+
+    /// Represents `#[proc_macro_derive]`
+    ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
+
     /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
     PubTransparent(Span),
 
     /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
 
+    /// Represents `#[rustc_builtin_macro]`.
+    RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
+
     /// Represents `#[rustc_layout_scalar_valid_range_end]`.
     RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 159b807a3b2..af2d46d0bc7 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -61,8 +61,12 @@ impl AttributeKind {
             PassByValue(..) => Yes,
             Path(..) => No,
             Pointee(..) => No,
+            ProcMacro(..) => No,
+            ProcMacroAttribute(..) => No,
+            ProcMacroDerive { .. } => No,
             PubTransparent(..) => Yes,
             Repr { .. } => No,
+            RustcBuiltinMacro { .. } => Yes,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 15b90bd2ed7..0c10517d044 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -41,6 +41,7 @@ pub(crate) mod must_use;
 pub(crate) mod no_implicit_prelude;
 pub(crate) mod non_exhaustive;
 pub(crate) mod path;
+pub(crate) mod proc_macro_attrs;
 pub(crate) mod repr;
 pub(crate) mod rustc_internal;
 pub(crate) mod semantics;
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
new file mode 100644
index 00000000000..4de77dc268e
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -0,0 +1,139 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
+
+use crate::attributes::{
+    AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
+};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct ProcMacroParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
+    const PATH: &[Symbol] = &[sym::proc_macro];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
+}
+
+pub(crate) struct ProcMacroAttributeParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
+    const PATH: &[Symbol] = &[sym::proc_macro_attribute];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
+}
+
+pub(crate) struct ProcMacroDeriveParser;
+impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
+    const PATH: &[Symbol] = &[sym::proc_macro_derive];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate =
+        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
+        Some(AttributeKind::ProcMacroDerive {
+            trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
+            helper_attrs,
+            span: cx.attr_span,
+        })
+    }
+}
+
+pub(crate) struct RustcBuiltinMacroParser;
+impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
+    const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate =
+        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
+        Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
+    }
+}
+
+fn parse_derive_like<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    args: &ArgParser<'_>,
+    trait_name_mandatory: bool,
+) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
+    let Some(list) = args.list() else {
+        // For #[rustc_builtin_macro], it is permitted to leave out the trait name
+        if args.no_args().is_ok() && !trait_name_mandatory {
+            return Some((None, ThinVec::new()));
+        }
+        cx.expected_list(cx.attr_span);
+        return None;
+    };
+    let mut items = list.mixed();
+
+    // Parse the name of the trait that is derived.
+    let Some(trait_attr) = items.next() else {
+        cx.expected_at_least_one_argument(list.span);
+        return None;
+    };
+    let Some(trait_attr) = trait_attr.meta_item() else {
+        cx.unexpected_literal(trait_attr.span());
+        return None;
+    };
+    let Some(trait_ident) = trait_attr.path().word() else {
+        cx.expected_identifier(trait_attr.path().span());
+        return None;
+    };
+    if !trait_ident.name.can_be_raw() {
+        cx.expected_identifier(trait_ident.span);
+        return None;
+    }
+    if let Err(e) = trait_attr.args().no_args() {
+        cx.expected_no_args(e);
+        return None;
+    };
+
+    // Parse optional attributes
+    let mut attributes = ThinVec::new();
+    if let Some(attrs) = items.next() {
+        let Some(attr_list) = attrs.meta_item() else {
+            cx.expected_list(attrs.span());
+            return None;
+        };
+        if !attr_list.path().word_is(sym::attributes) {
+            cx.expected_specific_argument(attrs.span(), vec!["attributes"]);
+            return None;
+        }
+        let Some(attr_list) = attr_list.args().list() else {
+            cx.expected_list(attrs.span());
+            return None;
+        };
+
+        // Parse item in `attributes(...)` argument
+        for attr in attr_list.mixed() {
+            let Some(attr) = attr.meta_item() else {
+                cx.expected_identifier(attr.span());
+                return None;
+            };
+            if let Err(e) = attr.args().no_args() {
+                cx.expected_no_args(e);
+                return None;
+            };
+            let Some(ident) = attr.path().word() else {
+                cx.expected_identifier(attr.path().span());
+                return None;
+            };
+            if !ident.name.can_be_raw() {
+                cx.expected_identifier(ident.span);
+                return None;
+            }
+            attributes.push(ident.name);
+        }
+    }
+
+    // If anything else is specified, we should reject it
+    if let Some(next) = items.next() {
+        cx.expected_no_args(next.span());
+    }
+
+    Some((Some(trait_ident.name), attributes))
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 45bfe345207..9b86d101840 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -38,6 +38,9 @@ use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
 use crate::attributes::non_exhaustive::NonExhaustiveParser;
 use crate::attributes::path::PathParser as PathAttributeParser;
+use crate::attributes::proc_macro_attrs::{
+    ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
+};
 use crate::attributes::repr::{AlignParser, ReprParser};
 use crate::attributes::rustc_internal::{
     RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -154,6 +157,8 @@ attribute_parsers!(
         Single<MustUseParser>,
         Single<OptimizeParser>,
         Single<PathAttributeParser>,
+        Single<ProcMacroDeriveParser>,
+        Single<RustcBuiltinMacroParser>,
         Single<RustcForceInlineParser>,
         Single<RustcLayoutScalarValidRangeEnd>,
         Single<RustcLayoutScalarValidRangeStart>,
@@ -186,6 +191,8 @@ attribute_parsers!(
         Single<WithoutArgs<ParenSugarParser>>,
         Single<WithoutArgs<PassByValueParser>>,
         Single<WithoutArgs<PointeeParser>>,
+        Single<WithoutArgs<ProcMacroAttributeParser>>,
+        Single<WithoutArgs<ProcMacroParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
         Single<WithoutArgs<SpecializationTraitParser>>,
         Single<WithoutArgs<StdInternalSymbolParser>>,
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 42b7e0e06d1..09f5e6f6efc 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -1,11 +1,13 @@
-use std::mem;
+use std::{mem, slice};
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, NodeId, attr};
+use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
 use rustc_ast_pretty::pprust;
+use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_parsing::AttributeParser;
 use rustc_errors::DiagCtxtHandle;
-use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
 use rustc_session::Session;
@@ -22,7 +24,7 @@ struct ProcMacroDerive {
     trait_name: Symbol,
     function_ident: Ident,
     span: Span,
-    attrs: Vec<Symbol>,
+    attrs: ThinVec<Symbol>,
 }
 
 struct ProcMacroDef {
@@ -41,6 +43,7 @@ struct CollectProcMacros<'a> {
     macros: Vec<ProcMacro>,
     in_root: bool,
     dcx: DiagCtxtHandle<'a>,
+    session: &'a Session,
     source_map: &'a SourceMap,
     is_proc_macro_crate: bool,
     is_test_crate: bool,
@@ -63,6 +66,7 @@ pub fn inject(
         macros: Vec::new(),
         in_root: true,
         dcx,
+        session: sess,
         source_map: sess.source_map(),
         is_proc_macro_crate,
         is_test_crate,
@@ -98,8 +102,18 @@ impl<'a> CollectProcMacros<'a> {
         function_ident: Ident,
         attr: &'a ast::Attribute,
     ) {
-        let Some((trait_name, proc_attrs)) =
-            parse_macro_name_and_helper_attrs(self.dcx, attr, "derive")
+        let Some(rustc_hir::Attribute::Parsed(AttributeKind::ProcMacroDerive {
+            trait_name,
+            helper_attrs,
+            ..
+        })) = AttributeParser::parse_limited(
+            self.session,
+            slice::from_ref(attr),
+            sym::proc_macro_derive,
+            item.span,
+            item.node_id(),
+            None,
+        )
         else {
             return;
         };
@@ -110,7 +124,7 @@ impl<'a> CollectProcMacros<'a> {
                 span: item.span,
                 trait_name,
                 function_ident,
-                attrs: proc_attrs,
+                attrs: helper_attrs,
             }));
         } else {
             let msg = if !self.in_root {
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 89d6e62834d..5a53670c865 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -1,26 +1,8 @@
-expand_arg_not_attributes =
-    second argument must be `attributes`
-
-expand_attr_no_arguments =
-    attribute must have either one or two arguments
-
-expand_attribute_meta_item =
-    attribute must be a meta item, not a literal
-
-expand_attribute_single_word =
-    attribute must only be a single word
-
 expand_attributes_on_expressions_experimental =
     attributes on expressions are experimental
     .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
     .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
 
-expand_attributes_wrong_form =
-    attribute must be of form: `attributes(foo, bar)`
-
-expand_cannot_be_name_of_macro =
-    `{$trait_ident}` cannot be a name of {$macro_type} macro
-
 expand_collapse_debuginfo_illegal =
     illegal value for attribute #[collapse_debuginfo(no|external|yes)]
 
@@ -71,9 +53,6 @@ expand_glob_delegation_outside_impls =
 expand_glob_delegation_traitless_qpath =
     qualified path without a trait in glob delegation
 
-expand_helper_attribute_name_invalid =
-    `{$name}` cannot be a name of derive helper attribute
-
 expand_incomplete_parse =
     macro expansion ignores {$descr} and any tokens following
     .label = caused by the macro expansion here
@@ -165,12 +144,6 @@ expand_mve_unrecognized_var =
 expand_non_inline_modules_in_proc_macro_input_are_unstable =
     non-inline modules in proc macro input are unstable
 
-expand_not_a_meta_item =
-    not a meta item
-
-expand_only_one_word =
-    must only be one word
-
 expand_proc_macro_back_compat = using an old version of `{$crate_name}`
     .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 5a7883ccba6..c01320fc644 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -861,7 +861,7 @@ impl SyntaxExtension {
     /// | (unspecified) | no  | if-ext        | if-ext   | yes |
     /// | external      | no  | if-ext        | if-ext   | yes |
     /// | yes           | yes | yes           | yes      | yes |
-    fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool) -> bool {
+    fn get_collapse_debuginfo(sess: &Session, attrs: &[hir::Attribute], ext: bool) -> bool {
         let flag = sess.opts.cg.collapse_macro_debuginfo;
         let attr = ast::attr::find_by_name(attrs, sym::collapse_debuginfo)
             .and_then(|attr| {
@@ -872,7 +872,7 @@ impl SyntaxExtension {
                     .ok()
             })
             .unwrap_or_else(|| {
-                if ast::attr::contains_name(attrs, sym::rustc_builtin_macro) {
+                if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) {
                     CollapseMacroDebuginfo::Yes
                 } else {
                     CollapseMacroDebuginfo::Unspecified
@@ -915,16 +915,18 @@ impl SyntaxExtension {
         let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
         tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
 
-        let (builtin_name, helper_attrs) = ast::attr::find_by_name(attrs, sym::rustc_builtin_macro)
-            .map(|attr| {
-                // Override `helper_attrs` passed above if it's a built-in macro,
-                // marking `proc_macro_derive` macros as built-in is not a realistic use case.
-                parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else(
-                    || (Some(name), Vec::new()),
-                    |(name, helper_attrs)| (Some(name), helper_attrs),
-                )
-            })
-            .unwrap_or_else(|| (None, helper_attrs));
+        let (builtin_name, helper_attrs) = match find_attr!(attrs, AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, .. } => (builtin_name, helper_attrs))
+        {
+            // Override `helper_attrs` passed above if it's a built-in macro,
+            // marking `proc_macro_derive` macros as built-in is not a realistic use case.
+            Some((Some(name), helper_attrs)) => {
+                (Some(*name), helper_attrs.iter().copied().collect())
+            }
+            Some((None, _)) => (Some(name), Vec::new()),
+
+            // Not a built-in macro
+            None => (None, helper_attrs),
+        };
 
         let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
 
@@ -1390,80 +1392,6 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
     }
 }
 
-pub fn parse_macro_name_and_helper_attrs(
-    dcx: DiagCtxtHandle<'_>,
-    attr: &impl AttributeExt,
-    macro_type: &str,
-) -> Option<(Symbol, Vec<Symbol>)> {
-    // Once we've located the `#[proc_macro_derive]` attribute, verify
-    // that it's of the form `#[proc_macro_derive(Foo)]` or
-    // `#[proc_macro_derive(Foo, attributes(A, ..))]`
-    let list = attr.meta_item_list()?;
-    let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
-        dcx.emit_err(errors::AttrNoArguments { span: attr.span() });
-        return None;
-    };
-    let Some(trait_attr) = trait_attr.meta_item() else {
-        dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
-        return None;
-    };
-    let trait_ident = match trait_attr.ident() {
-        Some(trait_ident) if trait_attr.is_word() => trait_ident,
-        _ => {
-            dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span });
-            return None;
-        }
-    };
-
-    if !trait_ident.name.can_be_raw() {
-        dcx.emit_err(errors::CannotBeNameOfMacro {
-            span: trait_attr.span,
-            trait_ident,
-            macro_type,
-        });
-    }
-
-    let attributes_attr = list.get(1);
-    let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
-        if !attr.has_name(sym::attributes) {
-            dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
-        }
-        attr.meta_item_list()
-            .unwrap_or_else(|| {
-                dcx.emit_err(errors::AttributesWrongForm { span: attr.span() });
-                &[]
-            })
-            .iter()
-            .filter_map(|attr| {
-                let Some(attr) = attr.meta_item() else {
-                    dcx.emit_err(errors::AttributeMetaItem { span: attr.span() });
-                    return None;
-                };
-
-                let ident = match attr.ident() {
-                    Some(ident) if attr.is_word() => ident,
-                    _ => {
-                        dcx.emit_err(errors::AttributeSingleWord { span: attr.span });
-                        return None;
-                    }
-                };
-                if !ident.name.can_be_raw() {
-                    dcx.emit_err(errors::HelperAttributeNameInvalid {
-                        span: attr.span,
-                        name: ident,
-                    });
-                }
-
-                Some(ident.name)
-            })
-            .collect()
-    } else {
-        Vec::new()
-    };
-
-    Some((trait_ident.name, proc_attrs))
-}
-
 /// If this item looks like a specific enums from `rental`, emit a fatal error.
 /// See #73345 and #83125 for more details.
 /// FIXME(#73933): Remove this eventually.
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 3ac5d213053..fd1391a554a 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -79,72 +79,6 @@ pub(crate) struct MacroBodyStability {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand_attr_no_arguments)]
-pub(crate) struct AttrNoArguments {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_not_a_meta_item)]
-pub(crate) struct NotAMetaItem {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_only_one_word)]
-pub(crate) struct OnlyOneWord {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_cannot_be_name_of_macro)]
-pub(crate) struct CannotBeNameOfMacro<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_ident: Ident,
-    pub macro_type: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_arg_not_attributes)]
-pub(crate) struct ArgumentNotAttributes {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attributes_wrong_form)]
-pub(crate) struct AttributesWrongForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attribute_meta_item)]
-pub(crate) struct AttributeMetaItem {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_attribute_single_word)]
-pub(crate) struct AttributeSingleWord {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(expand_helper_attribute_name_invalid)]
-pub(crate) struct HelperAttributeNameInvalid {
-    #[primary_span]
-    pub span: Span,
-    pub name: Ident,
-}
-
-#[derive(Diagnostic)]
 #[diag(expand_feature_removed, code = E0557)]
 #[note]
 pub(crate) struct FeatureRemoved<'a> {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e83f6a1df72..96501844264 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1363,6 +1363,17 @@ impl AttributeExt for Attribute {
             _ => None,
         }
     }
+
+    fn is_proc_macro_attr(&self) -> bool {
+        matches!(
+            self,
+            Attribute::Parsed(
+                AttributeKind::ProcMacro(..)
+                    | AttributeKind::ProcMacroAttribute(..)
+                    | AttributeKind::ProcMacroDerive { .. }
+            )
+        )
+    }
 }
 
 // FIXME(fn_delegation): use function delegation instead of manually forwarding
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 24a3a6e0c4f..ffb33c67f8a 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write};
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
-use rustc_attr_data_structures::EncodeCrossCrate;
+use rustc_attr_data_structures::{AttributeKind, EncodeCrossCrate, find_attr};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::sync::{join, par_for_each_in};
@@ -1965,18 +1965,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 // Proc-macros may have attributes like `#[allow_internal_unstable]`,
                 // so downstream crates need access to them.
                 let attrs = tcx.hir_attrs(proc_macro);
-                let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) {
+                let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) {
                     MacroKind::Bang
-                } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) {
+                } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) {
                     MacroKind::Attr
-                } else if let Some(attr) = ast::attr::find_by_name(attrs, sym::proc_macro_derive) {
-                    // This unwrap chain should have been checked by the proc-macro harness.
-                    name = attr.meta_item_list().unwrap()[0]
-                        .meta_item()
-                        .unwrap()
-                        .ident()
-                        .unwrap()
-                        .name;
+                } else if let Some(trait_name) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, ..} => trait_name)
+                {
+                    name = *trait_name;
                     MacroKind::Derive
                 } else {
                     bug!("Unknown proc-macro type for item {:?}", id);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a7cde2ad485..4c95f0748d3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2024,7 +2024,10 @@ impl<'tcx> TyCtxt<'tcx> {
             && let Some(def_id) = def_id.as_local()
             && let outer = self.def_span(def_id).ctxt().outer_expn_data()
             && matches!(outer.kind, ExpnKind::Macro(MacroKind::Derive, _))
-            && self.has_attr(outer.macro_def_id.unwrap(), sym::rustc_builtin_macro)
+            && find_attr!(
+                self.get_all_attrs(outer.macro_def_id.unwrap()),
+                AttributeKind::RustcBuiltinMacro { .. }
+            )
         {
             true
         } else {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 4b524bb2bd2..0b329cc38b0 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -130,6 +130,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         for attr in attrs {
             let mut style = None;
             match attr {
+                Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
+                }
+                Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
+                }
+                Attribute::Parsed(AttributeKind::ProcMacroDerive { span: attr_span, .. }) => {
+                    self.check_generic_attr(
+                        hir_id,
+                        sym::proc_macro_derive,
+                        *attr_span,
+                        target,
+                        Target::Fn,
+                    );
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
+                }
                 Attribute::Parsed(
                     AttributeKind::SkipDuringMethodDispatch { span: attr_span, .. }
                     | AttributeKind::Coinductive(attr_span)
@@ -275,6 +291,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::MacroTransparency(_)
                     | AttributeKind::Pointee(..)
                     | AttributeKind::Dummy
+                    | AttributeKind::RustcBuiltinMacro { .. }
                     | AttributeKind::OmitGdbPrettyPrinterSection,
                 ) => { /* do nothing  */ }
                 Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
@@ -373,16 +390,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::should_panic, ..] => {
                             self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn)
                         }
-                        [sym::proc_macro, ..] => {
-                            self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
-                        }
-                        [sym::proc_macro_attribute, ..] => {
-                            self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
-                        }
-                        [sym::proc_macro_derive, ..] => {
-                            self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn);
-                            self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
-                        }
                         [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
                             self.check_autodiff(hir_id, attr, span, target)
                         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1265a39d27b..14295ce0a31 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -36,6 +36,7 @@ use std::mem;
 
 use rustc_ast::token::{Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_errors::codes::*;
 use rustc_errors::{FatalError, struct_span_code_err};
@@ -987,28 +988,17 @@ fn clean_proc_macro<'tcx>(
     kind: MacroKind,
     cx: &mut DocContext<'tcx>,
 ) -> ItemKind {
-    let attrs = cx.tcx.hir_attrs(item.hir_id());
-    if kind == MacroKind::Derive
-        && let Some(derive_name) =
-            hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident())
-    {
-        *name = derive_name.name;
+    if kind != MacroKind::Derive {
+        return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
     }
+    let attrs = cx.tcx.hir_attrs(item.hir_id());
+    let Some((trait_name, helper_attrs)) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, helper_attrs, ..} => (*trait_name, helper_attrs))
+    else {
+        return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
+    };
+    *name = trait_name;
+    let helpers = helper_attrs.iter().copied().collect();
 
-    let mut helpers = Vec::new();
-    for mi in hir_attr_lists(attrs, sym::proc_macro_derive) {
-        if !mi.has_name(sym::attributes) {
-            continue;
-        }
-
-        if let Some(list) = mi.meta_item_list() {
-            for inner_mi in list {
-                if let Some(ident) = inner_mi.ident() {
-                    helpers.push(ident.name);
-                }
-            }
-        }
-    }
     ProcMacroItem(ProcMacro { kind, helpers })
 }
 
@@ -1021,17 +1011,16 @@ fn clean_fn_or_proc_macro<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> ItemKind {
     let attrs = cx.tcx.hir_attrs(item.hir_id());
-    let macro_kind = attrs.iter().find_map(|a| {
-        if a.has_name(sym::proc_macro) {
-            Some(MacroKind::Bang)
-        } else if a.has_name(sym::proc_macro_derive) {
-            Some(MacroKind::Derive)
-        } else if a.has_name(sym::proc_macro_attribute) {
-            Some(MacroKind::Attr)
-        } else {
-            None
-        }
-    });
+    let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) {
+        Some(MacroKind::Bang)
+    } else if find_attr!(attrs, AttributeKind::ProcMacroDerive { .. }) {
+        Some(MacroKind::Derive)
+    } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) {
+        Some(MacroKind::Attr)
+    } else {
+        None
+    };
+
     match macro_kind {
         Some(kind) => clean_proc_macro(item, name, kind, cx),
         None => {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 2006a824402..7b057998063 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -312,9 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 /// Functions marked with these attributes must have the exact signature.
 pub(crate) fn requires_exact_signature(attrs: &[Attribute]) -> bool {
     attrs.iter().any(|attr| {
-        [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
-            .iter()
-            .any(|&allow| attr.has_name(allow))
+        attr.is_proc_macro_attr()
     })
 }
 
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 7ae24db8b5f..814a1e5f691 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -43,12 +43,6 @@ error: malformed `no_sanitize` attribute input
 LL | #[no_sanitize]
    | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]`
 
-error: malformed `proc_macro` attribute input
-  --> $DIR/malformed-attrs.rs:100:1
-   |
-LL | #[proc_macro = 18]
-   | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
-
 error: malformed `instruction_set` attribute input
   --> $DIR/malformed-attrs.rs:107:1
    |
@@ -67,18 +61,6 @@ error: malformed `coroutine` attribute input
 LL |     #[coroutine = 63] || {}
    |     ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]`
 
-error: malformed `proc_macro_attribute` attribute input
-  --> $DIR/malformed-attrs.rs:117:1
-   |
-LL | #[proc_macro_attribute = 19]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-
-error: malformed `proc_macro_derive` attribute input
-  --> $DIR/malformed-attrs.rs:124:1
-   |
-LL | #[proc_macro_derive]
-   | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-
 error: malformed `must_not_suspend` attribute input
   --> $DIR/malformed-attrs.rs:133:1
    |
@@ -454,6 +436,24 @@ LL | #[no_implicit_prelude = 23]
    | |                     didn't expect any arguments here
    | help: must be of the form: `#[no_implicit_prelude]`
 
+error[E0565]: malformed `proc_macro` attribute input
+  --> $DIR/malformed-attrs.rs:100:1
+   |
+LL | #[proc_macro = 18]
+   | ^^^^^^^^^^^^^----^
+   | |            |
+   | |            didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro]`
+
+error[E0565]: malformed `proc_macro_attribute` attribute input
+  --> $DIR/malformed-attrs.rs:117:1
+   |
+LL | #[proc_macro_attribute = 19]
+   | ^^^^^^^^^^^^^^^^^^^^^^^----^
+   | |                      |
+   | |                      didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_attribute]`
+
 error[E0539]: malformed `must_use` attribute input
   --> $DIR/malformed-attrs.rs:120:1
    |
@@ -471,6 +471,15 @@ LL - #[must_use = 1]
 LL + #[must_use]
    |
 
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/malformed-attrs.rs:124:1
+   |
+LL | #[proc_macro_derive]
+   | ^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+
 error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
   --> $DIR/malformed-attrs.rs:129:1
    |
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
index 2f17d9620b4..bd136e64d3f 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
@@ -12,6 +12,7 @@ pub fn b() {}
 #[proc_macro_derive(unsafe(Foo))]
 //~^ ERROR attribute is only usable with crates of the `proc-macro` crate type
 //~| ERROR: expected identifier, found keyword `unsafe`
+//~| ERROR malformed `proc_macro_derive` attribute input
 pub fn c() {}
 
 #[unsafe(proc_macro_attribute)]
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 25b83a26e17..884e7663c85 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -1,11 +1,11 @@
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -40,7 +40,7 @@ LL | #[proc_macro_derive(r#unsafe(Foo))]
    |                     ++
 
 error: `proc_macro_attribute` is not an unsafe attribute
-  --> $DIR/proc-unsafe-attributes.rs:17:3
+  --> $DIR/proc-unsafe-attributes.rs:18:3
    |
 LL | #[unsafe(proc_macro_attribute)]
    |   ^^^^^^ this is not an unsafe attribute
@@ -48,7 +48,7 @@ LL | #[unsafe(proc_macro_attribute)]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `allow` is not an unsafe attribute
-  --> $DIR/proc-unsafe-attributes.rs:22:3
+  --> $DIR/proc-unsafe-attributes.rs:23:3
    |
 LL | #[unsafe(allow(dead_code))]
    |   ^^^^^^ this is not an unsafe attribute
@@ -56,7 +56,7 @@ LL | #[unsafe(allow(dead_code))]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `allow` is not an unsafe attribute
-  --> $DIR/proc-unsafe-attributes.rs:26:3
+  --> $DIR/proc-unsafe-attributes.rs:27:3
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |   ^^^^^^ this is not an unsafe attribute
@@ -64,7 +64,7 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
    = note: extraneous unsafe is not allowed in attributes
 
 error: expected identifier, found keyword `unsafe`
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^ expected identifier, found keyword
@@ -93,13 +93,13 @@ LL | #[proc_macro_derive(unsafe(Foo))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
-  --> $DIR/proc-unsafe-attributes.rs:17:1
+  --> $DIR/proc-unsafe-attributes.rs:18:1
    |
 LL | #[unsafe(proc_macro_attribute)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -107,15 +107,24 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/proc-unsafe-attributes.rs:12:1
+   |
+LL | #[proc_macro_derive(unsafe(Foo))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
+   | |                         |
+   | |                         didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -123,13 +132,14 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/proc-unsafe-attributes.rs:26:16
+  --> $DIR/proc-unsafe-attributes.rs:27:16
    |
 LL | #[unsafe(allow(unsafe(dead_code)))]
    |                ^^^^^^^^^^^^^^^^^ bad attribute argument
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors
 
-For more information about this error, try `rustc --explain E0452`.
+Some errors have detailed explanations: E0452, E0565.
+For more information about an error, try `rustc --explain E0452`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 9740eaaf1e9..b93cb2ea006 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -57,7 +57,7 @@
 // see gated-link-args.rs
 // see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700"
 // (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600")
-#![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
+#![proc_macro_derive(Test)] //~ WARN `#[proc_macro_derive]` only has an effect
 #![doc = "2400"]
 #![cold] //~ WARN attribute should be applied to a function
 //~^ WARN this was previously accepted
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 9016ca1efa7..8bac1f6155e 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -367,12 +367,6 @@ warning: `#[should_panic]` only has an effect on functions
 LL | #![should_panic]
    | ^^^^^^^^^^^^^^^^
 
-warning: `#[proc_macro_derive]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
-   |
-LL | #![proc_macro_derive()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
 warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
    |
@@ -409,6 +403,12 @@ warning: `#[must_use]` has no effect when applied to a module
 LL | #![must_use]
    | ^^^^^^^^^^^^
 
+warning: `#[proc_macro_derive]` only has an effect on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
+   |
+LL | #![proc_macro_derive(Test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 warning: attribute should be applied to a function definition
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
    |
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
index a94ffd602ef..392880e1b3b 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs
@@ -7,27 +7,27 @@
 // signal errors, making it incompatible with the "warnings only"
 // nature of issue-43106-gating-of-builtin-attrs.rs
 
-#[proc_macro_derive()]
+#[proc_macro_derive(Test)]
 //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
 mod proc_macro_derive1 {
-    mod inner { #![proc_macro_derive()] }
+    mod inner { #![proc_macro_derive(Test)] }
     // (no error issued here if there was one on outer module)
 }
 
 mod proc_macro_derive2 {
-    mod inner { #![proc_macro_derive()] }
+    mod inner { #![proc_macro_derive(Test)] }
     //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
 
-    #[proc_macro_derive()] fn f() { }
+    #[proc_macro_derive(Test)] fn f() { }
     //~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro`
 
-    #[proc_macro_derive()] struct S;
+    #[proc_macro_derive(Test)] struct S;
     //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
 
-    #[proc_macro_derive()] type T = S;
+    #[proc_macro_derive(Test)] type T = S;
     //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
 
-    #[proc_macro_derive()] impl S { }
+    #[proc_macro_derive(Test)] impl S { }
     //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions
 }
 
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
index e202b472d9c..537032d777f 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr
@@ -1,38 +1,38 @@
 error: the `#[proc_macro_derive]` attribute may only be used on bare functions
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:10:1
    |
-LL | #[proc_macro_derive()]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[proc_macro_derive(Test)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute may only be used on bare functions
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:18:17
    |
-LL |     mod inner { #![proc_macro_derive()] }
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     mod inner { #![proc_macro_derive(Test)] }
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:21:5
    |
-LL |     #[proc_macro_derive()] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[proc_macro_derive(Test)] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute may only be used on bare functions
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:24:5
    |
-LL |     #[proc_macro_derive()] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[proc_macro_derive(Test)] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute may only be used on bare functions
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:27:5
    |
-LL |     #[proc_macro_derive()] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[proc_macro_derive(Test)] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute may only be used on bare functions
   --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:30:5
    |
-LL |     #[proc_macro_derive()] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[proc_macro_derive(Test)] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/proc-macro/attribute.rs b/tests/ui/proc-macro/attribute.rs
index 30ed8ff8247..988cdcd0403 100644
--- a/tests/ui/proc-macro/attribute.rs
+++ b/tests/ui/proc-macro/attribute.rs
@@ -6,68 +6,85 @@
 extern crate proc_macro;
 use proc_macro::*;
 
-#[proc_macro_derive] //~ ERROR malformed `proc_macro_derive` attribute
+#[proc_macro_derive]
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
 pub fn foo1(input: TokenStream) -> TokenStream { input }
 
-#[proc_macro_derive = ""] //~ ERROR malformed `proc_macro_derive` attribute
+#[proc_macro_derive = ""]
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
 pub fn foo2(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d3, a, b)]
-//~^ ERROR attribute must have either one or two arguments
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE the only valid argument here is `attributes`
 pub fn foo3(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d4, attributes(a), b)]
-//~^ ERROR attribute must have either one or two arguments
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
 pub fn foo4(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive("a")]
-//~^ ERROR: not a meta item
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect a literal here
 pub fn foo5(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d6 = "")]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
 pub fn foo6(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(m::d7)]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
 pub fn foo7(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d8(a))]
-//~^ ERROR: must only be one word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
 pub fn foo8(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(self)]
-//~^ ERROR: `self` cannot be a name of derive macro
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
 pub fn foo9(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(PartialEq)] // OK
 pub fn foo10(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d11, a)]
-//~^ ERROR: second argument must be `attributes`
-//~| ERROR: attribute must be of form: `attributes(foo, bar)`
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE the only valid argument here is `attributes`
 pub fn foo11(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d12, attributes)]
-//~^ ERROR: attribute must be of form: `attributes(foo, bar)`
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected this to be a list
 pub fn foo12(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d13, attributes("a"))]
-//~^ ERROR: attribute must be a meta item, not a literal
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
 pub fn foo13(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d14, attributes(a = ""))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
 pub fn foo14(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d15, attributes(m::a))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
 pub fn foo15(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d16, attributes(a(b)))]
-//~^ ERROR: attribute must only be a single word
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE didn't expect any arguments here
 pub fn foo16(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d17, attributes(self))]
-//~^ ERROR: `self` cannot be a name of derive helper attribute
+//~^ ERROR malformed `proc_macro_derive` attribute
+//~| NOTE expected a valid identifier here
 pub fn foo17(input: TokenStream) -> TokenStream { input }
diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr
index 3269aaf7f91..db59a1fdfb3 100644
--- a/tests/ui/proc-macro/attribute.stderr
+++ b/tests/ui/proc-macro/attribute.stderr
@@ -1,104 +1,148 @@
-error: malformed `proc_macro_derive` attribute input
+error[E0539]: malformed `proc_macro_derive` attribute input
   --> $DIR/attribute.rs:9:1
    |
 LL | #[proc_macro_derive]
-   | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   | ^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:12:1
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:14:1
    |
 LL | #[proc_macro_derive = ""]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must have either one or two arguments
-  --> $DIR/attribute.rs:15:1
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:19:1
    |
 LL | #[proc_macro_derive(d3, a, b)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^
+   | |                       |
+   | |                       the only valid argument here is `attributes`
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must have either one or two arguments
-  --> $DIR/attribute.rs:19:1
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:24:1
    |
 LL | #[proc_macro_derive(d4, attributes(a), b)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   | |                                      |
+   | |                                      didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: not a meta item
-  --> $DIR/attribute.rs:23:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:29:1
    |
 LL | #[proc_macro_derive("a")]
-   |                     ^^^
+   | ^^^^^^^^^^^^^^^^^^^^---^^
+   | |                   |
+   | |                   didn't expect a literal here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: must only be one word
-  --> $DIR/attribute.rs:27:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:34:1
    |
 LL | #[proc_macro_derive(d6 = "")]
-   |                     ^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^----^^
+   | |                      |
+   | |                      didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: must only be one word
-  --> $DIR/attribute.rs:31:21
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:39:1
    |
 LL | #[proc_macro_derive(m::d7)]
-   |                     ^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^-----^^
+   | |                   |
+   | |                   expected a valid identifier here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: must only be one word
-  --> $DIR/attribute.rs:35:21
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:44:1
    |
 LL | #[proc_macro_derive(d8(a))]
-   |                     ^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^---^^
+   | |                     |
+   | |                     didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: `self` cannot be a name of derive macro
-  --> $DIR/attribute.rs:39:21
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:49:1
    |
 LL | #[proc_macro_derive(self)]
-   |                     ^^^^
-
-error: second argument must be `attributes`
-  --> $DIR/attribute.rs:46:26
-   |
-LL | #[proc_macro_derive(d11, a)]
-   |                          ^
+   | ^^^^^^^^^^^^^^^^^^^^----^^
+   | |                   |
+   | |                   expected a valid identifier here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must be of form: `attributes(foo, bar)`
-  --> $DIR/attribute.rs:46:26
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:57:1
    |
 LL | #[proc_macro_derive(d11, a)]
-   |                          ^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   | |                        |
+   | |                        the only valid argument here is `attributes`
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must be of form: `attributes(foo, bar)`
-  --> $DIR/attribute.rs:51:26
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:62:1
    |
 LL | #[proc_macro_derive(d12, attributes)]
-   |                          ^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^
+   | |                        |
+   | |                        expected this to be a list
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must be a meta item, not a literal
-  --> $DIR/attribute.rs:55:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:67:1
    |
 LL | #[proc_macro_derive(d13, attributes("a"))]
-   |                                     ^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
+   | |                                   |
+   | |                                   expected a valid identifier here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must only be a single word
-  --> $DIR/attribute.rs:59:37
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:72:1
    |
 LL | #[proc_macro_derive(d14, attributes(a = ""))]
-   |                                     ^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+   | |                                     |
+   | |                                     didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must only be a single word
-  --> $DIR/attribute.rs:63:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:77:1
    |
 LL | #[proc_macro_derive(d15, attributes(m::a))]
-   |                                     ^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+   | |                                   |
+   | |                                   expected a valid identifier here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: attribute must only be a single word
-  --> $DIR/attribute.rs:67:37
+error[E0565]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:82:1
    |
 LL | #[proc_macro_derive(d16, attributes(a(b)))]
-   |                                     ^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
+   | |                                    |
+   | |                                    didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: `self` cannot be a name of derive helper attribute
-  --> $DIR/attribute.rs:71:37
+error[E0539]: malformed `proc_macro_derive` attribute input
+  --> $DIR/attribute.rs:87:1
    |
 LL | #[proc_macro_derive(d17, attributes(self))]
-   |                                     ^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
+   | |                                   |
+   | |                                   expected a valid identifier here
+   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
+Some errors have detailed explanations: E0539, E0565.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/proc-macro/invalid-attributes.rs b/tests/ui/proc-macro/invalid-attributes.rs
index a70c73e9b8f..703defad69b 100644
--- a/tests/ui/proc-macro/invalid-attributes.rs
+++ b/tests/ui/proc-macro/invalid-attributes.rs
@@ -7,20 +7,32 @@ extern crate proc_macro;
 
 use proc_macro::TokenStream;
 
-#[proc_macro = "test"] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro = "test"]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
 pub fn a(a: TokenStream) -> TokenStream { a }
 
-#[proc_macro()] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro()]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
 pub fn c(a: TokenStream) -> TokenStream { a }
 
-#[proc_macro(x)] //~ ERROR malformed `proc_macro` attribute
+#[proc_macro(x)]
+//~^ ERROR malformed `proc_macro` attribute
+//~| NOTE didn't expect any arguments here
 pub fn d(a: TokenStream) -> TokenStream { a }
 
-#[proc_macro_attribute = "test"] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute = "test"]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
 pub fn e(_: TokenStream, a: TokenStream) -> TokenStream { a }
 
-#[proc_macro_attribute()] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute()]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
 pub fn g(_: TokenStream, a: TokenStream) -> TokenStream { a }
 
-#[proc_macro_attribute(x)] //~ ERROR malformed `proc_macro_attribute` attribute
+#[proc_macro_attribute(x)]
+//~^ ERROR malformed `proc_macro_attribute` attribute
+//~| NOTE didn't expect any arguments here
 pub fn h(_: TokenStream, a: TokenStream) -> TokenStream { a }
diff --git a/tests/ui/proc-macro/invalid-attributes.stderr b/tests/ui/proc-macro/invalid-attributes.stderr
index fe411fa5e1f..11c182ee03a 100644
--- a/tests/ui/proc-macro/invalid-attributes.stderr
+++ b/tests/ui/proc-macro/invalid-attributes.stderr
@@ -1,38 +1,57 @@
-error: malformed `proc_macro` attribute input
+error[E0565]: malformed `proc_macro` attribute input
   --> $DIR/invalid-attributes.rs:10:1
    |
 LL | #[proc_macro = "test"]
-   | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+   | ^^^^^^^^^^^^^--------^
+   | |            |
+   | |            didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro]`
 
-error: malformed `proc_macro` attribute input
-  --> $DIR/invalid-attributes.rs:13:1
+error[E0565]: malformed `proc_macro` attribute input
+  --> $DIR/invalid-attributes.rs:15:1
    |
 LL | #[proc_macro()]
-   | ^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+   | ^^^^^^^^^^^^--^
+   | |           |
+   | |           didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro]`
 
-error: malformed `proc_macro` attribute input
-  --> $DIR/invalid-attributes.rs:16:1
+error[E0565]: malformed `proc_macro` attribute input
+  --> $DIR/invalid-attributes.rs:20:1
    |
 LL | #[proc_macro(x)]
-   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
+   | ^^^^^^^^^^^^---^
+   | |           |
+   | |           didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro]`
 
-error: malformed `proc_macro_attribute` attribute input
-  --> $DIR/invalid-attributes.rs:19:1
+error[E0565]: malformed `proc_macro_attribute` attribute input
+  --> $DIR/invalid-attributes.rs:25:1
    |
 LL | #[proc_macro_attribute = "test"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^--------^
+   | |                      |
+   | |                      didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_attribute]`
 
-error: malformed `proc_macro_attribute` attribute input
-  --> $DIR/invalid-attributes.rs:22:1
+error[E0565]: malformed `proc_macro_attribute` attribute input
+  --> $DIR/invalid-attributes.rs:30:1
    |
 LL | #[proc_macro_attribute()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
+   | ^^^^^^^^^^^^^^^^^^^^^^--^
+   | |                     |
+   | |                     didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_attribute]`
 
-error: malformed `proc_macro_attribute` attribute input
-  --> $DIR/invalid-attributes.rs:25:1
+error[E0565]: malformed `proc_macro_attribute` attribute input
+  --> $DIR/invalid-attributes.rs:35:1
    |
 LL | #[proc_macro_attribute(x)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
+   | ^^^^^^^^^^^^^^^^^^^^^^---^
+   | |                     |
+   | |                     didn't expect any arguments here
+   | help: must be of the form: `#[proc_macro_attribute]`
 
 error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0565`.