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
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

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've moved the feature gating to the initialization of on_unknown_attr, and added some comments

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_data_structures::sync::{DynSend, DynSync};
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
use rustc_feature::{AttributeTemplate, Features};
Expand Down Expand Up @@ -62,18 +62,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 @@ -1127,14 +1127,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
54 changes: 27 additions & 27 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,15 @@ pub(crate) struct OnUnknownData {

impl OnUnknownData {
pub(crate) fn from_attrs<'tcx>(tcx: TyCtxt<'tcx>, item: &Item) -> Option<OnUnknownData> {
if let Some(Attribute::Parsed(AttributeKind::OnUnknown { directive, .. })) =
AttributeParser::parse_limited(
tcx.sess,
&item.attrs,
&[sym::diagnostic, sym::on_unknown],
item.span,
item.id,
Some(tcx.features()),
)
if tcx.features().diagnostic_on_unknown()
&& let Some(Attribute::Parsed(AttributeKind::OnUnknown { directive, .. })) =
AttributeParser::parse_limited(
tcx.sess,
&item.attrs,
&[sym::diagnostic, sym::on_unknown],
)
Comment thread
JonathanBrouwer marked this conversation as resolved.
{
Some(Self { directive: Box::new(*directive?) })
Some(Self { directive: directive? })
} else {
None
}
Expand Down Expand Up @@ -216,6 +214,8 @@ pub(crate) struct ImportData<'ra> {
/// A `#[diagnostic::on_unknown]` attribute applied
/// to the given import. This allows crates to specify
/// custom error messages for a specific import
///
/// This is `None` if the feature flag for `diagnostic::on_unknown` is disabled.
pub on_unknown_attr: Option<OnUnknownData>,
}

Expand Down Expand Up @@ -845,24 +845,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
.collect::<Vec<_>>();
let default_message =
format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
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)
{
let args = FormatArgs {
this: paths.join(", "),
// Unused
this_sugared: String::new(),
// Unused
item_context: "",
// Unused
generic_args: Vec::new(),
};
let CustomDiagnostic { message, label, notes, .. } = directive.eval(None, &args);
let (message, label, notes) =
// Feature gating for `on_unknown_attr` happens initialization of the field
if let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive) {
let args = FormatArgs {
this: paths.join(", "),
// Unused
this_sugared: String::new(),
// Unused
item_context: "",
// Unused
generic_args: Vec::new(),
};
let CustomDiagnostic { message, label, notes, .. } = directive.eval(None, &args);

(message, label, notes)
} else {
(None, None, Vec::new())
};
(message, label, notes)
} else {
(None, None, Vec::new())
};
let has_custom_message = message.is_some();
let message = message.as_deref().unwrap_or(default_message.as_str());

Expand Down
Loading
Loading