Ports #[macro_use] and #[macro_escape] to the new attribute parsing infrastructure

This commit is contained in:
Jonathan Brouwer
2025-07-12 17:42:39 +02:00
parent a7a1618e6c
commit a460b46d0f
15 changed files with 206 additions and 65 deletions

View File

@@ -157,6 +157,19 @@ pub enum UsedBy {
Linker, 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)] #[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
pub struct StrippedCfgItem<ModId = DefId> { pub struct StrippedCfgItem<ModId = DefId> {
pub parent_module: ModId, pub parent_module: ModId,
@@ -351,9 +364,15 @@ pub enum AttributeKind {
/// Represents `#[loop_match]`. /// Represents `#[loop_match]`.
LoopMatch(Span), LoopMatch(Span),
/// Represents `#[macro_escape]`.
MacroEscape(Span),
/// Represents `#[rustc_macro_transparency]`. /// Represents `#[rustc_macro_transparency]`.
MacroTransparency(Transparency), MacroTransparency(Transparency),
/// Represents `#[macro_use]`.
MacroUse { span: Span, arguments: MacroUseArgs },
/// Represents `#[marker]`. /// Represents `#[marker]`.
Marker(Span), Marker(Span),

View File

@@ -45,7 +45,9 @@ impl AttributeKind {
LinkOrdinal { .. } => No, LinkOrdinal { .. } => No,
LinkSection { .. } => Yes, // Needed for rustdoc LinkSection { .. } => Yes, // Needed for rustdoc
LoopMatch(..) => No, LoopMatch(..) => No,
MacroEscape(..) => No,
MacroTransparency(..) => Yes, MacroTransparency(..) => Yes,
MacroUse { .. } => No,
Marker(..) => No, Marker(..) => No,
MayDangle(..) => No, MayDangle(..) => No,
MustUse { .. } => Yes, MustUse { .. } => Yes,

View File

@@ -24,7 +24,7 @@ use rustc_ast::token::CommentKind;
use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast::{AttrStyle, IntTy, UintTy};
use rustc_ast_pretty::pp::Printer; use rustc_ast_pretty::pp::Printer;
use rustc_span::hygiene::Transparency; use rustc_span::hygiene::Transparency;
use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
pub use stability::*; pub use stability::*;
use thin_vec::ThinVec; use thin_vec::ThinVec;
pub use version::*; pub use version::*;
@@ -172,7 +172,7 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H); print_tup!(A B C D E F G H);
print_skip!(Span, (), ErrorGuaranteed); print_skip!(Span, (), ErrorGuaranteed);
print_disp!(u16, bool, NonZero<u32>); 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. /// Finds attributes in sequences of attributes by pattern matching.
/// ///

View File

@@ -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 })
}
}

View File

@@ -36,6 +36,7 @@ pub(crate) mod inline;
pub(crate) mod link_attrs; pub(crate) mod link_attrs;
pub(crate) mod lint_helpers; pub(crate) mod lint_helpers;
pub(crate) mod loop_match; pub(crate) mod loop_match;
pub(crate) mod macro_attrs;
pub(crate) mod must_use; pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude; pub(crate) mod no_implicit_prelude;
pub(crate) mod non_exhaustive; pub(crate) mod non_exhaustive;

View File

@@ -34,7 +34,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
ArgParser::List(_) => { ArgParser::List(_) => {
let suggestions = let suggestions =
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use"); <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(), num_suggestions: suggestions.len(),
suggestions: DiagArgValue::StrListSepByAnd( suggestions: DiagArgValue::StrListSepByAnd(
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),

View File

@@ -33,6 +33,7 @@ use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
}; };
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
use crate::attributes::must_use::MustUseParser; use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser; use crate::attributes::non_exhaustive::NonExhaustiveParser;
@@ -126,6 +127,7 @@ attribute_parsers!(
BodyStabilityParser, BodyStabilityParser,
ConfusablesParser, ConfusablesParser,
ConstStabilityParser, ConstStabilityParser,
MacroUseParser,
NakedParser, NakedParser,
StabilityParser, StabilityParser,
UsedParser, UsedParser,
@@ -174,6 +176,7 @@ attribute_parsers!(
Single<WithoutArgs<FfiPureParser>>, Single<WithoutArgs<FfiPureParser>>,
Single<WithoutArgs<FundamentalParser>>, Single<WithoutArgs<FundamentalParser>>,
Single<WithoutArgs<LoopMatchParser>>, Single<WithoutArgs<LoopMatchParser>>,
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>, Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>, Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>, 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 /// 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. /// 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 { pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {

View File

@@ -438,7 +438,7 @@ pub(crate) struct IllFormedAttributeInput {
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_parsing_ill_formed_attribute_input)] #[diag(attr_parsing_ill_formed_attribute_input)]
pub(crate) struct MustUseIllFormedAttributeInput { pub(crate) struct IllFormedAttributeInputLint {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub num_suggestions: usize, 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? /// Should we tell the user to write a list when they didn't?
list: bool, list: bool,
}, },
ExpectedIdentifier,
} }
pub(crate) struct AttributeParseError { pub(crate) struct AttributeParseError {
@@ -600,11 +601,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
diag.code(E0538); diag.code(E0538);
} }
AttributeParseErrorReason::UnexpectedLiteral => { 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); diag.code(E0565);
} }
AttributeParseErrorReason::ExpectedNoArgs => { 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); diag.code(E0565);
} }
AttributeParseErrorReason::ExpectedNameValue(None) => { 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); let suggestions = self.template.suggestions(false, &name);

View File

