From a275453887155727db06313a68d5fa61977c461b Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 8 May 2026 19:03:10 +0000 Subject: [PATCH 1/3] replace leftover call to ArgParser::list with AcceptContext::expect_lits --- .../rustc_attr_parsing/src/attributes/repr.rs | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index cc6f3c83e0475..496510f67c3f2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -285,33 +285,29 @@ impl RustcAlignParser { const TEMPLATE: AttributeTemplate = template!(List: &[""]); fn parse(&mut self, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) { - match args { - ArgParser::NoArgs | ArgParser::NameValue(_) => { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - } - ArgParser::List(list) => { - let Some(align) = cx.expect_single(list) else { - return; - }; - - let Some(lit) = align.lit() else { - cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { - span: align.span(), - }); - - return; - }; - - match parse_alignment(&lit.kind, cx) { - Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), - Err(message) => { - cx.emit_err(session_diagnostics::InvalidAlignmentValue { - span: lit.span, - error_part: message, - }); - } - } + let Some(list) = cx.expect_list(args, cx.attr_span) else { + return; + }; + + let Some(align) = cx.expect_single(list) else { + return; + }; + + let Some(lit) = align.lit() else { + cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { + span: align.span(), + }); + + return; + }; + + match parse_alignment(&lit.kind, cx) { + Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), + Err(message) => { + cx.emit_err(session_diagnostics::InvalidAlignmentValue { + span: lit.span, + error_part: message, + }); } } } From 9097f5b67a58eeaa85eb7b662a442265b526fb90 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 8 May 2026 19:10:24 +0000 Subject: [PATCH 2/3] rustc_attr_parsing: improve error message for codegen attributes --- compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs | 6 ++++-- 1 file changed, 4 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 6e606def83625..27501fb3cec1d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -594,8 +594,10 @@ impl SingleAttributeParser for SanitizeParser { return; } None => { - cx.adcx() - .expected_string_literal(value.value_span, Some(value.value_as_lit())); + cx.adcx().expected_specific_argument_strings( + value.value_span, + &[sym::on, sym::off], + ); return; } }; From dcdba78e7e3ecafea3a786fcb2854e61eadfc074 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 8 May 2026 19:10:24 +0000 Subject: [PATCH 3/3] rustc_attr_parsing: add AcceptContext::expect_string_literal --- compiler/rustc_ast/src/attr/mod.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 4 +- .../src/attributes/cfi_encoding.rs | 5 +- .../src/attributes/codegen_attrs.rs | 8 +-- .../src/attributes/confusables.rs | 5 +- .../src/attributes/crate_level.rs | 10 +-- .../src/attributes/debugger.rs | 5 +- .../rustc_attr_parsing/src/attributes/doc.rs | 6 +- .../src/attributes/inline.rs | 14 +--- .../src/attributes/link_attrs.rs | 29 +++------ .../src/attributes/must_not_suspend.rs | 8 +-- .../src/attributes/must_use.rs | 11 +--- .../rustc_attr_parsing/src/attributes/path.rs | 5 +- .../src/attributes/prototype.rs | 3 +- .../rustc_attr_parsing/src/attributes/repr.rs | 6 +- .../src/attributes/rustc_allocator.rs | 5 +- .../src/attributes/rustc_internal.rs | 54 ++++----------- .../src/attributes/stability.rs | 9 +-- .../src/attributes/test_attrs.rs | 28 ++------ .../rustc_attr_parsing/src/attributes/util.rs | 7 +- compiler/rustc_attr_parsing/src/context.rs | 65 +++++++++++++++++++ compiler/rustc_attr_parsing/src/parser.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- 23 files changed, 116 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0374a86d3eb1c..88556aa58c773 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -845,7 +845,7 @@ pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool { } impl MetaItemLit { - pub fn value_str(&self) -> Option { + pub fn value_as_str(&self) -> Option { LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str()) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 4cc07ceaf231f..f838f73838499 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -135,12 +135,12 @@ fn parse_cfg_entry_version( cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }) ); }; - let Some(version_lit) = version.lit() else { + let Some(version_lit) = version.as_lit() else { return Err( cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() }) ); }; - let Some(version_str) = version_lit.value_str() else { + let Some(version_str) = version_lit.value_as_str() else { return Err( cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span }) ); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs index 1a99e8ff1a6ff..0f6b5ee8ad9d8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs @@ -13,10 +13,7 @@ impl SingleAttributeParser for CfiEncodingParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::cfi_encoding))?; - let Some(value_str) = name_value.value_as_str() else { - cx.adcx().expected_string_literal(name_value.value_span, None); - return None; - }; + let value_str = cx.expect_string_literal(name_value)?; if value_str.as_str().trim().is_empty() { cx.adcx().expected_non_empty_string_literal(name_value.value_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 27501fb3cec1d..5c2a41a7a970b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -119,10 +119,7 @@ impl SingleAttributeParser for ExportNameParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; if name.as_str().contains('\0') { // `#[export_name = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. @@ -478,8 +475,7 @@ fn parse_tf_attribute( } // Use value - let Some(value_str) = value.value_as_str() else { - cx.adcx().expected_string_literal(value.value_span, Some(value.value_as_lit())); + let Some(value_str) = cx.expect_string_literal(value) else { return features; }; for feature in value_str.as_str().split(",") { diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 5877ac5819aac..311fc0d33c1f8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -19,10 +19,7 @@ impl AttributeParser for ConfusablesParser { } for param in list.mixed() { - let span = param.span(); - - let Some(lit) = param.lit().and_then(|i| i.value_str()) else { - cx.adcx().expected_string_literal(span, param.lit()); + let Some(lit) = cx.expect_string_literal(param) else { continue; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 038246536a63f..9d6887a338739 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -17,10 +17,7 @@ impl SingleAttributeParser for CrateNameParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let n = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = n.value_as_str() else { - cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(n)?; Some(AttributeKind::CrateName { name, name_span: n.value_span, attr_span: cx.attr_span }) } @@ -44,10 +41,7 @@ impl CombineAttributeParser for CrateTypeParser { ) -> impl IntoIterator { let n = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(crate_type) = n.value_as_str() else { - cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit())); - return None; - }; + let crate_type = cx.expect_string_literal(n)?; let Ok(crate_type) = crate_type.try_into() else { // We don't error on invalid `#![crate_type]` when not applied to a crate diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index b77fdfadf8240..0fc4166a178e4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -34,10 +34,7 @@ impl CombineAttributeParser for DebuggerViualizerParser { } }; - let Some(path) = args.value_as_str() else { - cx.adcx().expected_string_literal(args.value_span, Some(args.value_as_lit())); - return None; - }; + let path = cx.expect_string_literal(args)?; Some(DebugVisualizer { span: ident.span.to(args.value_span), visualizer_type, path }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 10232a7c55a5f..535f67f67a263 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -255,8 +255,7 @@ impl DocParser { } ArgParser::List(list) => { for i in list.mixed() { - let Some(alias) = i.lit().and_then(|i| i.value_str()) else { - cx.adcx().expected_string_literal(i.span(), i.lit()); + let Some(alias) = cx.expect_string_literal(i) else { continue; }; @@ -264,8 +263,7 @@ impl DocParser { } } ArgParser::NameValue(nv) => { - let Some(alias) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + let Some(alias) = cx.expect_string_literal(nv) else { return; }; self.add_alias(cx, alias, nv.value_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index a02f0a89cc042..aee0537771fd4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -77,21 +77,11 @@ impl SingleAttributeParser for RustcForceInlineParser { ArgParser::List(list) => { let l = cx.expect_single(list)?; - let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { - cx.adcx().expected_string_literal(l.span(), l.lit()); - return None; - }; - - Some(reason) - } - ArgParser::NameValue(v) => { - let Some(reason) = v.value_as_str() else { - cx.adcx().expected_string_literal(v.value_span, Some(v.value_as_lit())); - return None; - }; + let reason = cx.expect_string_literal(l)?; Some(reason) } + ArgParser::NameValue(v) => cx.expect_string_literal(v), }; Some(AttributeKind::Inline( diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index d9310906dfeef..0685f989c383d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -37,10 +37,7 @@ impl SingleAttributeParser for LinkNameParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; Some(LinkName { name, span: cx.attr_span }) } @@ -260,8 +257,7 @@ impl LinkParser { let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::name)) else { return false; }; - let Some(link_name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.args_span(), Some(nv.value_as_lit())); + let Some(link_name) = cx.expect_string_literal(nv) else { return false; }; @@ -286,8 +282,7 @@ impl LinkParser { let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::kind)) else { return true; }; - let Some(link_kind) = nv.value_as_str() else { - cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); + let Some(link_kind) = cx.expect_string_literal(nv) else { return true; }; @@ -365,8 +360,7 @@ impl LinkParser { let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::modifiers)) else { return true; }; - let Some(link_modifiers) = nv.value_as_str() else { - cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); + let Some(link_modifiers) = cx.expect_string_literal(nv) else { return true; }; *modifiers = Some((link_modifiers, nv.value_span)); @@ -408,8 +402,7 @@ impl LinkParser { else { return true; }; - let Some(link_wasm_import_module) = nv.value_as_str() else { - cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); + let Some(link_wasm_import_module) = cx.expect_string_literal(nv) else { return true; }; *wasm_import_module = Some((link_wasm_import_module, item.span())); @@ -429,8 +422,7 @@ impl LinkParser { else { return true; }; - let Some(link_import_name_type) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + let Some(link_import_name_type) = cx.expect_string_literal(nv) else { return true; }; if cx.sess().target.arch != Arch::X86 { @@ -498,10 +490,7 @@ impl SingleAttributeParser for LinkSectionParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; if name.as_str().contains('\0') { // `#[link_section = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. @@ -630,9 +619,7 @@ impl SingleAttributeParser for LinkageParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::linkage))?; - let Some(value) = name_value.value_as_str() else { - cx.adcx() - .expected_string_literal(name_value.value_span, Some(name_value.value_as_lit())); + let Some(value) = cx.expect_string_literal(name_value) else { return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs index de7ea837b3a7c..f8e5cb37328a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs @@ -14,13 +14,7 @@ impl SingleAttributeParser for MustNotSuspendParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let reason = match args { - ArgParser::NameValue(reason) => match reason.value_as_str() { - Some(val) => Some(val), - None => { - cx.adcx().expected_nv_or_no_args(reason.value_span); - return None; - } - }, + ArgParser::NameValue(reason) => cx.expect_string_literal(reason), ArgParser::NoArgs => None, ArgParser::List(list) => { cx.adcx().expected_nv_or_no_args(list.span); diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index 6cdf8c74c0c5f..646ac69b6452a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -30,16 +30,7 @@ impl SingleAttributeParser for MustUseParser { span: cx.attr_span, reason: match args { ArgParser::NoArgs => None, - ArgParser::NameValue(name_value) => { - let Some(value_str) = name_value.value_as_str() else { - cx.adcx().expected_string_literal( - name_value.value_span, - Some(&name_value.value_as_lit()), - ); - return None; - }; - Some(value_str) - } + ArgParser::NameValue(name_value) => cx.expect_string_literal(name_value), ArgParser::List(list) => { cx.adcx().expected_nv_or_no_args(list.span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index 0ff87866d6245..8b6f20478df7c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -14,10 +14,7 @@ impl SingleAttributeParser for PathParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(path) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let path = cx.expect_string_literal(nv)?; Some(AttributeKind::Path(path)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index fbc27a8d0fd16..8b8eccab029dd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -74,8 +74,7 @@ fn extract_value( return; } - let Some(value_sym) = val.value_as_str() else { - cx.adcx().expected_string_literal(val.value_span, Some(val.value_as_lit())); + let Some(value_sym) = cx.expect_string_literal(val) else { *failed = true; return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 496510f67c3f2..0ba32c6ca8fa9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -43,7 +43,7 @@ impl CombineAttributeParser for ReprParser { } for param in list.mixed() { - if let Some(_) = param.lit() { + if let Some(_) = param.as_lit() { cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span }); continue; } @@ -212,7 +212,7 @@ fn parse_repr_align( return None; }; - let Some(lit) = align.lit() else { + let Some(lit) = align.as_lit() else { match align_kind { Packed => { cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger { @@ -293,7 +293,7 @@ impl RustcAlignParser { return; }; - let Some(lit) = align.lit() else { + let Some(lit) = align.as_lit() else { cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { span: align.span(), }); diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs index 3706fec5e770b..b21677b4f79ea 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs @@ -27,10 +27,7 @@ impl SingleAttributeParser for RustcAllocatorZeroedVariantParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function"); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; Some(AttributeKind::RustcAllocatorZeroedVariant { name }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 859293bf33a1e..8a648550ae8c6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -152,14 +152,9 @@ impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let arg = cx.expect_single_element_list(args, cx.attr_span)?; + let lint_message = cx.expect_string_literal(arg)?; - let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg - else { - cx.adcx().expected_string_literal(arg.span(), arg.lit()); - return None; - }; - - Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message }) + Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message }) } } @@ -204,10 +199,7 @@ fn parse_cgu_fields( } }; - let Some(str) = arg.value_as_str() else { - cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); - continue; - }; + let str = cx.expect_string_literal(arg)?; if res.is_some() { cx.adcx().duplicate_key(ident.span.to(arg.args_span()), ident.name); @@ -324,10 +316,7 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { return None; }; - let Some(suggestion) = arg.value_as_str() else { - cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); - return None; - }; + let suggestion = cx.expect_string_literal(arg)?; Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion }) } @@ -388,10 +377,7 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser { } }; - let Some(field) = arg.value_as_str() else { - cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); - continue; - }; + let field = cx.expect_string_literal(arg)?; if res.is_some() { cx.adcx().duplicate_key(ident.span, ident.name); @@ -551,10 +537,7 @@ impl SingleAttributeParser for LangParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; let Some(lang_item) = LangItem::from_name(name) else { cx.emit_err(UnknownLangItem { span: cx.attr_span, name }); return None; @@ -649,10 +632,7 @@ impl CombineAttributeParser for RustcMirParser { mi.span(), Some(sym::borrowck_graphviz_postflow), )?; - let Some(path) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, None); - return None; - }; + let path = cx.expect_string_literal(nv)?; let path = PathBuf::from(path.to_string()); if path.file_name().is_some() { Some(RustcMirKind::BorrowckGraphvizPostflow { path }) @@ -757,8 +737,7 @@ impl CombineAttributeParser for RustcCleanParser { continue; }; let value_span = value.value_span; - let Some(value) = value.value_as_str() else { - cx.adcx().expected_string_literal(value_span, None); + let Some(value) = cx.expect_string_literal(value) else { continue; }; match ident.name { @@ -983,10 +962,7 @@ impl SingleAttributeParser for RustcDiagnosticItemParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - let Some(value) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let value = cx.expect_string_literal(nv)?; Some(AttributeKind::RustcDiagnosticItem(value)) } } @@ -1038,11 +1014,7 @@ impl SingleAttributeParser for RustcReservationImplParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - - let Some(value_str) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let value_str = cx.expect_string_literal(nv)?; Some(AttributeKind::RustcReservationImpl(value_str)) } @@ -1065,11 +1037,7 @@ impl SingleAttributeParser for RustcDocPrimitiveParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let nv = cx.expect_name_value(args, cx.attr_span, None)?; - - let Some(value_str) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let value_str = cx.expect_string_literal(nv)?; Some(AttributeKind::RustcDocPrimitive(cx.attr_span, value_str)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index d70c66dc18cf4..4d8943aa36684 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -105,8 +105,7 @@ impl AttributeParser for StabilityParser { let Some(nv) = cx.expect_name_value(args, cx.attr_span, None) else { return; }; - let Some(value_str) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + let Some(value_str) = cx.expect_string_literal(nv) else { return; }; this.allowed_through_unstable_modules = Some(value_str); @@ -292,11 +291,7 @@ fn insert_value_into_option_or_error( } let (_ident, arg) = cx.expect_name_value(param, param.span(), Some(name.name))?; - - let Some(s) = arg.value_as_str() else { - cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); - return None; - }; + let s = cx.expect_string_literal(arg)?; *item = Some(s); diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 1ae8dd0e37c20..7ffeb3d2194a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -60,16 +60,7 @@ impl SingleAttributeParser for ShouldPanicParser { Some(AttributeKind::ShouldPanic { reason: match args { ArgParser::NoArgs => None, - ArgParser::NameValue(name_value) => { - let Some(str_value) = name_value.value_as_str() else { - cx.adcx().expected_string_literal( - name_value.value_span, - Some(name_value.value_as_lit()), - ); - return None; - }; - Some(str_value) - } + ArgParser::NameValue(name_value) => cx.expect_string_literal(name_value), ArgParser::List(list) => { let single = cx.expect_single(list)?; let (ident, arg) = @@ -78,11 +69,7 @@ impl SingleAttributeParser for ShouldPanicParser { cx.adcx().expected_specific_argument_strings(list.span, &[sym::expected]); return None; } - let Some(expected) = arg.value_as_str() else { - cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); - return None; - }; - Some(expected) + cx.expect_string_literal(arg) } }, }) @@ -103,10 +90,7 @@ impl SingleAttributeParser for ReexportTestHarnessMainParser { Some(sym::reexport_test_harness_main), )?; - let Some(name) = nv.value_as_str() else { - cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let name = cx.expect_string_literal(nv)?; Some(AttributeKind::ReexportTestHarnessMain(name)) } @@ -211,11 +195,7 @@ impl SingleAttributeParser for RustcTestMarkerParser { fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option { let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::rustc_test_marker))?; - - let Some(value_str) = name_value.value_as_str() else { - cx.adcx().expected_string_literal(name_value.value_span, None); - return None; - }; + let value_str = cx.expect_string_literal(name_value)?; if value_str.as_str().trim().is_empty() { cx.adcx().expected_non_empty_string_literal(name_value.value_span); diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 438c6ba435056..82f515aff3999 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -41,7 +41,7 @@ pub(crate) fn parse_single_integer( args: &ArgParser, ) -> Option { let single = cx.expect_single_element_list(args, cx.attr_span)?; - let Some(lit) = single.lit() else { + let Some(lit) = single.as_lit() else { cx.adcx().expected_integer_literal(single.span()); return None; }; @@ -54,10 +54,7 @@ pub(crate) fn parse_single_integer( impl AcceptContext<'_, '_> { pub(crate) fn parse_limit_int(&mut self, nv: &NameValueParser) -> Option { - let Some(limit) = nv.value_as_str() else { - self.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; + let limit = self.expect_string_literal(nv)?; let error_str = match limit.as_str().parse() { Ok(i) => return Some(Limit::new(i)), diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bf4989b83200b..81cd32faea127 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -562,6 +562,13 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> { } /// Assert that an [`ArgParser`] has no args, or emits an error and return `None`. + /// + /// This is a higher-level (and harder to misuse) wrapper over multiple + /// [`ArgParser::as_no_args`]. You may still want to use the lower-level methods for the + /// following reasons: + /// + /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). + /// - The attribute can be parsed in multiple ways and it does not make sense to emit an error. pub(crate) fn expect_no_args<'arg>(&mut self, arg: &'arg ArgParser) -> Option<()> { if let Err(span) = arg.as_no_args() { self.adcx().expected_no_args(span); @@ -570,6 +577,26 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> { Some(()) } + + /// Asserts that a node is a string literal, or emits an error and return `None` + /// + /// `arg` must be a reference to any node that may contain a name-value pair, that is: + /// + /// - [`NameValueParser`], + /// - [`MetaItemOrLitParser`], + /// + /// This is a higher-level (and harder to misuse) wrapper over multiple `as_` methods in the + /// [`parser`][crate::parser] module. You may still want to use the lower-level methods for the + /// following reasons: + /// + /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). + /// - The attribute can be parsed in multiple ways and it does not make sense to emit an error. + pub(crate) fn expect_string_literal<'arg, Arg>(&mut self, arg: &'arg Arg) -> Option + where + Arg: ExpectStringLiteral, + { + arg.expect_string_literal(self) + } } pub(crate) trait ExpectNameValue { @@ -649,6 +676,44 @@ impl ExpectNameValue for ArgParser { } } +pub(crate) trait ExpectStringLiteral { + fn expect_string_literal<'f, 'sess>(&self, cx: &mut AcceptContext<'f, 'sess>) + -> Option; +} + +impl ExpectStringLiteral for NameValueParser { + fn expect_string_literal<'f, 'sess>( + &self, + cx: &mut AcceptContext<'f, 'sess>, + ) -> Option { + let value = self.value_as_str(); + if value.is_none() { + cx.adcx().expected_string_literal(self.value_span, Some(self.value_as_lit())); + } + value + } +} + +impl ExpectStringLiteral for MetaItemOrLitParser { + fn expect_string_literal<'f, 'sess>( + &self, + cx: &mut AcceptContext<'f, 'sess>, + ) -> Option { + let Some(lit) = self.as_lit() else { + cx.adcx().expected_string_literal(self.span(), None); + return None; + }; + + let str = lit.value_as_str(); + + if str.is_none() { + cx.adcx().expected_string_literal(self.span(), Some(lit)); + } + + str + } +} + impl<'f, 'sess> Deref for AcceptContext<'f, 'sess> { type Target = SharedContext<'f, 'sess>; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 845f1394cc3de..48790f273adfc 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -240,7 +240,7 @@ impl MetaItemOrLitParser { } } - pub fn lit(&self) -> Option<&MetaItemLit> { + pub fn as_lit(&self) -> Option<&MetaItemLit> { match self { MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit), MetaItemOrLitParser::MetaItemParser(_) => None, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 7747d9920a321..34785b0401189 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1340,7 +1340,7 @@ impl AttributeExt for Attribute { #[inline] fn value_str(&self) -> Option { - self.value_lit().and_then(|x| x.value_str()) + self.value_lit().and_then(|x| x.value_as_str()) } #[inline]