Skip to content
Draft
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
11 changes: 2 additions & 9 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_hir::Attribute;
use rustc_hir::attrs::AttributeKind;
use rustc_session::Session;
use rustc_session::parse::{feature_err, feature_warn};
use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym};
use rustc_span::{Span, Spanned, Symbol, sym};
use thin_vec::ThinVec;

use crate::errors;
Expand Down Expand Up @@ -646,14 +646,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
let mut errored = false;

if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
AttributeParser::parse_limited(
sess,
&krate.attrs,
&[sym::feature],
DUMMY_SP,
krate.id,
Some(&features),
)
AttributeParser::parse_limited(sess, &krate.attrs, &[sym::feature])
{
// `feature(...)` used on non-nightly. This is definitely an error.
let mut err = errors::FeatureOnNonNightly {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ impl OnUnknownParser {
args: &ArgParser,
mode: Mode,
) {
if !cx.features().diagnostic_on_unknown() {
if let Some(features) = cx.features
&& !features.diagnostic_on_unknown()
{
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
return;
}
Copy link
Copy Markdown
Contributor

@mejrs mejrs Apr 17, 2026

Choose a reason for hiding this comment

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

There are a couple of rustc_resolve types that have a pub on_unknown_attr: Option<OnUnknownData> field.

This change makes it so they can be Some even if the feature is not used. The reason you aren't noticing it is because of this check at the use site:

let (message, label, notes) = if self.tcx.features().diagnostic_on_unknown()
&& let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive)
{

I'm on the fence whether it's worth the effort to "fix" this. But I would like some comments here and there to document whatever we end up with.

View changes since the review

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
if let Some(pa) = T::convert(cx, args) {
if let Some((_, used)) = group.1 {
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
} else {
group.1 = Some((pa, cx.attr_span));
}

group.1 = Some((pa, cx.attr_span));
}
},
)];
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::convert::identity;

use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety};
use rustc_errors::{DiagCtxtHandle, MultiSpan};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
Expand Down Expand Up @@ -52,18 +52,16 @@ impl<'sess> AttributeParser<'sess, Early> {
sess: &'sess Session,
attrs: &[ast::Attribute],
sym: &'static [Symbol],
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
) -> Option<Attribute> {
Self::parse_limited_should_emit(
sess,
attrs,
sym,
target_span,
target_node_id,
Target::Crate, // Does not matter, we're not going to emit errors anyways
features,
// Because we're not emitting warnings/errors, the target should not matter
DUMMY_SP,
CRATE_NODE_ID,
Target::Crate,
None,
ShouldEmit::Nothing,
)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ impl<'a> TraitDef<'a> {
match item {
Annotatable::Item(item) => {
let is_packed = matches!(
AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr], item.span, item.id, None),
AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr]),
Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
);

Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_builtin_macros/src/proc_macro_harness.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{mem, slice};

