diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index e72533fb3c890..05e1557f58b60 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -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 { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 791b9de0f763e..c2f92ebedddcf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -26,7 +26,7 @@ impl SingleAttributeParser for OptimizeParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { 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, @@ -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; }; @@ -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( diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index e6c66b597ce08..b445f23f2202b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -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; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index d4ef92fc9a548..a104f68292fcb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -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; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index 0a9aaaaa1893e..e70a54302fd2f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -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; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 74fee3df0c524..d32a7a1de9491 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -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()); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 622f7e1ceba49..ebf72722c9012 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -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 { + fn convert(_: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { + args.ignore_args(); Some(AttributeKind::RustcDummy) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index a02f0a89cc042..1df3008ff3e50 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -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)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 6f239a8f5761d..a42a77d95c5c0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -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; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 36ee18d5bbe8d..29289c55fdda4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -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); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 1158f1c5acf4c..7d81659ddc580 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -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; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 36acd788b7f1a..7322b78bfa465 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -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; }; @@ -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; }; @@ -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; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 25031784c011a..26c803e366437 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -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; }; @@ -199,7 +199,7 @@ impl SingleAttributeParser for TestRunnerParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { 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; }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 85fff6684ecd1..11ef1d6daa7ba 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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}; @@ -403,6 +405,8 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { kind: EmitAttribute, span: impl Into, ) { + #[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 } @@ -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. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f4506d8d5fedc..5eb1fd617d84b 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -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; @@ -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, @@ -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()), @@ -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); } @@ -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)); @@ -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, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index ce2367006128d..3da0d98cddfa7 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -5,6 +5,8 @@ use std::borrow::Borrow; use std::fmt::{Debug, Display}; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; @@ -87,7 +89,7 @@ impl> Display for PathParser

{ } } -#[derive(Clone, Debug)] +#[derive(Debug)] #[must_use] pub enum ArgParser { NoArgs, @@ -209,13 +211,26 @@ impl ArgParser { Self::NameValue(args) => Err(args.args_span()), } } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + ArgParser::List(list) => { + for item in list.mixed() { + item.ignore_args(); + } + } + _ => {} + } + } } /// Inside lists, values could be either literals, or more deeply nested meta items. /// This enum represents that. /// /// Choose which one you want using the provided methods. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum MetaItemOrLitParser { MetaItemParser(MetaItemParser), Lit(MetaItemLit), @@ -253,6 +268,26 @@ impl MetaItemOrLitParser { MetaItemOrLitParser::Lit(_) => None, } } + + /// Returns some if this `MetaItemOrLitParser` is a `MetaItem` with no arguments + pub fn meta_item_no_args(&self) -> Option<&MetaItemParser> { + let meta_item = self.meta_item()?; + match meta_item.args().no_args() { + Ok(_) => Some(meta_item), + Err(_) => None, + } + } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + #[cfg(debug_assertions)] + match self { + MetaItemOrLitParser::MetaItemParser(meta_item) => { + meta_item.ignore_args(); + } + MetaItemOrLitParser::Lit(_) => {} + } + } } // FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs. @@ -269,10 +304,14 @@ impl MetaItemOrLitParser { /// `= value` part /// /// The syntax of MetaItems can be found at -#[derive(Clone)] pub struct MetaItemParser { path: OwnedPathParser, args: ArgParser, + + /// Whether the `args` of this meta item have been looked at. + /// This is tracked because if the arguments of a `MetaItemParser` are ignored, this is probably a mistake + #[cfg(debug_assertions)] + args_checked: AtomicBool, } impl Debug for MetaItemParser { @@ -309,6 +348,8 @@ impl MetaItemParser { /// Gets just the args parser, without caring about the path. pub fn args(&self) -> &ArgParser { + #[cfg(debug_assertions)] + self.args_checked.store(true, Ordering::Relaxed); &self.args } @@ -321,6 +362,16 @@ impl MetaItemParser { pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser> { self.path().word_is(sym).then(|| self.args()) } + + /// Explicitly ignore the arguments, disarming the arguments-used check + pub fn ignore_args(&self) { + self.args().ignore_args(); + } + + #[cfg(debug_assertions)] + pub fn are_args_checked(&self) -> bool { + self.args_checked.load(Ordering::Relaxed) + } } #[derive(Clone)] @@ -531,7 +582,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { ArgParser::NoArgs }; - Ok(MetaItemParser { path: PathParser(path), args }) + Ok(MetaItemParser { + path: PathParser(path), + args, + #[cfg(debug_assertions)] + args_checked: AtomicBool::new(false), + }) } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { @@ -656,7 +712,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct MetaItemListParser { sub_parsers: ThinVec, pub span: Span, diff --git a/tests/ui/attributes/args-checked.rs b/tests/ui/attributes/args-checked.rs new file mode 100644 index 0000000000000..18369acfea034 --- /dev/null +++ b/tests/ui/attributes/args-checked.rs @@ -0,0 +1,73 @@ +#![feature(rustc_attrs)] +#![feature(optimize_attribute)] +#![feature(coverage_attribute)] +#![feature(custom_test_frameworks)] +#![allow(unused_attributes)] + +#![test_runner(x = 5)] +//~^ ERROR malformed +#![test_runner(x(x,y,z))] +//~^ ERROR malformed + +#[inline(always = 5)] +//~^ ERROR malformed +#[inline(always(x, y, z))] +//~^ ERROR malformed +#[instruction_set(arm::a32 = 5)] +//~^ ERROR malformed +#[instruction_set(arm::a32(x, y, z))] +//~^ ERROR malformed +#[optimize(size = 5)] +//~^ ERROR malformed +#[optimize(size(x, y, z))] +//~^ ERROR malformed +//~| ERROR multiple `optimize` attributes +#[coverage(off = 5)] +//~^ ERROR malformed +#[coverage(off(x, y, z))] +//~^ ERROR malformed +#[rustc_abi(debug = 5)] +//~^ ERROR malformed +#[rustc_abi(debug(x, y, z))] +//~^ ERROR malformed +fn main() { + +} + +#[macro_export(local_inner_macros = 5)] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +#[macro_export(local_inner_macros(x, y, z))] +//~^ ERROR valid forms for the attribute are +//~| WARN previously accepted +macro_rules! m { + () => {}; +} + +#[rustc_allow_const_fn_unstable(x = 5)] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +#[rustc_allow_const_fn_unstable(x(x, y, z))] +//~^ ERROR `rustc_allow_const_fn_unstable` expects feature names +const fn g() {} + +#[used(always = 5)] +//~^ ERROR malformed +#[used(always(x, y, z))] +//~^ ERROR malformed +static H: u64 = 5; + +#[rustc_must_implement_one_of(eq = 5, neq)] +//~^ ERROR malformed +#[rustc_must_implement_one_of(eq(x, y, z), neq)] +//~^ ERROR malformed +trait T { + +} + +#[rustc_dump_layout(debug = 5)] +//~^ ERROR malformed +#[rustc_dump_layout(debug(x, y, z))] +//~^ ERROR malformed +enum E { + +} diff --git a/tests/ui/attributes/args-checked.stderr b/tests/ui/attributes/args-checked.stderr new file mode 100644 index 0000000000000..13dd6fde23cb7 --- /dev/null +++ b/tests/ui/attributes/args-checked.stderr @@ -0,0 +1,361 @@ +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:7:1 + | +LL | #![test_runner(x = 5)] + | ^^^^^^^^^^^^^^^-----^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x = 5)] +LL + #![test_runner(path)] + | + +error[E0565]: malformed `test_runner` attribute input + --> $DIR/args-checked.rs:9:1 + | +LL | #![test_runner(x(x,y,z))] + | ^^^^^^^^^^^^^^^--------^^ + | | + | didn't expect a literal here + | +help: must be of the form + | +LL - #![test_runner(x(x,y,z))] +LL + #![test_runner(path)] + | + +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:12:1 + | +LL | #[inline(always = 5)] + | ^^^^^^^^^----------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always = 5)] +LL + #[inline(always)] + | +LL - #[inline(always = 5)] +LL + #[inline(never)] + | +LL - #[inline(always = 5)] +LL + #[inline] + | + +error[E0539]: malformed `inline` attribute input + --> $DIR/args-checked.rs:14:1 + | +LL | #[inline(always(x, y, z))] + | ^^^^^^^^^---------------^^ + | | + | valid arguments are `always` or `never` + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[inline(always(x, y, z))] +LL + #[inline(always)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline(never)] + | +LL - #[inline(always(x, y, z))] +LL + #[inline] + | + +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:16:1 + | +LL | #[instruction_set(arm::a32 = 5)] + | ^^^^^^^^^^^^^^^^^^------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32 = 5)] +LL + #[instruction_set(set)] + | + +error[E0539]: malformed `instruction_set` attribute input + --> $DIR/args-checked.rs:18:1 + | +LL | #[instruction_set(arm::a32(x, y, z))] + | ^^^^^^^^^^^^^^^^^^-----------------^^ + | | + | valid arguments are `arm::a32` or `arm::t32` + | + = note: for more information, visit +help: must be of the form + | +LL - #[instruction_set(arm::a32(x, y, z))] +LL + #[instruction_set(set)] + | + +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:20:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^--------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size = 5)] +LL + #[optimize(none)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(size)] + | +LL - #[optimize(size = 5)] +LL + #[optimize(speed)] + | + +error[E0539]: malformed `optimize` attribute input + --> $DIR/args-checked.rs:22:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^-------------^^ + | | + | valid arguments are `size`, `speed` or `none` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(none)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(size)] + | +LL - #[optimize(size(x, y, z))] +LL + #[optimize(speed)] + | + +error: multiple `optimize` attributes + --> $DIR/args-checked.rs:22:1 + | +LL | #[optimize(size(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/args-checked.rs:20:1 + | +LL | #[optimize(size = 5)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:25:1 + | +LL | #[coverage(off = 5)] + | ^^^^^^^^^^^-------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off = 5)] +LL + #[coverage(off)] + | +LL - #[coverage(off = 5)] +LL + #[coverage(on)] + | + +error[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:27:1 + | +LL | #[coverage(off(x, y, z))] + | ^^^^^^^^^^^------------^^ + | | + | valid arguments are `on` or `off` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(off)] + | +LL - #[coverage(off(x, y, z))] +LL + #[coverage(on)] + | + +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:29:1 + | +LL | #[rustc_abi(debug = 5)] + | ^^^^^^^^^^^-----------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug = 5)] +LL + #[rustc_abi(debug)] + | + +error[E0539]: malformed `rustc_abi` attribute input + --> $DIR/args-checked.rs:31:1 + | +LL | #[rustc_abi(debug(x, y, z))] + | ^^^^^^^^^^^----------------^ + | | + | valid arguments are `assert_eq` or `debug` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(assert_eq)] + | +LL - #[rustc_abi(debug(x, y, z))] +LL + #[rustc_abi(debug)] + | + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:47:33 + | +LL | #[rustc_allow_const_fn_unstable(x = 5)] + | ^^^^^ + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:49:33 + | +LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] + | ^^^^^^^^^^ + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:53:1 + | +LL | #[used(always = 5)] + | ^^^^^^^----------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always = 5)] +LL + #[used(compiler)] + | +LL - #[used(always = 5)] +LL + #[used(linker)] + | +LL - #[used(always = 5)] +LL + #[used] + | + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:55:1 + | +LL | #[used(always(x, y, z))] + | ^^^^^^^---------------^^ + | | + | valid arguments are `compiler` or `linker` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[used(always(x, y, z))] +LL + #[used(compiler)] + | +LL - #[used(always(x, y, z))] +LL + #[used(linker)] + | +LL - #[used(always(x, y, z))] +LL + #[used] + | + +error[E0539]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:59:1 + | +LL | #[rustc_must_implement_one_of(eq = 5, neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq = 5, neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + +error[E0539]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:61:1 + | +LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ + | | + | expected a valid identifier here + | +help: must be of the form + | +LL - #[rustc_must_implement_one_of(eq(x, y, z), neq)] +LL + #[rustc_must_implement_one_of(function1, function2, ...)] + | + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:67:1 + | +LL | #[rustc_dump_layout(debug = 5)] + | ^^^^^^^^^^^^^^^^^^^^---------^^ + | | + | didn't expect a literal here + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:69:1 + | +LL | #[rustc_dump_layout(debug(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^--------------^^ + | | + | didn't expect a literal here + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:37:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:40:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: aborting due to 23 previous errors + +Some errors have detailed explanations: E0539, E0565. +For more information about an error, try `rustc --explain E0539`. +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:37:1 + | +LL | #[macro_export(local_inner_macros = 5)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default + +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/args-checked.rs:40:1 + | +LL | #[macro_export(local_inner_macros(x, y, z))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(invalid_macro_export_arguments)]` (part of `#[deny(future_incompatible)]`) on by default +