From 362e0f9160c8cc53e5d5bda96f60ee430af3f7d4 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 4 Apr 2026 17:53:15 +0000 Subject: [PATCH 1/6] special case `expected_single_argument` when no argument is provided --- .../rustc_attr_parsing/src/attributes/cfg.rs | 4 ++-- .../src/attributes/codegen_attrs.rs | 6 +++--- .../src/attributes/debugger.rs | 2 +- .../src/attributes/inline.rs | 4 ++-- .../src/attributes/link_attrs.rs | 2 +- .../src/attributes/macro_attrs.rs | 2 +- .../src/attributes/prototype.rs | 2 +- .../rustc_attr_parsing/src/attributes/repr.rs | 2 +- .../src/attributes/rustc_internal.rs | 8 ++++---- .../src/attributes/test_attrs.rs | 6 +++--- .../rustc_attr_parsing/src/attributes/util.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 18 ++++++++++++++++-- .../src/session_diagnostics.rs | 5 +++++ tests/rustdoc-ui/doc-cfg.stderr | 4 ++-- .../ui/attributes/inline/invalid-inline.stderr | 2 +- tests/ui/attributes/malformed-attrs.stderr | 2 +- tests/ui/cfg/suggest-any-or-all.stderr | 2 +- .../cfg-attr-syntax-validation.rs | 2 +- .../cfg-attr-syntax-validation.stderr | 2 +- .../cfg_attr-attr-syntax-validation.stderr | 2 +- tests/ui/coverage-attr/bad-syntax.stderr | 2 +- tests/ui/error-codes/E0540.stderr | 2 +- tests/ui/link-native-libs/issue-43926.stderr | 2 +- .../windows/link-ordinal-missing-argument.rs | 4 ++-- .../link-ordinal-missing-argument.stderr | 4 ++-- tests/ui/span/E0805.stderr | 2 +- 26 files changed, 57 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index ccc4a1a64c56..fd0593f5e893 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -78,7 +78,7 @@ pub fn parse_cfg( } } - adcx.expected_single_argument(list.span); + adcx.expected_single_argument(list.span, list.len()); return None; }; parse_cfg_entry(cx, single).ok() @@ -93,7 +93,7 @@ pub fn parse_cfg_entry( ArgParser::List(list) => match meta.path().word_sym() { Some(sym::not) => { let Some(single) = list.single() else { - return Err(cx.adcx().expected_single_argument(list.span)); + return Err(cx.adcx().expected_single_argument(list.span, list.len())); }; CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 93664aff4915..688854d6c74f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -30,7 +30,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option, args: &ArgParser) -> Option AttributeParser for UsedParser { ArgParser::NoArgs => UsedBy::Default, ArgParser::List(list) => { let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 3bde4949bce0..06180e74c9e2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -26,7 +26,7 @@ fn extend( return None; }; let Some(single) = l.single() else { - cx.adcx().expected_single_argument(l.span); + cx.adcx().expected_single_argument(l.span, l.len()); return None; }; let Some(mi) = single.meta_item() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index f34a776d9ae8..e5b2fb130a18 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -38,7 +38,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return None; }; @@ -80,7 +80,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option None, ArgParser::List(list) => { let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 6ae4e31af9df..5989f4100b7e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -393,7 +393,7 @@ fn parse_link_cfg( return true; }; let Some(link_cfg) = link_cfg.single() else { - cx.adcx().expected_single_argument(item.span()); + cx.adcx().expected_single_argument(item.span(), link_cfg.len()); return true; }; if !features.link_cfg() { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 3467d5712e1a..4a2ef91ba83d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -181,7 +181,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option( } let Some(val) = arg.name_value() else { - cx.adcx().expected_single_argument(arg.span().unwrap_or(span)); + cx.adcx().expected_single_argument(arg.span().unwrap_or(span), 2); *failed = true; return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index ebb9d90eb152..71a41384d213 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -297,7 +297,7 @@ fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParse } ArgParser::List(list) => { let Some(align) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index d77c804af697..31531a02d688 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -197,7 +197,7 @@ impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(arg) = args.list().and_then(MetaItemListParser::single) else { let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span); + cx.adcx().expected_single_argument(attr_span, 2); return None; }; @@ -382,7 +382,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option, args: &ArgParser) -> Option { let Some(item) = list.single() else { let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span); + cx.adcx().expected_single_argument(attr_span, list.len()); return None; }; let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { @@ -1084,7 +1084,7 @@ fn extend( } let Some(item) = args.list().and_then(|l| l.single()) else { let inner_span = cx.inner_span; - cx.adcx().expected_single_argument(inner_span); + cx.adcx().expected_single_argument(inner_span, 2); return None; }; let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 0f7baa941702..7657b3738305 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -72,7 +72,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return None; }; let Some(single) = single.meta_item() else { @@ -150,7 +150,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option, args: &ArgParser) -> Option( return None; }; let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span); + cx.adcx().expected_single_argument(list.span, list.len()); return None; }; let Some(lit) = single.lit() else { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0be1b9b45b22..4176b59984a4 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -751,8 +751,22 @@ pub(crate) fn expected_not_literal(&mut self, span: Span) -> ErrorGuaranteed { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNotLiteral) } - pub(crate) fn expected_single_argument(&mut self, span: Span) -> ErrorGuaranteed { - self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument) + /// Signals that we expected exactly one argument and that we got either zero or two or more. + /// The `provided_arguments` argument allows distinguishing between "expected an argument here" + /// (when zero arguments are provided) and "expect a single argument here" (when two or more + /// arguments are provided). + pub(crate) fn expected_single_argument( + &mut self, + span: Span, + provided_arguments: usize, + ) -> ErrorGuaranteed { + let reason = if provided_arguments == 0 { + AttributeParseErrorReason::ExpectedArgument + } else { + AttributeParseErrorReason::ExpectedSingleArgument + }; + + self.emit_parse_error(span, reason) } pub(crate) fn expected_at_least_one_argument(&mut self, span: Span) -> ErrorGuaranteed { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 5b198813dc43..1bb9a2a474df 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -557,6 +557,7 @@ pub(crate) enum AttributeParseErrorReason<'a> { upper_bound: isize, }, ExpectedAtLeastOneArgument, + ExpectedArgument, ExpectedSingleArgument, ExpectedList, ExpectedListOrNoArgs, @@ -777,6 +778,10 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); } + AttributeParseErrorReason::ExpectedArgument => { + diag.span_label(self.span, "expected an argument here"); + diag.code(E0805); + } AttributeParseErrorReason::ExpectedAtLeastOneArgument => { diag.span_label(self.span, "expected at least 1 argument here"); } diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index db525ca7a807..f3af95528b2d 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -4,7 +4,7 @@ error[E0805]: malformed `doc` attribute input LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^^^^^--^^^^^^^^^^^^^^^^^ | | - | expected a single argument here + | expected an argument here | help: if the function should be disabled, use `#[cfg(false)]` | @@ -36,7 +36,7 @@ error[E0805]: malformed `doc` attribute input LL | #[doc(cfg())] | ^^^^^^^^^--^^ | | - | expected a single argument here + | expected an argument here | help: if the function should be disabled, use `#[cfg(false)]` | diff --git a/tests/ui/attributes/inline/invalid-inline.stderr b/tests/ui/attributes/inline/invalid-inline.stderr index 78ffe3270a79..6a784de39ccc 100644 --- a/tests/ui/attributes/inline/invalid-inline.stderr +++ b/tests/ui/attributes/inline/invalid-inline.stderr @@ -25,7 +25,7 @@ error[E0805]: malformed `inline` attribute input LL | #[inline()] | ^^^^^^^^--^ | | - | expected a single argument here + | expected an argument here | = note: for more information, visit help: try changing it to one of the following valid forms of the attribute diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 4e98772f57e2..c344db0bf218 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -242,7 +242,7 @@ error[E0805]: malformed `used` attribute input LL | #[used()] | ^^^^^^--^ | | - | expected a single argument here + | expected an argument here | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/cfg/suggest-any-or-all.stderr b/tests/ui/cfg/suggest-any-or-all.stderr index 3d3bc7e05164..35dbe93cebeb 100644 --- a/tests/ui/cfg/suggest-any-or-all.stderr +++ b/tests/ui/cfg/suggest-any-or-all.stderr @@ -24,7 +24,7 @@ error[E0805]: malformed `cfg` attribute input LL | #[cfg()] | ^^^^^--^ | | - | expected a single argument here + | expected an argument here | = note: for more information, visit help: if the struct should be disabled, use `#[cfg(false)]` diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 7d4fd206c6b5..5f319555b9a1 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -12,7 +12,7 @@ #[cfg()] //~^ ERROR malformed `cfg` attribute -//~| NOTE expected a single argument here +//~| NOTE expected an argument here //~| NOTE for more information, visit struct S3; diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 6187c36b0d6c..4ef7f8f7cfec 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -26,7 +26,7 @@ error[E0805]: malformed `cfg` attribute input LL | #[cfg()] | ^^^^^--^ | | - | expected a single argument here + | expected an argument here | = note: for more information, visit help: if the struct should be disabled, use `#[cfg(false)]` diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr index fd03fa62864a..a3c35a96cb7f 100644 --- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -123,7 +123,7 @@ error[E0805]: malformed `inline` attribute input LL | #[cfg_attr(true, inline())] | ^^^^^^-- | | - | expected a single argument here + | expected an argument here | = note: for more information, visit help: try changing it to one of the following valid forms of the attribute diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index 4a356221ff60..8e36e9593028 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -56,7 +56,7 @@ error[E0805]: malformed `coverage` attribute input LL | #[coverage()] | ^^^^^^^^^^--^ | | - | expected a single argument here + | expected an argument here | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/error-codes/E0540.stderr b/tests/ui/error-codes/E0540.stderr index ae23dce5c50a..53f696807a68 100644 --- a/tests/ui/error-codes/E0540.stderr +++ b/tests/ui/error-codes/E0540.stderr @@ -4,7 +4,7 @@ error[E0805]: malformed `inline` attribute input LL | #[inline()] | ^^^^^^^^--^ | | - | expected a single argument here + | expected an argument here | = note: for more information, visit help: try changing it to one of the following valid forms of the attribute diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index f7b85788a2a3..db718d3b0d18 100644 --- a/tests/ui/link-native-libs/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr @@ -4,7 +4,7 @@ error[E0805]: malformed `link` attribute input LL | #[link(name = "foo", cfg())] | ^^^^^^^^^^^^^^^^^^^^^-----^^ | | - | expected a single argument here + | expected an argument here | = note: for more information, visit diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs index 58f190855405..b9bc234c161e 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs @@ -2,12 +2,12 @@ extern "C" { #[link_ordinal()] //~^ ERROR malformed `link_ordinal` attribute input - //~| NOTE expected a single argument + //~| NOTE expected an argument here //~| NOTE for more information, visit fn foo(); #[link_ordinal()] //~^ ERROR malformed `link_ordinal` attribute input - //~| NOTE expected a single argument + //~| NOTE expected an argument here //~| NOTE for more information, visit static mut imported_variable: i32; } diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr index d575b0961af5..482bea98e779 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr @@ -4,7 +4,7 @@ error[E0805]: malformed `link_ordinal` attribute input LL | #[link_ordinal()] | ^^^^^^^^^^^^^^--^ | | | - | | expected a single argument here + | | expected an argument here | help: must be of the form: `#[link_ordinal(ordinal)]` | = note: for more information, visit @@ -15,7 +15,7 @@ error[E0805]: malformed `link_ordinal` attribute input LL | #[link_ordinal()] | ^^^^^^^^^^^^^^--^ | | | - | | expected a single argument here + | | expected an argument here | help: must be of the form: `#[link_ordinal(ordinal)]` | = note: for more information, visit diff --git a/tests/ui/span/E0805.stderr b/tests/ui/span/E0805.stderr index 0247e8d8ec9b..a6a2868ef77c 100644 --- a/tests/ui/span/E0805.stderr +++ b/tests/ui/span/E0805.stderr @@ -4,7 +4,7 @@ error[E0805]: malformed `cfg` macro input LL | if cfg!(not()) { } | ^^^^^^^^--^ | | | - | | expected a single argument here + | | expected an argument here | help: must be of the form: `cfg!(predicate)` | = note: for more information, visit From cdcecc85acdf50c87cfd1fbc0f5ddbc93b267fb8 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 4 Apr 2026 18:57:54 +0000 Subject: [PATCH 2/6] fix error message for `#[custom_mir]` --- compiler/rustc_attr_parsing/src/attributes/prototype.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index e77096743dd0..e23e2ba633f7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -82,7 +82,7 @@ fn extract_value( } let Some(val) = arg.name_value() else { - cx.adcx().expected_single_argument(arg.span().unwrap_or(span), 2); + cx.adcx().expected_name_value(span, Some(key)); *failed = true; return; }; From 6f87e0be69471b26dff9713d09c2b41bf4b14300 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 4 Apr 2026 18:42:42 +0000 Subject: [PATCH 3/6] use `AcceptContext::single_element_list` where possible --- .../src/attributes/codegen_attrs.rs | 24 ++-------- .../src/attributes/debugger.rs | 10 +--- .../src/attributes/instruction_set.rs | 6 +-- .../src/attributes/link_attrs.rs | 7 +-- .../src/attributes/macro_attrs.rs | 10 +--- .../src/attributes/rustc_internal.rs | 25 ++-------- .../src/attributes/test_attrs.rs | 11 +---- .../rustc_attr_parsing/src/attributes/util.rs | 10 +--- compiler/rustc_attr_parsing/src/context.rs | 36 +++++++++++++- tests/ui/attributes/malformed-attrs.stderr | 4 +- .../ui/coverage-attr/bad-attr-ice.feat.stderr | 2 +- .../coverage-attr/bad-attr-ice.nofeat.stderr | 2 +- tests/ui/coverage-attr/bad-syntax.stderr | 6 ++- tests/ui/coverage-attr/name-value.stderr | 48 ++++++++++++++----- tests/ui/coverage-attr/word-only.stderr | 24 +++++----- tests/ui/link-native-libs/issue-43926.stderr | 6 +-- 16 files changed, 106 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 688854d6c74f..3cb75e41825e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -23,16 +23,7 @@ impl SingleAttributeParser for OptimizeParser { const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + 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)) { Some(sym::size) => OptimizeAttr::Size, @@ -84,22 +75,13 @@ impl SingleAttributeParser for CoverageParser { const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::on, sym::off]); - return None; - }; - - let Some(arg) = args.single() else { - cx.adcx().expected_single_argument(args.span, args.len()); - return None; - }; + let arg = cx.single_element_list(args, cx.attr_span)?; let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]); let Some(arg) = arg.meta_item() else { - fail_incorrect_argument(args.span); + fail_incorrect_argument(arg.span()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 06180e74c9e2..65e9b968e946 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -20,15 +20,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let Some(l) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - let Some(single) = l.single() else { - cx.adcx().expected_single_argument(l.span, l.len()); - return None; - }; + let single = cx.single_element_list(args, cx.attr_span)?; let Some(mi) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), None); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 00e2241f2e70..4003aba76af8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -20,11 +20,7 @@ impl SingleAttributeParser for InstructionSetParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32]; const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32]; - let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else { - let attr_span = cx.attr_span; - cx.adcx().expected_specific_argument(attr_span, POSSIBLE_SYMBOLS); - return None; - }; + let maybe_meta_item = cx.single_element_list(args, cx.attr_span)?; let Some(meta_item) = maybe_meta_item.meta_item() else { cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 5989f4100b7e..8aa7759daa04 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -388,12 +388,7 @@ fn parse_link_cfg( cx.adcx().duplicate_key(item.span(), sym::cfg); return true; } - let Some(link_cfg) = item.args().list() else { - cx.adcx().expected_list(item.span(), item.args()); - return true; - }; - let Some(link_cfg) = link_cfg.single() else { - cx.adcx().expected_single_argument(item.span(), link_cfg.len()); + let Some(link_cfg) = cx.single_element_list(item.args(), item.span()) else { return true; }; if !features.link_cfg() { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 4a2ef91ba83d..a0ded93180eb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -175,15 +175,7 @@ impl SingleAttributeParser for CollapseDebugInfoParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let single = cx.single_element_list(args, cx.attr_span)?; let Some(mi) = single.meta_item() else { cx.adcx().expected_not_literal(single.span()); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 31531a02d688..b45b2405ea8e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -195,11 +195,7 @@ impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]); const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(arg) = args.list().and_then(MetaItemListParser::single) else { - let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span, 2); - return None; - }; + let arg = cx.single_element_list(args, cx.attr_span)?; let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg else { @@ -375,19 +371,10 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - - let Some(single) = args.single() else { - cx.adcx().expected_single_argument(args.span, args.len()); - return None; - }; + let single = cx.single_element_list(args, cx.attr_span)?; let Some(arg) = single.meta_item() else { - cx.adcx().expected_name_value(args.span, None); + cx.adcx().expected_name_value(single.span(), None); return None; }; @@ -1082,11 +1069,7 @@ fn extend( if !cx.cx.sess.opts.unstable_opts.query_dep_graph { cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" }); } - let Some(item) = args.list().and_then(|l| l.single()) else { - let inner_span = cx.inner_span; - cx.adcx().expected_single_argument(inner_span, 2); - return None; - }; + let item = cx.single_element_list(args, cx.attr_span)?; let Some(ident) = item.meta_item().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 7657b3738305..4fe0f079bc83 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -208,16 +208,7 @@ impl SingleAttributeParser for TestRunnerParser { const TEMPLATE: AttributeTemplate = template!(List: &["path"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let single = cx.single_element_list(args, cx.attr_span)?; let Some(meta) = single.meta_item() else { cx.adcx().expected_not_literal(single.span()); diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 392942ce31e9..98f8cc23b500 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -41,15 +41,7 @@ pub(crate) fn parse_single_integer( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> Option { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let single = cx.single_element_list(args, cx.attr_span)?; let Some(lit) = single.lit() else { cx.adcx().expected_integer_literal(single.span()); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4176b59984a4..46e255af2270 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -60,7 +60,7 @@ use crate::attributes::traits::*; use crate::attributes::transparency::*; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, RefPathParser}; +use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions, ParsedDescription, @@ -502,6 +502,36 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> { AttributeDiagnosticContext { ctx: self, custom_suggestions: Vec::new() } } + + /// Asserts that this MetaItem is a list that contains a single element. Emits an error and + /// returns `None` if it is not the case. + /// + /// Some examples: + /// + /// - In `#[allow(warnings)]`, `warnings` is returned + /// - In `#[cfg_attr(docsrs, doc = "foo")]`, `None` is returned, "expected a single argument + /// here" is emitted. + /// - In `#[cfg()]`, `None` is returned, "expected an argument here" is emitted. + /// + /// The provided span is used as a fallback for diagnostic generation in case `arg` does not + /// contain any. It should be the span of the node that contains `arg`. + pub(crate) fn single_element_list<'arg>( + &mut self, + arg: &'arg ArgParser, + span: Span, + ) -> Option<&'arg MetaItemOrLitParser> { + let ArgParser::List(l) = arg else { + self.adcx().expected_list(span, arg); + return None; + }; + + let Some(single) = l.single() else { + self.adcx().expected_single_argument(l.span, l.len()); + return None; + }; + + Some(single) + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { @@ -689,6 +719,8 @@ pub(crate) fn expected_integer_literal_in_range( ) } + /// The provided span is used as a fallback in case `args` does not contain any. It should be + /// the span of the node that contains `args`. pub(crate) fn expected_list(&mut self, span: Span, args: &ArgParser) -> ErrorGuaranteed { let span = match args { ArgParser::NoArgs => span, @@ -745,7 +777,7 @@ pub(crate) fn duplicate_key(&mut self, span: Span, key: Symbol) -> ErrorGuarante self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key)) } - /// An error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser) + /// An error that should be emitted when a [`MetaItemOrLitParser`] /// was expected *not* to be a literal, but instead a meta item. pub(crate) fn expected_not_literal(&mut self, span: Span) -> ErrorGuaranteed { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNotLiteral) diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index c344db0bf218..ab9de6f797f5 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -314,7 +314,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/malformed-attrs.rs:92:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -353,7 +353,7 @@ error[E0539]: malformed `instruction_set` attribute input LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ | | - | valid arguments are `arm::a32` or `arm::t32` + | expected this to be a list | help: must be of the form: `#[instruction_set(set)]` | = note: for more information, visit diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr index 5a003af42da5..ee4011b9d773 100644 --- a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr +++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr @@ -2,7 +2,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/bad-attr-ice.rs:11:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr index 4501e5e9dc82..7feef95a7930 100644 --- a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr +++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr @@ -12,7 +12,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/bad-attr-ice.rs:11:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index 8e36e9593028..522dd06e87b0 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -26,7 +26,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:17:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -39,7 +39,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/bad-syntax.rs:20:1 | LL | #[coverage = true] - | ^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index 06e59e5a8646..d15be83465fd 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -2,7 +2,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:12:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -17,7 +19,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:17:5 | LL | #![coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -32,7 +36,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:21:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -55,7 +61,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:26:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -70,7 +78,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:29:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -93,7 +103,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:35:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -116,7 +128,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:39:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -139,7 +153,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:44:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -162,7 +178,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:50:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -177,7 +195,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:53:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -200,7 +220,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:58:5 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -223,7 +245,9 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:64:1 | LL | #[coverage = "off"] - | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index 05478695256f..481010415237 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -2,7 +2,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:12:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -15,7 +15,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:17:5 | LL | #![coverage] - | ^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -28,7 +28,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:21:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -49,7 +49,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:26:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -62,7 +62,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:29:5 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -83,7 +83,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:35:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -104,7 +104,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:39:5 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -125,7 +125,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:44:5 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -146,7 +146,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:50:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -159,7 +159,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:53:5 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -180,7 +180,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:58:5 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | @@ -201,7 +201,7 @@ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:64:1 | LL | #[coverage] - | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument + | ^^^^^^^^^^^ expected this to be a list | help: try changing it to one of the following valid forms of the attribute | diff --git a/tests/ui/link-native-libs/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index db718d3b0d18..161754f32003 100644 --- a/tests/ui/link-native-libs/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr @@ -2,9 +2,9 @@ error[E0805]: malformed `link` attribute input --> $DIR/issue-43926.rs:1:1 | LL | #[link(name = "foo", cfg())] - | ^^^^^^^^^^^^^^^^^^^^^-----^^ - | | - | expected an argument here + | ^^^^^^^^^^^^^^^^^^^^^^^^--^^ + | | + | expected an argument here | = note: for more information, visit From ec3f4382dfd7b0788d2b491a47572a087d42097f Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sat, 4 Apr 2026 19:46:50 +0000 Subject: [PATCH 4/6] Fix error message in `#[patchable_function_entry]` --- compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs | 2 +- .../patchable-function-entry-attribute.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 3cb75e41825e..68fbba02283d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -737,7 +737,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Date: Fri, 10 Apr 2026 15:44:24 +0100 Subject: [PATCH 5/6] bootstrap: auto-patch libgccjit.so for NixOS Currently all downloaded rustc and LLVM components are auto patched on NixOS, but this is not done for libgccjit.so, so when GCC backend is enabled on NixOS, the build ICEs with errors like this: thread 'rustc' (2286205) panicked at compiler/rustc_codegen_gcc/src/lib.rs:191:9: Cannot load libgccjit.so: libzstd.so.1: cannot open shared object file: No such file or directory Fix this by auto-patch libgccjit.so, too. `zstd` is added to the dependency environment. Signed-off-by: Gary Guo --- src/bootstrap/src/core/download.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index b8e00c596f28..3b3044484f39 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -398,6 +398,16 @@ pub fn download_ci_gcc(&self, gcc_sha: &str, root_dir: &Path) { self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error); } self.unpack(&tarball, root_dir, "gcc-dev"); + + if self.should_fix_bins_and_dylibs() { + let lib_dir = root_dir.join("lib"); + for entry in t!(fs::read_dir(lib_dir)) { + let lib = t!(entry).path(); + if path_is_dylib(&lib) { + self.fix_bin_or_dylib(&lib); + } + } + } } } @@ -677,6 +687,8 @@ fn fix_bin_or_dylib(out: &Path, fname: &Path, exec_ctx: &ExecutionContext) { // bintools: Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`). // cc.lib: Needed similarly for `libstdc++.so.6`. // zlib: Needed as a system dependency of `libLLVM-*.so`. + // zstd.out: Needed as a system dependency of `libgccjit.so`. `.out` is necessary as the + // default output of `zstd` derivation is `.bin`. // patchelf: Needed for patching ELF binaries (see doc comment above). let nix_deps_dir = out.join(".nix-deps"); const NIX_EXPR: &str = " @@ -685,6 +697,7 @@ fn fix_bin_or_dylib(out: &Path, fname: &Path, exec_ctx: &ExecutionContext) { name = \"rust-stage0-dependencies\"; paths = [ zlib + zstd.out patchelf stdenv.cc.bintools stdenv.cc.cc.lib From f97143d9511c148c5f37412cdfca73e1edb88957 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 10 Apr 2026 20:04:37 +0200 Subject: [PATCH 6/6] Use a linting node closer the parsing of `#[cfg_attr]` --- .../rustc_attr_parsing/src/attributes/cfg.rs | 8 +++++--- compiler/rustc_expand/src/config.rs | 9 ++++++--- tests/ui/check-cfg/allow-mod-level.rs | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 tests/ui/check-cfg/allow-mod-level.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index ccc4a1a64c56..91b71b851ae9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -2,7 +2,7 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; -use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; +use rustc_ast::{AttrItem, Attribute, LitKind, ast, token}; use rustc_errors::{Applicability, PResult, msg}; use rustc_feature::{ AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, @@ -324,12 +324,13 @@ pub fn parse_cfg_attr( cfg_attr: &Attribute, sess: &Session, features: Option<&Features>, + lint_node_id: ast::NodeId, ) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> { match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => { check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim); match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { - parse_cfg_attr_internal(p, sess, features, cfg_attr) + parse_cfg_attr_internal(p, sess, features, lint_node_id, cfg_attr) }) { Ok(r) => return Some(r), Err(e) => { @@ -390,6 +391,7 @@ fn parse_cfg_attr_internal<'a>( parser: &mut Parser<'a>, sess: &'a Session, features: Option<&Features>, + lint_node_id: ast::NodeId, attribute: &Attribute, ) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> { // Parse cfg predicate @@ -410,7 +412,7 @@ fn parse_cfg_attr_internal<'a>( Some(attribute.get_normal_item().unsafety), ParsedDescription::Attribute, pred_span, - CRATE_NODE_ID, + lint_node_id, Target::Crate, features, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ec5951e50e3a..8bc1af32ffc7 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -283,9 +283,12 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace)); let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace); - let Some((cfg_predicate, expanded_attrs)) = - rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features) - else { + let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr( + cfg_attr, + &self.sess, + self.features, + self.lint_node_id, + ) else { return vec![trace_attr]; }; diff --git a/tests/ui/check-cfg/allow-mod-level.rs b/tests/ui/check-cfg/allow-mod-level.rs new file mode 100644 index 000000000000..02610d3b1f02 --- /dev/null +++ b/tests/ui/check-cfg/allow-mod-level.rs @@ -0,0 +1,16 @@ +// This test check that a module-level `#![allow(unexpected_cfgs)]` works +// +// Related to https://github.com/rust-lang/rust/issues/155118 +// +//@ check-pass +//@ no-auto-check-cfg +//@ compile-flags: --check-cfg=cfg() + +mod my_mod { + #![allow(unexpected_cfgs)] + + #[cfg_attr(asan, sanitize(address = "off"))] + static MY_ITEM: () = (); +} + +fn main() {}