Rollup merge of #145788 - JonathanBrouwer:proper-fix-for-macro-call-target, r=jdonszelmann

Fix attribute target checking for macro calls

Fixes https://github.com/rust-lang/rust/issues/145779

r? `@jdonszelmann`
This commit is contained in:
Stuart Cook
2025-08-25 19:52:20 +10:00
committed by GitHub
14 changed files with 337 additions and 59 deletions

View File

@@ -127,6 +127,7 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
Warn(Target::Field),
Warn(Target::Arm),
Warn(Target::MacroDef),
Warn(Target::MacroCall),
]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
@@ -174,6 +175,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
Warn(Target::MacroCall),
]);
fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -278,6 +280,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
Warn(Target::MacroDef),
Warn(Target::Arm),
Warn(Target::Field),
Warn(Target::MacroCall),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
}
@@ -365,7 +368,8 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
}
},
)];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
// Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker`
@@ -450,6 +454,7 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
Warn(Target::Field),
Warn(Target::Arm),
Warn(Target::MacroDef),
Warn(Target::MacroCall),
]);
}

View File

@@ -25,6 +25,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
Warn(Target::MacroDef),
Warn(Target::Arm),
Warn(Target::AssocConst),
Warn(Target::MacroCall),
]);
const TEMPLATE: AttributeTemplate = template!(
Word,

View File

@@ -110,8 +110,11 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
const PATH: &[Symbol] = &[sym::link_ordinal];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),
Warn(Target::MacroCall),
]);
const TEMPLATE: AttributeTemplate = template!(
List: &["ordinal"],
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"

View File

@@ -19,6 +19,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
Warn(Target::Field),
Warn(Target::Arm),
Warn(Target::MacroDef),
Warn(Target::MacroCall),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;
}

View File

@@ -1,11 +1,13 @@
use super::prelude::*;
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate), Warn(Target::MacroCall)]);
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 ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
}
@@ -13,8 +15,7 @@ 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 ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
}
@@ -23,8 +24,7 @@ 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 ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]);
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"

View File

@@ -41,8 +41,14 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
.emit_node_span_lint(
// This check is here because `deprecated` had its own lint group and removing this would be a breaking change
if name.segments[0].name == sym::deprecated
&& ![Target::Closure, Target::Expression, Target::Statement, Target::Arm]
.contains(target)
&& ![
Target::Closure,
Target::Expression,
Target::Statement,
Target::Arm,
Target::MacroCall,
]
.contains(target)
{
rustc_session::lint::builtin::USELESS_DEPRECATED
} else {

View File

@@ -7,12 +7,12 @@ use rustc_ast::mut_visit::*;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
use rustc_ast::{
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, CRATE_NODE_ID,
DUMMY_NODE_ID, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle,
MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID,
ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner,
MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::{AttributeParser, EvalConfigResult, ShouldEmit, validate_attr};
use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::PResult;
@@ -2165,7 +2165,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
None,
Target::MacroCall,
call.span(),
CRATE_NODE_ID,
self.cx.current_expansion.lint_node_id,
Some(self.cx.ecfg.features),
ShouldEmit::ErrorsAndLints,
);
@@ -2184,7 +2184,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.cx.current_expansion.lint_node_id,
BuiltinLintDiag::UnusedDocComment(attr.span),
);
} else if rustc_attr_parsing::is_builtin_attr(attr) {
} else if rustc_attr_parsing::is_builtin_attr(attr)
&& !AttributeParser::<Early>::is_parsed_attribute(&attr.path())
{
let attr_name = attr.ident().unwrap().name;
// `#[cfg]` and `#[cfg_attr]` are special - they are
// eagerly evaluated.