about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs19
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs2
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs115
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs14
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs10
-rw-r--r--compiler/rustc_hir/src/hir.rs1
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs17
-rw-r--r--compiler/rustc_resolve/messages.ftl2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs67
-rw-r--r--compiler/rustc_resolve/src/errors.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs8
15 files changed, 206 insertions, 65 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 9f99b33adcc..1e2576bef2c 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -157,6 +157,19 @@ pub enum UsedBy {
     Linker,
 }
 
+#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum MacroUseArgs {
+    UseAll,
+    UseSpecific(ThinVec<Ident>),
+}
+
+impl Default for MacroUseArgs {
+    fn default() -> Self {
+        Self::UseSpecific(ThinVec::new())
+    }
+}
+
 #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
 pub struct StrippedCfgItem<ModId = DefId> {
     pub parent_module: ModId,
@@ -351,9 +364,15 @@ pub enum AttributeKind {
     /// Represents `#[loop_match]`.
     LoopMatch(Span),
 
+    /// Represents `#[macro_escape]`.
+    MacroEscape(Span),
+
     /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
 
+    /// Represents `#[macro_use]`.
+    MacroUse { span: Span, arguments: MacroUseArgs },
+
     /// Represents `#[marker]`.
     Marker(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 86d9ddba4d2..159b807a3b2 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -45,7 +45,9 @@ impl AttributeKind {
             LinkOrdinal { .. } => No,
             LinkSection { .. } => Yes, // Needed for rustdoc
             LoopMatch(..) => No,
+            MacroEscape(..) => No,
             MacroTransparency(..) => Yes,
+            MacroUse { .. } => No,
             Marker(..) => No,
             MayDangle(..) => No,
             MustUse { .. } => Yes,
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index ecca0e39063..4c5af805ca9 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_ast::token::CommentKind;
 use rustc_ast::{AttrStyle, IntTy, UintTy};
 use rustc_ast_pretty::pp::Printer;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{ErrorGuaranteed, Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
 pub use stability::*;
 use thin_vec::ThinVec;
 pub use version::*;
@@ -172,7 +172,7 @@ macro_rules! print_tup {
 print_tup!(A B C D E F G H);
 print_skip!(Span, (), ErrorGuaranteed);
 print_disp!(u16, bool, NonZero<u32>);
-print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
+print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
 
 /// Finds attributes in sequences of attributes by pattern matching.
 ///
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
new file mode 100644
index 00000000000..eade49180ac
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -0,0 +1,115 @@
+use rustc_attr_data_structures::{AttributeKind, MacroUseArgs};
+use rustc_errors::DiagArgValue;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
+
+use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
+use crate::parser::ArgParser;
+use crate::session_diagnostics;
+
+pub(crate) struct MacroEscapeParser;
+impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
+    const PATH: &[Symbol] = &[sym::macro_escape];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape;
+}
+
+/// `#[macro_use]` attributes can either:
+/// - Use all macros from a crate, if provided without arguments
+/// - Use specific macros from a crate, if provided with arguments `#[macro_use(macro1, macro2)]`
+/// A warning should be provided if an use all is combined with specific uses, or if multiple use-alls are used.
+#[derive(Default)]
+pub(crate) struct MacroUseParser {
+    state: MacroUseArgs,
+
+    /// Spans of all `#[macro_use]` arguments with arguments, used for linting
+    uses_attr_spans: ThinVec<Span>,
+    /// If `state` is `UseSpecific`, stores the span of the first `#[macro_use]` argument, used as the span for this attribute
+    /// If `state` is `UseAll`, stores the span of the first `#[macro_use]` arguments without arguments
+    first_span: Option<Span>,
+}
+
+const MACRO_USE_TEMPLATE: AttributeTemplate = template!(Word, List: "name1, name2, ...");
+
+impl<S: Stage> AttributeParser<S> for MacroUseParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::macro_use],
+        MACRO_USE_TEMPLATE,
+        |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| {
+            let span = cx.attr_span;
+            group.first_span.get_or_insert(span);
+            match args {
+                ArgParser::NoArgs => {
+                    match group.state {
+                        MacroUseArgs::UseAll => {
+                            let first_span = group.first_span.expect(
+                                "State is UseAll is some so this is not the first attribute",
+                            );
+                            // Since there is a `#[macro_use]` import already, give a warning
+                            cx.warn_unused_duplicate(first_span, span);
+                        }
+                        MacroUseArgs::UseSpecific(_) => {
+                            group.state = MacroUseArgs::UseAll;
+                            group.first_span = Some(span);
+                            // If there is a `#[macro_use]` attribute, warn on all `#[macro_use(...)]` attributes since everything is already imported
+                            for specific_use in group.uses_attr_spans.drain(..) {
+                                cx.warn_unused_duplicate(span, specific_use);
+                            }
+                        }
+                    }
+                }
+                ArgParser::List(list) => {
+                    if list.is_empty() {
+                        cx.warn_empty_attribute(list.span);
+                        return;
+                    }
+
+                    match &mut group.state {
+                        MacroUseArgs::UseAll => {
+                            let first_span = group.first_span.expect(
+                                "State is UseAll is some so this is not the first attribute",
+                            );
+                            cx.warn_unused_duplicate(first_span, span);
+                        }
+                        MacroUseArgs::UseSpecific(arguments) => {
+                            // Store here so if we encounter a `UseAll` later we can still lint this attribute
+                            group.uses_attr_spans.push(cx.attr_span);
+
+                            for item in list.mixed() {
+                                let Some(item) = item.meta_item() else {
+                                    cx.expected_identifier(item.span());
+                                    continue;
+                                };
+                                if let Err(err_span) = item.args().no_args() {
+                                    cx.expected_no_args(err_span);
+                                    continue;
+                                }
+                                let Some(item) = item.path().word() else {
+                                    cx.expected_identifier(item.span());
+                                    continue;
+                                };
+                                arguments.push(item);
+                            }
+                        }
+                    }
+                }
+                ArgParser::NameValue(_) => {
+                    let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use);
+                    cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
+                        num_suggestions: suggestions.len(),
+                        suggestions: DiagArgValue::StrListSepByAnd(
+                            suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                        ),
+                        span,
+                    });
+                }
+            }
+        },
+    )];
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 200f1381960..15b90bd2ed7 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -36,6 +36,7 @@ pub(crate) mod inline;
 pub(crate) mod link_attrs;
 pub(crate) mod lint_helpers;
 pub(crate) mod loop_match;
