diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index b686a8cf935ca..f419c1e776b81 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -39,50 +39,10 @@ pub(crate) fn cfg_eval( let features = Some(features); CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id }) .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() } struct CfgEval<'a>(StripUnconfigured<'a>); -fn flat_map_annotatable( - vis: &mut impl MutVisitor, - annotatable: Annotatable, -) -> Option { - match annotatable { - Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item), - Annotatable::AssocItem(item, ctxt) => { - Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt)) - } - Annotatable::ForeignItem(item) => { - vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem) - } - Annotatable::Stmt(stmt) => { - vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt) - } - Annotatable::Expr(mut expr) => { - vis.visit_expr(&mut expr); - Some(Annotatable::Expr(expr)) - } - Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm), - Annotatable::ExprField(field) => { - vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField) - } - Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField), - Annotatable::GenericParam(param) => { - vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam) - } - Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), - Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), - Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), - Annotatable::Crate(mut krate) => { - vis.visit_crate(&mut krate); - Some(Annotatable::Crate(krate)) - } - } -} - fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { struct CfgFinder; @@ -106,14 +66,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item), Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt), Annotatable::Expr(expr) => CfgFinder.visit_expr(expr), - Annotatable::Arm(arm) => CfgFinder.visit_arm(arm), - Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field), - Annotatable::PatField(field) => CfgFinder.visit_pat_field(field), - Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param), - Annotatable::Param(param) => CfgFinder.visit_param(param), - Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field), - Annotatable::Variant(variant) => CfgFinder.visit_variant(variant), - Annotatable::Crate(krate) => CfgFinder.visit_crate(krate), + _ => unreachable!(), }; res.is_break() } @@ -123,11 +76,11 @@ impl CfgEval<'_> { self.0.configure(node) } - fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option { + fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable { // Tokenizing and re-parsing the `Annotatable` can have a significant // performance impact, so try to avoid it if possible if !has_cfg_or_cfg_attr(&annotatable) { - return Some(annotatable); + return annotatable; } // The majority of parsed attribute targets will never need to have early cfg-expansion @@ -140,39 +93,6 @@ impl CfgEval<'_> { // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization // process is lossless, so this process is invisible to proc-macros. - let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> = - match annotatable { - Annotatable::Item(_) => { - |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap())) - } - Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| { - Ok(Annotatable::AssocItem( - parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(), - AssocCtxt::Trait, - )) - }, - Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| { - Ok(Annotatable::AssocItem( - parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(), - AssocCtxt::Impl, - )) - }, - Annotatable::ForeignItem(_) => |parser| { - Ok(Annotatable::ForeignItem( - parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(), - )) - }, - Annotatable::Stmt(_) => |parser| { - Ok(Annotatable::Stmt(P(parser - .parse_stmt_without_recovery(false, ForceCollect::Yes)? - .unwrap()))) - }, - Annotatable::Expr(_) => { - |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?)) - } - _ => unreachable!(), - }; - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) // to `None`-delimited groups containing the corresponding tokens. This // is normally delayed until the proc-macro server actually needs to @@ -191,19 +111,56 @@ impl CfgEval<'_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // + // After that we have our re-parsed `AttrTokenStream`, recursively configuring + // our attribute target will correctly configure the tokens as well. let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; - match parse_annotatable_with(&mut parser) { - Ok(a) => annotatable = a, + let res: PResult<'_, Annotatable> = try { + match annotatable { + Annotatable::Item(_) => { + let item = parser.parse_item(ForceCollect::Yes)?.unwrap(); + Annotatable::Item(self.flat_map_item(item).pop().unwrap()) + } + Annotatable::AssocItem(_, AssocCtxt::Trait) => { + let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::AssocItem( + self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(), + AssocCtxt::Trait, + ) + } + Annotatable::AssocItem(_, AssocCtxt::Impl) => { + let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::AssocItem( + self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(), + AssocCtxt::Impl, + ) + } + Annotatable::ForeignItem(_) => { + let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(); + Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap()) + } + Annotatable::Stmt(_) => { + let stmt = + parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap(); + Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap())) + } + Annotatable::Expr(_) => { + let mut expr = parser.parse_expr_force_collect()?; + self.visit_expr(&mut expr); + Annotatable::Expr(expr) + } + _ => unreachable!(), + } + }; + + match res { + Ok(ann) => ann, Err(err) => { err.emit(); - return Some(annotatable); + annotatable } } - - // Now that we have our re-parsed `AttrTokenStream`, recursively configuring - // our attribute target will correctly configure the tokens as well. - flat_map_annotatable(self, annotatable) } }