@@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute {
// FIXME: should not be needed anymore when all attrs are parsed // FIXME: should not be needed anymore when all attrs are parsed
Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span,
Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, Attribute::Parsed(AttributeKind::MayDangle(span)) => *span,
Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span,
Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span,

View File

@@ -303,6 +303,8 @@ pub fn check_builtin_meta_item(
| sym::cold | sym::cold
| sym::target_feature | sym::target_feature
| sym::rustc_allow_const_fn_unstable | sym::rustc_allow_const_fn_unstable
| sym::macro_use
| sym::macro_escape
| sym::naked | sym::naked
| sym::no_mangle | sym::no_mangle
| sym::non_exhaustive | sym::non_exhaustive

View File

@@ -227,6 +227,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => {
self.check_link_section(hir_id, *attr_span, span, target) 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)) => { Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
self.check_naked(hir_id, *attr_span, span, target) 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_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target),
[sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
[sym::link, ..] => self.check_link(hir_id, 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::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod),
[sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
[sym::should_panic, ..] => { [sym::should_panic, ..] => {
@@ -2411,17 +2414,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
} }
fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { fn check_macro_use(&self, hir_id: HirId, name: Symbol, attr_span: Span, target: Target) {
let Some(name) = attr.name() else {
return;
};
match target { match target {
Target::ExternCrate | Target::Mod => {} Target::ExternCrate | Target::Mod => {}
_ => { _ => {
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES, UNUSED_ATTRIBUTES,
hir_id, hir_id,
attr.span(), attr_span,
errors::MacroUse { name }, errors::MacroUse { name },
); );
} }
@@ -2474,7 +2474,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// Warn on useless empty attributes. // Warn on useless empty attributes.
// FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute`
let note = if attr.has_any_name(&[ let note = if attr.has_any_name(&[
sym::macro_use,
sym::allow, sym::allow,
sym::expect, sym::expect,
sym::warn, sym::warn,

View File

@@ -41,8 +41,6 @@ resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
resolve_attributes_starting_with_rustc_are_reserved = resolve_attributes_starting_with_rustc_are_reserved =
attributes starting with `rustc` are reserved for use by the `rustc` compiler attributes starting with `rustc` are reserved for use by the `rustc` compiler
resolve_bad_macro_import = bad macro import
resolve_binding_in_never_pattern = resolve_binding_in_never_pattern =
never patterns cannot contain variable bindings never patterns cannot contain variable bindings
.suggestion = use a wildcard `_` instead .suggestion = use a wildcard `_` instead

View File

@@ -11,11 +11,14 @@ use std::sync::Arc;
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
use rustc_ast::{ use rustc_ast::{
self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, 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 as attr;
use rustc_attr_parsing::AttributeParser;
use rustc_expand::base::ResolverExpand; use rustc_expand::base::ResolverExpand;
use rustc_expand::expand::AstFragment; use rustc_expand::expand::AstFragment;
use rustc_hir::Attribute;
use rustc_hir::def::{self, *}; use rustc_hir::def::{self, *};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_index::bit_set::DenseBitSet; use rustc_index::bit_set::DenseBitSet;
@@ -25,6 +28,7 @@ use rustc_middle::metadata::ModChild;
use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::ty::{Feed, Visibility};
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
use rustc_span::{Ident, Span, Symbol, kw, sym}; use rustc_span::{Ident, Span, Symbol, kw, sym};
use thin_vec::ThinVec;
use tracing::debug; use tracing::debug;
use crate::Namespace::{MacroNS, TypeNS, ValueNS}; 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. /// 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 { fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> bool {
let mut import_all = None; let mut import_all = None;
let mut single_imports = Vec::new(); let mut single_imports = ThinVec::new();
for attr in &item.attrs { if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) =
if attr.has_name(sym::macro_use) { 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() { if self.parent_scope.module.parent.is_some() {
self.r.dcx().emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { self.r
span: item.span, .dcx()
}); .emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { span: item.span });
} }
if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind if let ItemKind::ExternCrate(Some(orig_name), _) = item.kind
&& orig_name == kw::SelfLower && orig_name == kw::SelfLower
{ {
self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { 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),
} }
match arguments {
MacroUseArgs::UseAll => import_all = Some(span),
MacroUseArgs::UseSpecific(imports) => single_imports = imports,
} }
} }

View File

@@ -815,13 +815,6 @@ pub(crate) struct ExternCrateLoadingMacroNotAtCrateRoot {
pub(crate) span: Span, pub(crate) span: Span,
} }
#[derive(Diagnostic)]
#[diag(resolve_bad_macro_import, code = E0466)]
pub(crate) struct BadMacroImport {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(resolve_extern_crate_self_requires_renaming)] #[diag(resolve_extern_crate_self_requires_renaming)]
pub(crate) struct ExternCrateSelfRequiresRenaming { pub(crate) struct ExternCrateSelfRequiresRenaming {

View File

@@ -7,8 +7,9 @@ use rustc_hir::{self as hir, AmbigArg};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::{Span, sym}; use rustc_span::{Span};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use rustc_attr_data_structures::{AttributeKind, find_attr};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -99,15 +100,14 @@ impl LateLintPass<'_> for MacroUseImports {
&& let hir::ItemKind::Use(path, _kind) = &item.kind && let hir::ItemKind::Use(path, _kind) = &item.kind
&& let hir_id = item.hir_id() && let hir_id = item.hir_id()
&& let attrs = cx.tcx.hir_attrs(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 && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns
&& !id.is_local() && !id.is_local()
{ {
for kid in cx.tcx.module_children(id) { for kid in cx.tcx.module_children(id) {
if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { 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); 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() { } else if item.span.from_expansion() {