+pub(crate) mod macro_attrs;
 pub(crate) mod must_use;
 pub(crate) mod no_implicit_prelude;
 pub(crate) mod non_exhaustive;
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
index e0a3e675509..42af3ed0bfa 100644
--- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -34,7 +34,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
                 ArgParser::List(_) => {
                     let suggestions =
                         <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use");
-                    cx.emit_err(session_diagnostics::MustUseIllFormedAttributeInput {
+                    cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
                         num_suggestions: suggestions.len(),
                         suggestions: DiagArgValue::StrListSepByAnd(
                             suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 4d692d9562c..45bfe345207 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -33,6 +33,7 @@ use crate::attributes::lint_helpers::{
     AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
 };
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
+use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
 use crate::attributes::non_exhaustive::NonExhaustiveParser;
@@ -126,6 +127,7 @@ attribute_parsers!(
         BodyStabilityParser,
         ConfusablesParser,
         ConstStabilityParser,
+        MacroUseParser,
         NakedParser,
         StabilityParser,
         UsedParser,
@@ -174,6 +176,7 @@ attribute_parsers!(
         Single<WithoutArgs<FfiPureParser>>,
         Single<WithoutArgs<FundamentalParser>>,
         Single<WithoutArgs<LoopMatchParser>>,
+        Single<WithoutArgs<MacroEscapeParser>>,
         Single<WithoutArgs<MarkerParser>>,
         Single<WithoutArgs<MayDangleParser>>,
         Single<WithoutArgs<NoImplicitPreludeParser>>,
@@ -386,6 +389,17 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         })
     }
 
+    /// emit an error that a `name` was expected here
+    pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedIdentifier,
+        })
+    }
+
     /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
     /// a nicer error message talking about the specific name that was found lacking a value.
     pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 9a400e0fe10..1de25ca252b 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -438,7 +438,7 @@ pub(crate) struct IllFormedAttributeInput {
 
 #[derive(Diagnostic)]
 #[diag(attr_parsing_ill_formed_attribute_input)]
-pub(crate) struct MustUseIllFormedAttributeInput {
+pub(crate) struct IllFormedAttributeInputLint {
     #[primary_span]
     pub span: Span,
     pub num_suggestions: usize,
@@ -549,6 +549,7 @@ pub(crate) enum AttributeParseErrorReason {
         /// Should we tell the user to write a list when they didn't?
         list: bool,
     },
+    ExpectedIdentifier,
 }
 
 pub(crate) struct AttributeParseError {
@@ -600,11 +601,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                 diag.code(E0538);
             }
             AttributeParseErrorReason::UnexpectedLiteral => {
-                diag.span_label(self.span, format!("didn't expect a literal here"));
+                diag.span_label(self.span, "didn't expect a literal here");
                 diag.code(E0565);
             }
             AttributeParseErrorReason::ExpectedNoArgs => {
-                diag.span_label(self.span, format!("didn't expect any arguments here"));
+                diag.span_label(self.span, "didn't expect any arguments here");
                 diag.code(E0565);
             }
             AttributeParseErrorReason::ExpectedNameValue(None) => {
@@ -684,6 +685,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                     }
                 }
             }
