diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c2511ac75d5d2..93f19922b4188 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 73b2727fdab0a..043997371fb80 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -25,7 +25,7 @@ impl SingleAttributeParser for OptimizeParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let single = cx.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 23db854252a37..7fa467a46068f 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 a79b7d6afbcdc..e90ea58ffbcb4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -25,6 +25,7 @@ impl OnMoveParser { ) { 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 dcfba68a4cf8b..855eb4d894d29 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 { ) { if !cx.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 99f856684abd5..d14cc777e01d4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -204,6 +204,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 ee5c507b62920..0c9e11fd23059 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<'_, '_, S>, _: &ArgParser) -> Option { + fn convert(_: &mut AcceptContext<'_, '_, S>, 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 e5b2fb130a185..4c2e657ab80ff 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -42,7 +42,7 @@ impl SingleAttributeParser for InlineParser { 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::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 4003aba76af8e..c02ac8959a77a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -22,7 +22,7 @@ impl SingleAttributeParser for InstructionSetParser { const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32]; let maybe_meta_item = cx.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 a0ded93180eb0..2c0c9bbf60955 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 e1b8b3b29bf00..92f9585346877 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -110,7 +110,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 15bcffe529a0c..b85046433a360 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -49,7 +49,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; }; @@ -945,7 +945,7 @@ impl SingleAttributeParser for RustcIfThisChangedParser { cx.adcx().expected_single_argument(attr_span, list.len()); return None; }; - 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; }; @@ -1003,7 +1003,7 @@ impl CombineAttributeParser for RustcThenThisWouldNeedParser { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } let item = cx.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 4fe0f079bc83c..f226bcd94bab6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -157,7 +157,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; }; @@ -210,7 +210,7 @@ impl SingleAttributeParser for TestRunnerParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let single = cx.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 51345162ee071..c946af6062eca 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -465,6 +465,8 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { kind: AttributeLintKind, span: M, ) { + #[cfg(debug_assertions)] + self.has_lint_been_emitted.store(true, std::sync::atomic::Ordering::Relaxed); if !matches!( self.stage.should_emit(), ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true } @@ -568,6 +570,11 @@ pub struct SharedContext<'p, 'sess, S: Stage> { /// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S` /// is `Late` and is the ID of the syntactical component this attribute was applied to. pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind), + + /// 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: std::sync::atomic::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 68016d81c954c..9a1a8daa29814 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -207,6 +207,8 @@ impl<'sess> AttributeParser<'sess, Early> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: std::sync::atomic::AtomicBool::new(false), }, attr_span, inner_span, @@ -372,6 +374,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_span, target, emit_lint: &mut emit_lint, + #[cfg(debug_assertions)] + has_lint_been_emitted: std::sync::atomic::AtomicBool::new(false), }, attr_span, inner_span: lower_span(n.item.span()), @@ -384,6 +388,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { (accept.accept_fn)(&mut cx, &args); finalizers.push(&accept.finalizer); + #[cfg(debug_assertions)] + if !cx + .shared + .has_lint_been_emitted + .load(std::sync::atomic::Ordering::Relaxed) + { + cx.shared.cx.check_args_used(&attr, &args) + } if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_target(&accept.allowed_targets, target, &mut cx); } @@ -423,7 +435,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { 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: std::sync::atomic::AtomicBool::new(false), + }, all_attrs: &attr_paths, }) { attributes.push(Attribute::Parsed(attr)); @@ -439,6 +458,26 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { 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 a7daec6d6096c..bcdc42aa39af1 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -87,7 +87,7 @@ impl> Display for PathParser

{ } } -#[derive(Clone, Debug)] +#[derive(Debug)] #[must_use] pub enum ArgParser { NoArgs, @@ -209,13 +209,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 +266,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(_) => {} + } + } } /// Utility that deconstructs a MetaItem into usable parts. @@ -268,10 +301,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: std::sync::atomic::AtomicBool, } impl Debug for MetaItemParser { @@ -308,6 +345,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, std::sync::atomic::Ordering::Relaxed); &self.args } @@ -320,6 +359,17 @@ 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) { + #[cfg(debug_assertions)] + self.args().ignore_args(); + } + + #[cfg(debug_assertions)] + pub fn are_args_checked(&self) -> bool { + self.args_checked.load(std::sync::atomic::Ordering::Relaxed) + } } #[derive(Clone)] @@ -530,7 +580,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: std::sync::atomic::AtomicBool::new(false), + }) } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> { @@ -655,7 +710,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..8eee5e2f91723 --- /dev/null +++ b/tests/ui/attributes/args-checked.rs @@ -0,0 +1,72 @@ +#![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 +#[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..a3013dbf8db1d --- /dev/null +++ b/tests/ui/attributes/args-checked.stderr @@ -0,0 +1,321 @@ +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: `#![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: `#![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` + | help: must be of the form: `#[instruction_set(set)]` + | + = note: for more information, visit + +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` + | help: must be of the form: `#[instruction_set(set)]` + | + = note: for more information, visit + +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[E0539]: malformed `coverage` attribute input + --> $DIR/args-checked.rs:24: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:26: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:28: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:30: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:46:33 + | +LL | #[rustc_allow_const_fn_unstable(x = 5)] + | ^^^^^ + +error: `rustc_allow_const_fn_unstable` expects feature names + --> $DIR/args-checked.rs:48:33 + | +LL | #[rustc_allow_const_fn_unstable(x(x, y, z))] + | ^^^^^^^^^^ + +error[E0539]: malformed `used` attribute input + --> $DIR/args-checked.rs:52: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:54: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:58:1 + | +LL | #[rustc_must_implement_one_of(eq = 5, neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` + +error[E0539]: malformed `rustc_must_implement_one_of` attribute input + --> $DIR/args-checked.rs:60:1 + | +LL | #[rustc_must_implement_one_of(eq(x, y, z), neq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` + +error[E0565]: malformed `rustc_dump_layout` attribute input + --> $DIR/args-checked.rs:66: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:68: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:36: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:39: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 22 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:36: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:39: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 +