Ports #[macro_use] and #[macro_escape] to the new attribute parsing infrastructure
This commit is contained in:
@@ -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),
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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.
|
||||||
///
|
///
|
||||||
|
|||||||
115
compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Normal file
115
compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Normal 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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user