+            AttributeParseErrorReason::ExpectedIdentifier => {
+                diag.span_label(self.span, "expected a valid identifier here");
+            }
         }
 
         let suggestions = self.template.suggestions(false, &name);
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e7898648c2b..e83f6a1df72 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute {
             // FIXME: should not be needed anymore when all attrs are parsed
             Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
+            Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::MayDangle(span)) => *span,
             Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span,
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index cca621103b5..ed7fb774908 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -303,6 +303,8 @@ pub fn check_builtin_meta_item(
                 | sym::cold
                 | sym::target_feature
                 | sym::rustc_allow_const_fn_unstable
+                | sym::macro_use
+                | sym::macro_escape
                 | sym::naked
                 | sym::no_mangle
                 | sym::non_exhaustive
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 96c895e71df..04c1933f243 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -227,6 +227,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => {
                     self.check_link_section(hir_id, *attr_span, span, target)
                 }
+                Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => {
+                    self.check_macro_use(hir_id, sym::macro_use, *span, target)
+                }
+                Attribute::Parsed(AttributeKind::MacroEscape(span)) => {
+                    self.check_macro_use(hir_id, sym::macro_escape, *span, target)
+                }
                 Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
                     self.check_naked(hir_id, *attr_span, span, target)
                 }
@@ -362,9 +368,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target),
                         [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
                         [sym::link, ..] => self.check_link(hir_id, attr, span, target),
-                        [sym::macro_use, ..] | [sym::macro_escape, ..] => {
-                            self.check_macro_use(hir_id, attr, target)
-                        }
                         [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod),
                         [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
                         [sym::should_panic, ..] => {
@@ -2411,17 +2414,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
-        let Some(name) = attr.name() else {
-            return;
-        };
+    fn check_macro_use(&self, hir_id: HirId, name: Symbol, attr_span: Span, target: Target) {
         match target {
             Target::ExternCrate | Target::Mod => {}
             _ => {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span(),
+                    attr_span,
                     errors::MacroUse { name },
                 );
             }
@@ -2474,7 +2474,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         // Warn on useless empty attributes.
         // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute`
         let note = if attr.has_any_name(&[
-            sym::macro_use,
             sym::allow,
             sym::expect,
             sym::warn,
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index aa818cc9c46..39e9a9cc58a 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -41,8 +41,6 @@ resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
 resolve_attributes_starting_with_rustc_are_reserved =
     attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
-resolve_bad_macro_import = bad macro import
-
 resolve_binding_in_never_pattern =
     never patterns cannot contain variable bindings
     .suggestion = use a wildcard `_` instead
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 737577baa7a..fe7fa71a7fc 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -11,11 +11,14 @@ use std::sync::Arc;
 use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
 use rustc_ast::{
     self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem,
-    ForeignItemKind, Impl, Item, ItemKind, MetaItemKind, NodeId, StaticItem, StmtKind, TyAlias,
+    ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
 };
+use rustc_attr_data_structures::{AttributeKind, MacroUseArgs};
 use rustc_attr_parsing as attr;
+use rustc_attr_parsing::AttributeParser;
 use rustc_expand::base::ResolverExpand;
 use rustc_expand::expand::AstFragment;
+use rustc_hir::Attribute;
 use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_index::bit_set::DenseBitSet;
@@ -25,6 +28,7 @@ use rustc_middle::metadata::ModChild;
 use rustc_middle::ty::{Feed, Visibility};
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::{Ident, Span, Symbol, kw, sym};
+use thin_vec::ThinVec;
 use tracing::debug;
 
 use crate::Namespace::{MacroNS, TypeNS, ValueNS};
@@ -1019,42 +1023,31 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
     /// Returns `true` if we should consider the underlying `extern crate` to be used.
     fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> bool {
         let mut import_all = None;
-        let mut single_imports = Vec::new();
-        for attr in &item.attrs {
-            if attr.has_name(sym::macro_use) {
-                if self.parent_scope.module.parent.is_some() {
-                    self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot {
-                        span: item.span,
-                    });
-                }
-                if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind
-                    && orig_name == kw::SelfLower
-                {
-                    self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
-                }
-                let ill_formed = |span| {
-                    self.r.dcx().emit_err(errors::BadMacroImport { span });
-                };
-                match attr.meta() {
-                    Some(meta) => match meta.kind {
-                        MetaItemKind::Word => {
-                            import_all = Some(meta.span);
-                            break;
-                        }
-                        MetaItemKind::List(meta_item_inners) => {
-                            for meta_item_inner in meta_item_inners {
-                                match meta_item_inner.ident() {
-                                    Some(ident) if meta_item_inner.is_word() => {
-                                        single_imports.push(ident)
-                                    }
-                                    _ => ill_formed(meta_item_inner.span()),
-                                }
-                            }
-                        }
-                        MetaItemKind::NameValue(..) => ill_formed(meta.span),
-                    },
-                    None => ill_formed(attr.span),
-                }
+        let mut single_imports = ThinVec::new();
+        if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) =
+            AttributeParser::parse_limited(
+                self.r.tcx.sess,
+                &item.attrs,
+                sym::macro_use,
+                item.span,
+                item.id,
+                None,
+            )
+        {
+            if self.parent_scope.module.parent.is_some() {
+                self.r
+                    .dcx()
+                    .emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { span: item.span });
+            }
+            if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind
+                && orig_name == kw::SelfLower
+            {
+                self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span });
+            }
+
+            match arguments {
+                MacroUseArgs::UseAll => import_all = Some(span),
+                MacroUseArgs::UseSpecific(imports) => single_imports = imports,
             }
         }
 
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index b34bcb38f84..d6b1e4de6ea 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -816,13 +816,6 @@ pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot {
 }
 
 #[derive(Diagnostic)]
-#[diag(resolve_bad_macro_import, code = E0466)]
-pub(crate) struct BadMacroImport {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(resolve_extern_crate_self_requires_renaming)]
 pub(crate) struct ExternCrateSelfRequiresRenaming {
     #[primary_span]
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index c1a26c5a9c7..d1a54df988f 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -7,8 +7,9 @@ use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::edition::Edition;
-use rustc_span::{Span, sym};
+use rustc_span::{Span};
 use std::collections::BTreeMap;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -99,15 +100,14 @@ impl LateLintPass<'_> for MacroUseImports {
             && let hir::ItemKind::Use(path, _kind) = &item.kind
             && let hir_id = item.hir_id()
             && let attrs = cx.tcx.hir_attrs(hir_id)
-            && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use))
+            && let Some(mac_attr_span) = find_attr!(attrs, AttributeKind::MacroUse {span, ..} => *span)
             && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns
             && !id.is_local()
         {
             for kid in cx.tcx.module_children(id) {
                 if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
-                    let span = mac_attr.span();
                     let def_path = cx.tcx.def_path_str(mac_id);
-                    self.imports.push((def_path, span, hir_id));
+                    self.imports.push((def_path, mac_attr_span, hir_id));
                 }
             }
         } else if item.span.from_expansion() {