From 76fd1b3df32b4e81f94e5cb609eddd6ecbd992f7 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 4 Mar 2026 11:06:15 +0100 Subject: [PATCH] make tools on `AttributeParser` hold reference to `RegisteredTools` --- Cargo.lock | 1 + compiler/rustc_ast_lowering/src/lib.rs | 3 +-- compiler/rustc_attr_parsing/Cargo.toml | 1 + .../src/attributes/codegen_attrs.rs | 10 ++++++++- compiler/rustc_attr_parsing/src/interface.rs | 22 +++++++++++++------ compiler/rustc_expand/src/expand.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 2 +- 7 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b5491fb754d..4648a12da487 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3586,6 +3586,7 @@ dependencies = [ "rustc_feature", "rustc_hir", "rustc_lexer", + "rustc_lint_defs", "rustc_macros", "rustc_parse", "rustc_parse_format", diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 49790c2da6de..4783f63fa006 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -164,7 +164,6 @@ struct LoweringContext<'a, 'hir> { impl<'a, 'hir> LoweringContext<'a, 'hir> { fn new(tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>) -> Self { - let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { tcx, resolver, @@ -220,7 +219,7 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>) -> Self { attribute_parser: AttributeParser::new( tcx.sess, tcx.features(), - registered_tools, + tcx.registered_tools(()), ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, ), delayed_lints: Vec::new(), diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index fc83c3b6e9bc..fccc36a12805 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_parse_format = { path = "../rustc_parse_format" } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a6cf25330b55..94ced2251fc1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -265,10 +265,18 @@ fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option { let span = self.span?; + let Some(tools) = cx.tools else { + unreachable!("tools required while parsing attributes"); + }; + // only if we found a naked attribute do we do the somewhat expensive check 'outer: for other_attr in cx.all_attrs { for allowed_attr in ALLOW_LIST { - if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) { + if other_attr + .segments() + .next() + .is_some_and(|i| tools.iter().any(|tool| tool.name == i.name)) + { // effectively skips the error message being emitted below // if it's a tool attribute continue 'outer; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 567cdc7701ea..826066385034 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -8,6 +8,7 @@ use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; +use rustc_lint_defs::RegisteredTools; use rustc_session::Session; use rustc_session::lint::LintId; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -33,7 +34,7 @@ pub struct EmitAttribute( /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess> { - pub(crate) tools: Vec, + pub(crate) tools: Option<&'sess RegisteredTools>, pub(crate) features: Option<&'sess Features>, pub(crate) sess: &'sess Session, pub(crate) should_emit: ShouldEmit, @@ -59,6 +60,8 @@ impl<'sess> AttributeParser<'sess> { /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors + /// + /// Due to this function not taking in RegisteredTools, *do not* use this for parsing any lint attributes pub fn parse_limited( sess: &'sess Session, attrs: &[ast::Attribute], @@ -79,6 +82,8 @@ pub fn parse_limited( /// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors. /// Usually you want `parse_limited`, which emits no errors. + /// + /// Due to this function not taking in RegisteredTools, *do not* use this for parsing any lint attributes pub fn parse_limited_should_emit( sess: &'sess Session, attrs: &[ast::Attribute], @@ -98,6 +103,7 @@ pub fn parse_limited_should_emit( target_node_id, features, should_emit, + None, ); assert!(parsed.len() <= 1); parsed.pop() @@ -119,8 +125,9 @@ pub fn parse_limited_all( target_node_id: NodeId, features: Option<&'sess Features>, should_emit: ShouldEmit, + tools: Option<&'sess RegisteredTools>, ) -> Vec { - let mut p = Self { features, tools: Vec::new(), parse_only, sess, should_emit }; + let mut p = Self { features, tools, parse_only, sess, should_emit }; p.parse_attribute_list( attrs, target_span, @@ -202,7 +209,7 @@ pub fn parse_single_args( parse_fn: fn(cx: &mut AcceptContext<'_, '_>, item: &I) -> T, template: &AttributeTemplate, ) -> T { - let mut parser = Self { features, tools: Vec::new(), parse_only: None, sess, should_emit }; + let mut parser = Self { features, tools: None, parse_only: None, sess, should_emit }; let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) }; @@ -237,10 +244,10 @@ impl<'sess> AttributeParser<'sess> { pub fn new( sess: &'sess Session, features: &'sess Features, - tools: Vec, + tools: &'sess RegisteredTools, should_emit: ShouldEmit, ) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, should_emit } + Self { features: Some(features), tools: Some(tools), parse_only: None, sess, should_emit } } pub(crate) fn sess(&self) -> &'sess Session { @@ -432,12 +439,13 @@ pub fn parse_attribute_list( let attr = Attribute::Unparsed(Box::new(attr)); - if self.tools.contains(&parts[0]) + if self.tools.is_some_and(|tools| { + tools.iter().any(|tool| tool.name == parts[0]) // FIXME: this can be removed once #152369 has been merged. // https://github.com/rust-lang/rust/pull/152369 || [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn] .contains(&parts[0]) - { + }) { attributes.push(attr); } else { dropped_attributes.push(attr); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 2bb6c43f3dd6..b6611e7e0ca0 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2250,6 +2250,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { self.cx.current_expansion.lint_node_id, Some(self.cx.ecfg.features), ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, + Some(self.cx.resolver.registered_tools()), ); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 90c385ef6f5a..0040ddbf5e24 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -149,7 +149,7 @@ fn visit_item(&mut self, i: &'a Item) { let mut parser = AttributeParser::new( &self.r.tcx.sess, self.r.tcx.features(), - Vec::new(), + self.r.tcx().registered_tools(()), ShouldEmit::Nothing, ); let attrs = parser.parse_attribute_list(