diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c2511ac75d5d..278b3200a454 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -81,7 +81,7 @@ fn parse_unstable( ) -> impl IntoIterator { let mut res = Vec::new(); - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { cx.emit_err(session_diagnostics::ExpectsFeatureList { span: cx.attr_span, name: symbol.to_ident_string(), diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 84c83be8b4a5..c2dda74e9f51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -44,13 +44,9 @@ pub fn parse_cfg( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> Option { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; - let Some(single) = list.single() else { + let Some(single) = list.as_single() else { let target = cx.target; let mut adcx = cx.adcx(); if list.is_empty() { @@ -93,7 +89,7 @@ pub fn parse_cfg_entry( MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { ArgParser::List(list) => match meta.path().word_sym() { Some(sym::not) => { - let Some(single) = list.single() else { + let Some(single) = list.as_single() else { return Err(cx.adcx().expected_single_argument(list.span, list.len())); }; CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) @@ -136,7 +132,7 @@ fn parse_cfg_entry_version( meta_span: Span, ) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); - let Some(version) = list.single() else { + let Some(version) = list.as_single() else { return Err( cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: 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 357be2f48f85..ceb4da3df6a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -24,7 +24,7 @@ impl SingleAttributeParser for OptimizeParser { const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { Some(sym::size) => OptimizeAttr::Size, @@ -75,7 +75,7 @@ impl SingleAttributeParser for CoverageParser { const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let arg = cx.single_element_list(args, cx.attr_span)?; + let arg = cx.expect_single_element_list(args, cx.attr_span)?; let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]); @@ -371,8 +371,7 @@ impl AttributeParser for UsedParser { let used_by = match args { ArgParser::NoArgs => UsedBy::Default, ArgParser::List(list) => { - let Some(l) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); + let Some(l) = cx.expect_single(list) else { return; }; @@ -463,9 +462,7 @@ fn parse_tf_attribute( args: &ArgParser, ) -> impl IntoIterator { let mut features = Vec::new(); - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return features; }; if list.is_empty() { @@ -588,11 +585,7 @@ impl SingleAttributeParser for SanitizeParser { ]); 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 list = cx.expect_list(args, cx.attr_span)?; let mut on_set = SanitizerSet::empty(); let mut off_set = SanitizerSet::empty(); @@ -719,11 +712,7 @@ impl SingleAttributeParser for PatchableFunctionEntryParser { const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(meta_item_list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let meta_item_list = cx.expect_list(args, cx.attr_span)?; let mut prefix = None; let mut entry = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 4041ce85fa98..4aa6468be889 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -12,11 +12,7 @@ impl AttributeParser for ConfusablesParser { &[sym::rustc_confusables], template!(List: &[r#""name1", "name2", ..."#]), |this, cx, args| { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return; - }; + let Some(list) = cx.expect_list(args, cx.attr_span) else { return }; if list.is_empty() { cx.emit_err(EmptyConfusables { span: cx.attr_span }); diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 3739461c2004..451e126dd5c6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -314,9 +314,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return Vec::new(); }; @@ -362,9 +360,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return Vec::new(); }; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index 65e9b968e946..f31cf7008544 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -20,7 +20,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_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/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index ee99e2904c80..e56ed166592a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -344,7 +344,7 @@ fn parse_directive_items<'p, S: Stage>( } (Mode::RustcOnUnimplemented, sym::on) => { if is_root { - let items = or_malformed!(item.args().list()?); + let items = or_malformed!(item.args().as_list()?); let mut iter = items.mixed(); let condition: &MetaItemOrLitParser = match iter.next() { Some(c) => c, @@ -554,7 +554,7 @@ fn parse_predicate(input: &MetaItemOrLitParser) -> Result Ok(Predicate::Any(parse_predicate_sequence(mis)?)), sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)), sym::not => { - if let Some(single) = mis.single() { + if let Some(single) = mis.as_single() { Ok(Predicate::Not(Box::new(parse_predicate(single)?))) } else { Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span }) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 321f6e08a733..5d07478b152e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -199,7 +199,7 @@ fn parse_single_test_doc_attr_item( self.attribute.no_crate_inject = Some(path.span()) } Some(sym::attr) => { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { // FIXME: remove this method once merged and uncomment the line below instead. // cx.expected_list(cx.attr_span, args); let span = cx.attr_span; @@ -587,7 +587,7 @@ macro_rules! string_arg_and_crate_level { }), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, |dcx, level| DocTestTakesList.into_diag(dcx, level), diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 32f995753bad..0fc226add012 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -37,10 +37,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, list.len()); - return None; - }; + let l = cx.expect_single(list)?; match l.meta_item().and_then(|i| i.path().word_sym()) { Some(sym::always) => { @@ -78,10 +75,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, list.len()); - return None; - }; + 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()); diff --git a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs index 36e45a763e17..8a182959f95d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs +++ b/compiler/rustc_attr_parsing/src/attributes/instruction_set.rs @@ -19,7 +19,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 maybe_meta_item = cx.single_element_list(args, cx.attr_span)?; + let maybe_meta_item = cx.expect_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 b563ca535428..105fe77eba73 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -391,7 +391,7 @@ fn parse_link_cfg( cx.adcx().duplicate_key(item.span(), sym::cfg); return true; } - let Some(link_cfg) = cx.single_element_list(item.args(), item.span()) else { + let Some(link_cfg) = cx.expect_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 7dcf1b3eb064..f23694a84c4d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -142,7 +142,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option false, ArgParser::List(list) => { - let Some(l) = list.single() else { + let Some(l) = list.as_single() else { cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS); return None; }; @@ -174,7 +174,7 @@ impl SingleAttributeParser for CollapseDebugInfoParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_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/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 76dc171c6831..e57a34e7888a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -57,7 +57,7 @@ fn parse_derive_like( args: &ArgParser, trait_name_mandatory: bool, ) -> Option<(Option, ThinVec)> { - let Some(list) = args.list() else { + let Some(list) = args.as_list() else { // For #[rustc_builtin_macro], it is permitted to leave out the trait name if args.no_args().is_ok() && !trait_name_mandatory { return Some((None, ThinVec::new())); @@ -101,10 +101,7 @@ fn parse_derive_like( cx.adcx().expected_specific_argument(attrs.span(), &[sym::attributes]); return None; } - let Some(attr_list) = attr_list.args().list() else { - cx.adcx().expected_list(attrs.span(), attr_list.args()); - return None; - }; + let attr_list = cx.expect_list(attr_list.args(), attrs.span())?; // Parse item in `attributes(...)` argument for attr in attr_list.mixed() { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index b6110f627a8c..1778c68832a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -22,11 +22,7 @@ impl SingleAttributeParser for CustomMirParser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); 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 list = cx.expect_list(args, cx.attr_span)?; let mut dialect = None; let mut phase = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 71a41384d213..a90fa7d749f8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -32,9 +32,7 @@ fn extend( ) -> impl IntoIterator { let mut reprs = Vec::new(); - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return reprs; }; @@ -197,7 +195,7 @@ fn parse_repr_align( ) -> Option { use AlignKind::*; - let Some(align) = list.single() else { + let Some(align) = list.as_single() else { match align_kind { Packed => { cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { @@ -296,8 +294,7 @@ fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParse cx.adcx().expected_list(attr_span, args); } ArgParser::List(list) => { - let Some(align) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); + let Some(align) = cx.expect_single(list) else { return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index e6f97683c612..3a9eb71f3136 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -96,9 +96,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let ArgParser::List(items) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(items) = cx.expect_list(args, cx.attr_span) else { return vec![]; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 3f4049366f40..1d35923339eb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -30,11 +30,7 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(list) = args.list() else { - let span = cx.attr_span; - cx.adcx().expected_list(span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; let mut fn_names = ThinVec::new(); @@ -130,11 +126,7 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { const TEMPLATE: AttributeTemplate = template!(List: &["N"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let ArgParser::List(meta_items) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let meta_items = cx.expect_list(args, cx.attr_span)?; let mut parsed_indexes = ThinVec::new(); let mut errored = false; @@ -185,7 +177,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 arg = cx.single_element_list(args, cx.attr_span)?; + let arg = cx.expect_single_element_list(args, cx.attr_span)?; let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg else { @@ -210,11 +202,7 @@ fn parse_cgu_fields( args: &ArgParser, accepts_kind: bool, ) -> Option<(Symbol, Symbol, Option)> { - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let args = cx.expect_list(args, cx.attr_span)?; let mut cfg = None::<(Symbol, Span)>; let mut module = None::<(Symbol, Span)>; @@ -359,7 +347,7 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_single_element_list(args, cx.attr_span)?; let Some(arg) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), None); @@ -418,11 +406,7 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser { ]); 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 list = cx.expect_list(args, cx.attr_span)?; let mut fallback = None::; let mut diverging_block_default = None::; @@ -703,9 +687,7 @@ fn extend( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> impl IntoIterator { - let Some(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); + let Some(list) = cx.expect_list(args, cx.attr_span) else { return ThinVec::new(); }; @@ -825,11 +807,8 @@ 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(list) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; + let mut except = None; let mut loaded_from_disk = None; let mut cfg = None; @@ -926,11 +905,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)), ArgParser::List(list) => { - let Some(item) = list.single() else { - let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span, list.len()); - return None; - }; + let item = cx.expect_single(list)?; let Some(ident) = item.meta_item().and_then(|item| item.ident()) else { cx.adcx().expected_identifier(item.span()); return None; @@ -988,7 +963,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 item = cx.single_element_list(args, cx.attr_span)?; + let item = cx.expect_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/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 0559469bc369..f6f964fb4d69 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -311,11 +311,7 @@ pub(crate) fn parse_stability( let mut feature = None; let mut since = None; - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let param_span = param.span(); @@ -383,11 +379,7 @@ pub(crate) fn parse_unstability( let mut implied_by = None; let mut old_name = None; - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let Some(param) = param.meta_item() else { @@ -503,11 +495,7 @@ fn extend( return None; } - let ArgParser::List(list) = args else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let list = cx.expect_list(args, cx.attr_span)?; for param in list.mixed() { let Some(param) = param.meta_item() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 06087c8a4baa..456b29d0c3aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -28,10 +28,11 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let help = list.single().and_then(|item| item.meta_item()).and_then(|item| { - item.args().no_args().ok()?; - Some(item.path().to_string()) - }); + let help = + list.as_single().and_then(|item| item.meta_item()).and_then(|item| { + item.args().no_args().ok()?; + Some(item.path().to_string()) + }); cx.adcx().warn_ill_formed_attribute_input_with_help( ILL_FORMED_ATTRIBUTE_INPUT, help, @@ -71,10 +72,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(single) = list.single() else { - cx.adcx().expected_single_argument(list.span, list.len()); - return None; - }; + let single = cx.expect_single(list)?; let Some(single) = single.meta_item() else { cx.adcx().expected_name_value(single.span(), Some(sym::expected)); return None; @@ -140,17 +138,13 @@ impl SingleAttributeParser for RustcAbiParser { ]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let Some(args) = args.list() else { + let Some(args) = args.as_list() else { let attr_span = cx.attr_span; cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::assert_eq, sym::debug]); return None; }; - let Some(arg) = args.single() else { - let attr_span = cx.attr_span; - cx.adcx().expected_single_argument(attr_span, args.len()); - return None; - }; + let arg = cx.expect_single(args)?; let mut fail_incorrect_argument = |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]); @@ -203,7 +197,7 @@ impl SingleAttributeParser for TestRunnerParser { const TEMPLATE: AttributeTemplate = template!(List: &["path"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_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/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index b2a9addfeab3..d3eb62a4c60d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -17,11 +17,7 @@ impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let mut array = false; let mut boxed_slice = false; - let Some(args) = args.list() else { - let attr_span = cx.attr_span; - cx.adcx().expected_list(attr_span, args); - return None; - }; + let args = cx.expect_list(args, cx.attr_span)?; if args.is_empty() { cx.adcx().expected_at_least_one_argument(args.span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 98f8cc23b500..1f91b1a58309 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( cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser, ) -> Option { - let single = cx.single_element_list(args, cx.attr_span)?; + let single = cx.expect_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 5ced5d5f975a..cebbabfcbf1b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -61,7 +61,7 @@ use crate::attributes::traits::*; use crate::attributes::transparency::*; use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs}; -use crate::parser::{ArgParser, MetaItemOrLitParser, RefPathParser}; +use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, RefPathParser}; use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions, ParsedDescription, @@ -554,7 +554,7 @@ pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> { /// /// 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>( + pub(crate) fn expect_single_element_list<'arg>( &mut self, arg: &'arg ArgParser, span: Span, @@ -564,13 +564,59 @@ pub(crate) fn single_element_list<'arg>( return None; }; - let Some(single) = l.single() else { + let Some(single) = l.as_single() else { self.adcx().expected_single_argument(l.span, l.len()); return None; }; Some(single) } + + /// Asserts that an [`ArgParser`] is a list and returns it, or emits an error and returns + /// `None`. + /// + /// Some examples: + /// + /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list + /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list + /// + /// This is a higher-level (and harder to misuse) wrapper over [`ArgParser::as_list`]. That + /// allows using `?` when the attribute parsing function allows it. You may still want to use + /// [`ArgParser::as_list`] 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_list<'arg>( + &mut self, + args: &'arg ArgParser, + span: Span, + ) -> Option<&'arg MetaItemListParser> { + let list = args.as_list(); + if list.is_none() { + self.adcx().expected_list(span, args); + } + list + } + + /// Asserts that a [`MetaItemListParser`] contains a single element and returns it, or emits an + /// error and returns `None`. + /// + /// This is a higher-level (and harder to misuse) wrapper over [`MetaItemListParser::as_single`]. + /// That allows using `?` to early return. You may still want to use + /// [`MetaItemListParser::as_single`] 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_single<'arg>( + &mut self, + list: &'arg MetaItemListParser, + ) -> Option<&'arg MetaItemOrLitParser> { + let single = list.as_single(); + if single.is_none() { + self.adcx().expected_single_argument(list.span, list.len()); + } + single + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a7daec6d6096..ce2367006128 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -176,7 +176,7 @@ pub fn from_attr_args<'sess>( /// /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser> { + pub fn as_list(&self) -> Option<&MetaItemListParser> { match self { Self::List(l) => Some(l), Self::NameValue(_) | Self::NoArgs => None, @@ -255,6 +255,7 @@ pub fn meta_item(&self) -> Option<&MetaItemParser> { } } +// FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs. /// Utility that deconstructs a MetaItem into usable parts. /// /// MetaItems are syntactically extremely flexible, but specific attributes want to parse @@ -263,7 +264,7 @@ pub fn meta_item(&self) -> Option<&MetaItemParser> { /// MetaItems consist of some path, and some args. The args could be empty. In other words: /// /// - `name` -> args are empty -/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses +/// - `name(...)` -> args are a [`list`](ArgParser::as_list), which is the bit between the parentheses /// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the /// `= value` part /// @@ -694,7 +695,7 @@ pub fn is_empty(&self) -> bool { /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser> { + pub fn as_single(&self) -> Option<&MetaItemOrLitParser> { let mut iter = self.mixed(); iter.next().filter(|_| iter.next().is_none()) }