Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3586,6 +3586,7 @@ dependencies = [
"rustc_feature",
"rustc_hir",
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_parse",
"rustc_parse_format",
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -220,7 +219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
attribute_parser: AttributeParser::new(
tcx.sess,
tcx.features(),
registered_tools,
tcx.registered_tools(()),
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
),
delayed_lints: Vec::new(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov May 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this crate already depends on rustc_lint_defs indirectly through rustc_errors, so this is ok.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it doesn't matter but it feels somewhat silly when RegisteredTools is just a type alias.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it doesn't matter but it feels somewhat silly when RegisteredTools is just a type alias.

I think it's worth it for more consistency and to avoid confusion

rustc_macros = { path = "../rustc_macros" }
rustc_parse = { path = "../rustc_parse" }
rustc_parse_format = { path = "../rustc_parse_format" }
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,18 @@ impl AttributeParser for NakedParser {

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;
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
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};
Expand All @@ -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<Symbol>,
pub(crate) tools: Option<&'sess RegisteredTools>,
pub(crate) features: Option<&'sess Features>,
pub(crate) sess: &'sess Session,
pub(crate) should_emit: ShouldEmit,
Expand All @@ -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],
Expand All @@ -79,6 +82,8 @@ impl<'sess> AttributeParser<'sess> {

/// 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],
Expand All @@ -98,6 +103,7 @@ impl<'sess> AttributeParser<'sess> {
target_node_id,
features,
should_emit,
None,
);
assert!(parsed.len() <= 1);
parsed.pop()
Expand All @@ -119,8 +125,9 @@ impl<'sess> AttributeParser<'sess> {
target_node_id: NodeId,
features: Option<&'sess Features>,
should_emit: ShouldEmit,
tools: Option<&'sess RegisteredTools>,
) -> Vec<Attribute> {
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,
Expand Down Expand Up @@ -202,7 +209,7 @@ impl<'sess> AttributeParser<'sess> {
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)
};
Expand Down Expand Up @@ -237,10 +244,10 @@ impl<'sess> AttributeParser<'sess> {
pub fn new(
sess: &'sess Session,
features: &'sess Features,
tools: Vec<Symbol>,
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 {
Expand Down Expand Up @@ -432,12 +439,13 @@ impl<'sess> AttributeParser<'sess> {

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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
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 };
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
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(
Expand Down
Loading