use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
use rustc_ast::{self as ast, NodeId, attr};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::DiagCtxtHandle;
Expand Down Expand Up @@ -109,9 +109,6 @@ impl<'a> CollectProcMacros<'a> {
self.session,
slice::from_ref(attr),
&[sym::proc_macro_derive],
item.span,
item.node_id(),
None,
)
else {
return;
Expand Down
11 changes: 2 additions & 9 deletions compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::{assert_matches, iter};

use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, Diag, Level};
Expand Down Expand Up @@ -480,14 +480,7 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {

fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) =
AttributeParser::parse_limited(
cx.sess,
&i.attrs,
&[sym::should_panic],
i.span,
i.node_id(),
None,
)
AttributeParser::parse_limited(cx.sess, &i.attrs, &[sym::should_panic])
{
ShouldPanic::Yes(reason)
} else {
Expand Down
13 changes: 3 additions & 10 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn inject(

// Do this here so that the test_runner crate attribute gets marked as used
// even in non-test builds
let test_runner = get_test_runner(sess, features, krate);
let test_runner = get_test_runner(sess, krate);

if sess.is_test_crate() {
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
Expand Down Expand Up @@ -387,15 +387,8 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> {
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
}

fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> Option<ast::Path> {
match AttributeParser::parse_limited(
sess,
&krate.attrs,
&[sym::test_runner],
krate.spans.inner_span,
krate.id,
Some(features),
) {
fn get_test_runner(sess: &Session, krate: &ast::Crate) -> Option<ast::Path> {
match AttributeParser::parse_limited(sess, &krate.attrs, &[sym::test_runner]) {
Some(rustc_hir::Attribute::Parsed(AttributeKind::TestRunner(path))) => Some(path),
_ => None,
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,8 +712,7 @@ fn print_crate_info(
let crate_name = passes::get_crate_name(sess, attrs);
let lint_store = crate::unerased_lint_store(sess);
let features = rustc_expand::config::features(sess, attrs, crate_name);
let registered_tools =
rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess, &features);
let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess);
let lint_levels = rustc_lint::LintLevelsBuilder::crate_root(
sess,
&features,
Expand Down
15 changes: 4 additions & 11 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
};
use rustc_ast::{
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute,
HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs,
HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
};
use rustc_attr_parsing::parser::AllowExprMetavar;
use rustc_attr_parsing::{
Expand All @@ -28,7 +28,7 @@ use rustc_hir::{
use rustc_parse::parser::Recovery;
use rustc_session::Session;
use rustc_session::parse::feature_err;
use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
use tracing::instrument;

use crate::errors::{
Expand All @@ -51,14 +51,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
let mut features = Features::default();

if let Some(hir::Attribute::Parsed(AttributeKind::Feature(feature_idents, _))) =
AttributeParser::parse_limited(
sess,
krate_attrs,
&[sym::feature],
DUMMY_SP,
DUMMY_NODE_ID,
Some(&features),
)
AttributeParser::parse_limited(sess, krate_attrs, &[sym::feature])
{
for feature_ident in feature_idents {
// If the enabled feature has been removed, issue an error.
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,6 @@ impl EarlyLintPass for UnsafeCode {
cx.builder.sess(),
&it.attrs,
&[sym::allow_internal_unsafe],
it.span,
DUMMY_NODE_ID,
Some(cx.builder.features()),
)
{
self.report_unsafe(cx, span, BuiltinUnsafe::AllowInternalUnsafe);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/nonstandard_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl NonCamelCaseTypes {
impl EarlyLintPass for NonCamelCaseTypes {
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
let has_repr_c = matches!(
AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr], it.span, it.id, None),
AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr]),
Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
);

Expand Down
25 changes: 6 additions & 19 deletions compiler/rustc_passes/src/debugger_visualizer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Detecting usage of the `#[debugger_visualizer]` attribute.

use rustc_ast::ast::NodeId;
use rustc_ast::{HasNodeId, ItemKind, ast};
use rustc_ast::{ItemKind, ast};
use rustc_attr_parsing::AttributeParser;
use rustc_expand::base::resolve_path;
use rustc_hir::Attribute;
Expand All @@ -10,26 +9,14 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::{DUMMY_SP, Span, sym};
use rustc_span::sym;

use crate::errors::DebugVisualizerUnreadable;

impl DebuggerVisualizerCollector<'_> {
fn check_for_debugger_visualizer(
&mut self,
attrs: &[ast::Attribute],
span: Span,
node_id: NodeId,
) {
fn check_for_debugger_visualizer(&mut self, attrs: &[ast::Attribute]) {
if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
AttributeParser::parse_limited(
&self.sess,
attrs,
&[sym::debugger_visualizer],
span,
node_id,
None,
)
AttributeParser::parse_limited(&self.sess, attrs, &[sym::debugger_visualizer])
{
for DebugVisualizer { span, visualizer_type, path } in visualizers {
let file = match resolve_path(&self.sess, path.as_str(), span) {
Expand Down Expand Up @@ -69,12 +56,12 @@ struct DebuggerVisualizerCollector<'a> {
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
if let ItemKind::Mod(..) = item.kind {
self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
self.check_for_debugger_visualizer(&item.attrs);
}
rustc_ast::visit::walk_item(self, item);
}
fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
self.check_for_debugger_visualizer(&krate.attrs);
rustc_ast::visit::walk_crate(self, krate);
}
}
Expand Down
9 changes: 1 addition & 8 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,14 +1123,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
let mut import_all = None;
let mut single_imports = ThinVec::new();
if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) =
AttributeParser::parse_limited(
self.r.tcx.sess,
&item.attrs,
&[sym::macro_use],
item.span,
item.id,
None,
)
AttributeParser::parse_limited(self.r.tcx.sess, &item.attrs, &[sym::macro_use])
{
if self.parent_scope.module.parent.is_some() {
self.r
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,6 @@ impl OnUnknownData {
tcx.sess,
&item.attrs,
&[sym::diagnostic, sym::on_unknown],
item.span,
item.id,
Some(tcx.features()),
)
{
Some(Self { directive: Box::new(*directive?) })
Expand Down
15 changes: 3 additions & 12 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use std::mem;
use std::sync::Arc;

use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId};
use rustc_ast::{self as ast, Crate, DelegationSuffixes, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
Expand All @@ -16,7 +16,6 @@ use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{
AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
};
use rustc_feature::Features;
use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem};
use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
Expand Down Expand Up @@ -123,26 +122,18 @@ fn fast_print_path(path: &ast::Path) -> Symbol {

pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow();
registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess, tcx.features())
registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess)
}

pub fn registered_tools_ast(
dcx: DiagCtxtHandle<'_>,
pre_configured_attrs: &[ast::Attribute],
sess: &Session,
features: &Features,
) -> RegisteredTools {
let mut registered_tools = RegisteredTools::default();

if let Some(Attribute::Parsed(AttributeKind::RegisterTool(tools, _))) =
AttributeParser::parse_limited(
sess,
pre_configured_attrs,
&[sym::register_tool],
DUMMY_SP,
DUMMY_NODE_ID,
Some(features),
)
AttributeParser::parse_limited(sess, pre_configured_attrs, &[sym::register_tool])
{
for tool in tools {
if let Some(old_tool) = registered_tools.replace(tool) {
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/attributes/attr-order-deprecated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[deprecated = "AAA"]
//~^ NOTE also specified here
#[deprecated = "BBB"]
//~^ ERROR multiple `deprecated` attributes
fn deprecated() { }

fn main() {
deprecated();
//~^ WARN use of deprecated function `deprecated`: AAA [deprecated]
//~| NOTE `#[warn(deprecated)]` on by default
}
22 changes: 22 additions & 0 deletions tests/ui/attributes/attr-order-deprecated.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error: multiple `deprecated` attributes
--> $DIR/attr-order-deprecated.rs:3:1
|
LL | #[deprecated = "BBB"]
| ^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/attr-order-deprecated.rs:1:1
|
LL | #[deprecated = "AAA"]
| ^^^^^^^^^^^^^^^^^^^^^

warning: use of deprecated function `deprecated`: AAA
--> $DIR/attr-order-deprecated.rs:8:5
|
LL | deprecated();
| ^^^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default

error: aborting due to 1 previous error; 1 warning emitted

Loading
Loading