about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-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_const_eval/messages.ftl6
-rw-r--r--compiler/rustc_const_eval/src/errors.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs10
-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_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs17
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs7
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs5
-rw-r--r--compiler/rustc_passes/src/check_attr.rs27
19 files changed, 271 insertions, 224 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_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index aa0bc42d448..2985eafb63a 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -128,15 +128,15 @@ const_eval_frame_note_inner = inside {$where_ ->
 
 const_eval_frame_note_last = the failure occurred here
 
+const_eval_incompatible_arg_types =
+    calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}
+
 const_eval_incompatible_calling_conventions =
     calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
 
 const_eval_incompatible_return_types =
     calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
 
-const_eval_incompatible_types =
-    calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
-
 const_eval_interior_mutable_borrow_escaping =
     interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
     .label = this borrow of an interior mutable value refers to such a temporary
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index b6a64035261..a4148cb145f 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -500,7 +500,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             InvalidNichedEnumVariantWritten { .. } => {
                 const_eval_invalid_niched_enum_variant_written
             }
-            AbiMismatchArgument { .. } => const_eval_incompatible_types,
+            AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
             AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
         }
     }
@@ -625,12 +625,16 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                 diag.arg("data_size", info.data_size);
             }
             InvalidNichedEnumVariantWritten { enum_ty } => {
-                diag.arg("ty", enum_ty.to_string());
+                diag.arg("ty", enum_ty);
             }
-            AbiMismatchArgument { caller_ty, callee_ty }
-            | AbiMismatchReturn { caller_ty, callee_ty } => {
-                diag.arg("caller_ty", caller_ty.to_string());
-                diag.arg("callee_ty", callee_ty.to_string());
+            AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => {
+                diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output
+                diag.arg("caller_ty", caller_ty);
+                diag.arg("callee_ty", callee_ty);
+            }
+            AbiMismatchReturn { caller_ty, callee_ty } => {
+                diag.arg("caller_ty", caller_ty);
+                diag.arg("callee_ty", callee_ty);
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 1503f3bcd99..bda00ea2fb8 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -270,6 +270,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
         >,
         callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+        callee_arg_idx: usize,
         callee_arg: &mir::Place<'tcx>,
         callee_ty: Ty<'tcx>,
         already_live: bool,
@@ -298,6 +299,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Check compatibility
         if !self.check_argument_compat(caller_abi, callee_abi)? {
             throw_ub!(AbiMismatchArgument {
+                arg_idx: callee_arg_idx,
                 caller_ty: caller_abi.layout.ty,
                 callee_ty: callee_abi.layout.ty
             });
@@ -424,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // this is a single iterator (that handles `spread_arg`), then
             // `pass_argument` would be the loop body. It takes care to
             // not advance `caller_iter` for ignored arguments.
-            let mut callee_args_abis = callee_fn_abi.args.iter();
+            let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
             for local in body.args_iter() {
                 // Construct the destination place for this argument. At this point all
                 // locals are still dead, so we cannot construct a `PlaceTy`.
@@ -445,10 +447,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                             &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
                             *self.tcx,
                         );
-                        let callee_abi = callee_args_abis.next().unwrap();
+                        let (idx, callee_abi) = callee_args_abis.next().unwrap();
                         self.pass_argument(
                             &mut caller_args,
                             callee_abi,
+                            idx,
                             &dest,
                             field_ty,
                             /* already_live */ true,
@@ -456,10 +459,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     }
                 } else {
                     // Normal argument. Cannot mark it as live yet, it might be unsized!
-                    let callee_abi = callee_args_abis.next().unwrap();
+                    let (idx, callee_abi) = callee_args_abis.next().unwrap();
                     self.pass_argument(
                         &mut caller_args,
                         callee_abi,
+                        idx,
                         &dest,
                         ty,
                         /* already_live */ false,
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_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index acc831d30ca..6e63ce31024 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -768,7 +768,9 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
                     check_static_inhabited(tcx, def_id);
                     check_static_linkage(tcx, def_id);
                     let ty = tcx.type_of(def_id).instantiate_identity();
-                    res = res.and(wfcheck::check_static_item(tcx, def_id, ty, true));
+                    res = res.and(wfcheck::check_static_item(
+                        tcx, def_id, ty, /* should_check_for_sync */ true,
+                    ));
                 }
                 DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
                 _ => unreachable!(),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 68a91212e50..22fb02714dd 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -221,7 +221,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                     let ty = icx.lower_ty(ty);
                     // MIR relies on references to statics being scalars.
                     // Verify that here to avoid ill-formed MIR.
-                    match check_static_item(tcx, def_id, ty, false) {
+                    // We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
+                    // relying on the fact that non-Sync statics don't ICE the rest of the compiler.
+                    match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
                         Ok(()) => ty,
                         Err(guar) => Ty::new_error(tcx, guar),
                     }
@@ -286,7 +288,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 let ty = icx.lower_ty(ty);
                 // MIR relies on references to statics being scalars.
                 // Verify that here to avoid ill-formed MIR.
-                match check_static_item(tcx, def_id, ty, false) {
+                // We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
+                // relying on the fact that non-Sync statics don't ICE the rest of the compiler.
+                match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
                     Ok(()) => ty,
                     Err(guar) => Ty::new_error(tcx, guar),
                 }
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/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 2b0cfb86564..3e895c6b280 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -426,7 +426,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Trying to set discriminant to the niched variant, but the value does not match.
     InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
     /// ABI-incompatible argument types.
-    AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+    AbiMismatchArgument {
+        /// The index of the argument whose type is wrong.
+        arg_idx: usize,
+        caller_ty: Ty<'tcx>,
+        callee_ty: Ty<'tcx>,
+    },
     /// ABI-incompatible return types.
     AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
 }
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)
                         }