Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn parse_unstable(

for param in list.mixed() {
let param_span = param.span();
if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) {
if let Some(ident) = param.meta_item_no_args().and_then(|i| i.path().word()) {
res.push(ident.name);
} else {
cx.emit_err(session_diagnostics::ExpectsFeatures {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl SingleAttributeParser for OptimizeParser {
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
let single = cx.expect_single_element_list(args, cx.attr_span)?;

let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
let res = match single.meta_item_no_args().and_then(|i| i.path().word().map(|i| i.name)) {
Some(sym::size) => OptimizeAttr::Size,
Some(sym::speed) => OptimizeAttr::Speed,
Some(sym::none) => OptimizeAttr::DoNotOptimize,
Expand Down Expand Up @@ -80,7 +80,7 @@ impl SingleAttributeParser for CoverageParser {
let mut fail_incorrect_argument =
|span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);

let Some(arg) = arg.meta_item() else {
let Some(arg) = arg.meta_item_no_args() else {
fail_incorrect_argument(arg.span());
return None;
};
Expand Down Expand Up @@ -375,7 +375,7 @@ impl AttributeParser for UsedParser {
return;
};

match l.meta_item().and_then(|i| i.path().word_sym()) {
match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
Some(sym::compiler) => {
if !cx.features().used_with_arg() {
feature_err(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl AttributeParser for OnConstParser {
|this, cx, args| {
if !cx.features().diagnostic_on_const() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
args.ignore_args();
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ impl OnMoveParser {
fn parse<'sess>(&mut self, cx: &mut AcceptContext<'_, 'sess>, args: &ArgParser, mode: Mode) {
if !cx.features().diagnostic_on_move() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
args.ignore_args();
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ impl OnUnknownParser {
&& !features.diagnostic_on_unknown()
{
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
args.ignore_args();
return;
}
let span = cx.attr_span;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ impl DocParser {

// FIXME: convert list into a Vec of `AttributeKind` because current code is awful.
for attr in list.mixed() {
// Arguments of `attr` are checked via the span, so can be safely ignored
attr.ignore_args();
self.attribute.test_attrs.push(attr.span());
}
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ impl SingleAttributeParser for RustcDummyParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really

fn convert(_: &mut AcceptContext<'_, '_>, _: &ArgParser) -> Option<AttributeKind> {
fn convert(_: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
args.ignore_args();
Some(AttributeKind::RustcDummy)
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl SingleAttributeParser for InlineParser {
ArgParser::List(list) => {
let l = cx.expect_single(list)?;

match l.meta_item().and_then(|i| i.path().word_sym()) {
match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
Some(sym::always) => {
Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl SingleAttributeParser for InstructionSetParser {
const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
let maybe_meta_item = cx.expect_single_element_list(args, cx.attr_span)?;

let Some(meta_item) = maybe_meta_item.meta_item() else {
let Some(meta_item) = maybe_meta_item.meta_item_no_args() else {
cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
return None;
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ impl SingleAttributeParser for MacroExportParser {
cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
return None;
};
match l.meta_item().and_then(|i| i.path().word_sym()) {
match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
Some(sym::local_inner_macros) => true,
_ => {
cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl CombineAttributeParser for RustcDumpLayoutParser {

let mut result = Vec::new();
for item in items.mixed() {
let Some(arg) = item.meta_item() else {
let Some(arg) = item.meta_item_no_args() else {
cx.adcx().expected_not_literal(item.span());
continue;
};
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser {

let mut errored = false;
for argument in inputs {
let Some(meta) = argument.meta_item() else {
let Some(meta) = argument.meta_item_no_args() else {
cx.adcx().expected_identifier(argument.span());
return None;
};
Expand Down Expand Up @@ -906,7 +906,7 @@ impl SingleAttributeParser for RustcIfThisChangedParser {
ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),
ArgParser::List(list) => {
let item = cx.expect_single(list)?;
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {
cx.adcx().expected_identifier(item.span());
return None;
};
Expand Down Expand Up @@ -964,7 +964,7 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser {
cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
}
let item = cx.expect_single_element_list(args, cx.attr_span)?;
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {
cx.adcx().expected_identifier(item.span());
return None;
};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl SingleAttributeParser for RustcAbiParser {
let mut fail_incorrect_argument =
|span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]);

let Some(arg) = arg.meta_item() else {
let Some(arg) = arg.meta_item_no_args() else {
fail_incorrect_argument(args.span);
return None;
};
Expand Down Expand Up @@ -199,7 +199,7 @@ impl SingleAttributeParser for TestRunnerParser {
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
let single = cx.expect_single_element_list(args, cx.attr_span)?;

let Some(meta) = single.meta_item() else {
let Some(meta) = single.meta_item_no_args() else {
cx.adcx().expected_not_literal(single.span());
return None;
};
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::collections::btree_map::Entry;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::LazyLock;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicBool, Ordering};

use rustc_ast::{AttrStyle, MetaItemLit};
use rustc_data_structures::sync::{DynSend, DynSync};
Expand Down Expand Up @@ -403,6 +405,8 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> {
kind: EmitAttribute,
span: impl Into<MultiSpan>,
) {
#[cfg(debug_assertions)]
self.has_lint_been_emitted.store(true, Ordering::Relaxed);
if !matches!(
self.should_emit,
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
Expand Down Expand Up @@ -556,6 +560,11 @@ pub struct SharedContext<'p, 'sess> {
pub(crate) target: rustc_hir::Target,

pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute),

/// This atomic bool keeps track of whether any lint has been emitted.
/// This is used for the arguments-used check.
#[cfg(debug_assertions)]
pub(crate) has_lint_been_emitted: AtomicBool,
}

/// Context given to every attribute parser during finalization.
Expand Down
39 changes: 38 additions & 1 deletion compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::convert::identity;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicBool, Ordering};

use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
Expand Down Expand Up @@ -221,6 +223,8 @@ impl<'sess> AttributeParser<'sess> {
target_span,
target,
emit_lint: &mut emit_lint,
#[cfg(debug_assertions)]
has_lint_been_emitted: AtomicBool::new(false),
},
attr_span,
inner_span,
Expand Down Expand Up @@ -391,6 +395,8 @@ impl<'sess> AttributeParser<'sess> {
target_span,
target,
emit_lint: &mut emit_lint,
#[cfg(debug_assertions)]
has_lint_been_emitted: AtomicBool::new(false),
},
attr_span,
inner_span: lower_span(n.item.span()),
Expand All @@ -403,6 +409,10 @@ impl<'sess> AttributeParser<'sess> {
(accept.accept_fn)(&mut cx, &args);
finalizers.push(accept.finalizer);

#[cfg(debug_assertions)]
if !cx.shared.has_lint_been_emitted.load(Ordering::Relaxed) {
cx.shared.cx.check_args_used(&attr, &args)
}
if !matches!(cx.should_emit, ShouldEmit::Nothing) {
Self::check_target(&accept.allowed_targets, target, &mut cx);
}
Expand Down Expand Up @@ -450,7 +460,14 @@ impl<'sess> AttributeParser<'sess> {
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
for f in &finalizers {
if let Some(attr) = f(&mut FinalizeContext {
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
shared: SharedContext {
cx: self,
target_span,
target,
emit_lint: &mut emit_lint,
#[cfg(debug_assertions)]
has_lint_been_emitted: AtomicBool::new(false),
},
all_attrs: &attr_paths,
}) {
attributes.push(Attribute::Parsed(attr));
Expand All @@ -464,6 +481,26 @@ impl<'sess> AttributeParser<'sess> {
attributes
}

#[cfg(debug_assertions)]
/// Checks whether all `ArgParser`s were observed by an attribute parser at least once
/// This check exists because otherwise it is too easy to accidentally ignore the arguments of an attribute
fn check_args_used(&self, attr: &ast::Attribute, args: &ArgParser) {
if let ArgParser::List(items) = args {
for item in items.mixed() {
if let crate::parser::MetaItemOrLitParser::MetaItemParser(item) = item {
if !item.are_args_checked() {
self.dcx().span_delayed_bug(
item.span(),
"attribute args were not properly checked",
);
return;
}
self.check_args_used(attr, item.args());
}
}
}
}

/// Returns whether there is a parser for an attribute with this name
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
/// The list of attributes that are parsed attributes,
Expand Down
Loading
Loading