1use std::path::PathBuf;2use std::rc::Rc;3use std::sync::Arc;4use std::{iter, mem, slice};56use rustc_ast::mut_visit::*;7use rustc_ast::tokenstream::TokenStream;8use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};9use rustc_ast::{10 self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec,11 DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs,12 HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId,13 PatKind, StmtKind, TyKind, token,14};15use rustc_ast_pretty::pprust;16use rustc_attr_parsing::parser::AllowExprMetavar;17use rustc_attr_parsing::{18 AttributeParser, AttributeSafety, CFG_TEMPLATE, EvalConfigResult, ShouldEmit,19 eval_config_entry, parse_cfg, validate_attr,20};21use rustc_data_structures::flat_map_in_place::FlatMapInPlace;22use rustc_data_structures::stack::ensure_sufficient_stack;23use rustc_errors::{PResult, msg};24use rustc_feature::Features;25use rustc_hir::Target;26use rustc_hir::def::MacroKinds;27use rustc_hir::limit::Limit;28use rustc_parse::parser::{29 AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser,30 RecoverColon, RecoverComma, Recovery, token_descr,31};32use rustc_session::Session;33use rustc_session::errors::feature_err;34use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};35use rustc_span::hygiene::SyntaxContext;36use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym};37use smallvec::SmallVec;3839use crate::base::*;40use crate::config::{StripUnconfigured, attr_into_trace};41use crate::errors::{42 EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,43 RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,44 WrongFragmentKind,45};46use crate::mbe::diagnostics::annotate_err_with_kind;47use crate::module::{48 DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod,49};50use crate::placeholders::{PlaceholderExpander, placeholder};51use crate::stats::*;5253macro_rules! ast_fragments {54 (55 $($Kind:ident($AstTy:ty) {56 $kind_name:expr;57 $(one58 fn $visit_ast:ident;59 )?60 $(many61 fn $flat_map_ast_elt:ident;62 fn $visit_ast_elt:ident($($args:tt)*);63 )?64 fn $make_ast:ident;65 })*66 ) => {67 /// A fragment of AST that can be produced by a single macro expansion.68 /// Can also serve as an input and intermediate result for macro expansion operations.69 pub enum AstFragment {70 OptExpr(Option<Box<ast::Expr>>),71 MethodReceiverExpr(Box<ast::Expr>),72 $($Kind($AstTy),)*73 }7475 /// "Discriminant" of an AST fragment.76 #[derive(Copy, Clone, Debug, PartialEq, Eq)]77 pub enum AstFragmentKind {78 OptExpr,79 MethodReceiverExpr,80 $($Kind,)*81 }8283 impl AstFragmentKind {84 pub fn name(self) -> &'static str {85 match self {86 AstFragmentKind::OptExpr => "expression",87 AstFragmentKind::MethodReceiverExpr => "expression",88 $(AstFragmentKind::$Kind => $kind_name,)*89 }90 }9192 fn make_from(self, result: Box<dyn MacResult + '_>) -> Option<AstFragment> {93 match self {94 AstFragmentKind::OptExpr =>95 result.make_expr().map(Some).map(AstFragment::OptExpr),96 AstFragmentKind::MethodReceiverExpr =>97 result.make_expr().map(AstFragment::MethodReceiverExpr),98 $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*99 }100 }101 }102103 impl AstFragment {104 fn add_placeholders(&mut self, placeholders: &[NodeId]) {105 if placeholders.is_empty() {106 return;107 }108 match self {109 $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {110 ${ignore($flat_map_ast_elt)}111 placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()112 })),)?)*113 _ => panic!("unexpected AST fragment kind")114 }115 }116117 pub(crate) fn make_opt_expr(self) -> Option<Box<ast::Expr>> {118 match self {119 AstFragment::OptExpr(expr) => expr,120 _ => panic!("AstFragment::make_opt_expr called on the wrong kind of fragment"),121 }122 }123124 pub(crate) fn make_method_receiver_expr(self) -> Box<ast::Expr> {125 match self {126 AstFragment::MethodReceiverExpr(expr) => expr,127 _ => panic!("AstFragment::make_method_receiver_expr called on the wrong kind of fragment"),128 }129 }130131 $(pub fn $make_ast(self) -> $AstTy {132 match self {133 AstFragment::$Kind(ast) => ast,134 _ => panic!("AstFragment::{} called on the wrong kind of fragment", stringify!($make_ast)),135 }136 })*137138 fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {139 T::fragment_to_output(self)140 }141142 pub(crate) fn mut_visit_with(&mut self, vis: &mut impl MutVisitor) {143 match self {144 AstFragment::OptExpr(opt_expr) => {145 if let Some(expr) = opt_expr.take() {146 *opt_expr = vis.filter_map_expr(expr)147 }148 }149 AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),150 $($(AstFragment::$Kind(ast) => vis.$visit_ast(ast),)?)*151 $($(AstFragment::$Kind(ast) =>152 ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)*153 }154 }155156 pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {157 match self {158 AstFragment::OptExpr(Some(expr)) => try_visit!(visitor.visit_expr(expr)),159 AstFragment::OptExpr(None) => {}160 AstFragment::MethodReceiverExpr(expr) => try_visit!(visitor.visit_method_receiver_expr(expr)),161 $($(AstFragment::$Kind(ast) => try_visit!(visitor.$visit_ast(ast)),)?)*162 $($(AstFragment::$Kind(ast) => walk_list!(visitor, $visit_ast_elt, &ast[..], $($args)*),)?)*163 }164 V::Result::output()165 }166 }167168 impl<'a, 'b> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a, 'b> {169 $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a, 'b>>)170 -> Option<$AstTy> {171 Some(self.make(AstFragmentKind::$Kind).$make_ast())172 })*173 }174 }175}176177ast_fragments! {178 Expr(Box<ast::Expr>) {179 "expression";180 one fn visit_expr;181 fn make_expr;182 }183 Pat(Box<ast::Pat>) {184 "pattern";185 one fn visit_pat;186 fn make_pat;187 }188 Ty(Box<ast::Ty>) {189 "type";190 one fn visit_ty;191 fn make_ty;192 }193 Stmts(SmallVec<[ast::Stmt; 1]>) {194 "statement";195 many fn flat_map_stmt; fn visit_stmt();196 fn make_stmts;197 }198 Items(SmallVec<[Box<ast::Item>; 1]>) {199 "item";200 many fn flat_map_item; fn visit_item();201 fn make_items;202 }203 TraitItems(SmallVec<[Box<ast::AssocItem>; 1]>) {204 "trait item";205 many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait);206 fn make_trait_items;207 }208 ImplItems(SmallVec<[Box<ast::AssocItem>; 1]>) {209 "impl item";210 many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });211 fn make_impl_items;212 }213 TraitImplItems(SmallVec<[Box<ast::AssocItem>; 1]>) {214 "impl item";215 many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });216 fn make_trait_impl_items;217 }218 ForeignItems(SmallVec<[Box<ast::ForeignItem>; 1]>) {219 "foreign item";220 many fn flat_map_foreign_item; fn visit_foreign_item();221 fn make_foreign_items;222 }223 Arms(SmallVec<[ast::Arm; 1]>) {224 "match arm";225 many fn flat_map_arm; fn visit_arm();226 fn make_arms;227 }228 ExprFields(SmallVec<[ast::ExprField; 1]>) {229 "field expression";230 many fn flat_map_expr_field; fn visit_expr_field();231 fn make_expr_fields;232 }233 PatFields(SmallVec<[ast::PatField; 1]>) {234 "field pattern";235 many fn flat_map_pat_field; fn visit_pat_field();236 fn make_pat_fields;237 }238 GenericParams(SmallVec<[ast::GenericParam; 1]>) {239 "generic parameter";240 many fn flat_map_generic_param; fn visit_generic_param();241 fn make_generic_params;242 }243 Params(SmallVec<[ast::Param; 1]>) {244 "function parameter";245 many fn flat_map_param; fn visit_param();246 fn make_params;247 }248 FieldDefs(SmallVec<[ast::FieldDef; 1]>) {249 "field";250 many fn flat_map_field_def; fn visit_field_def();251 fn make_field_defs;252 }253 Variants(SmallVec<[ast::Variant; 1]>) {254 "variant";255 many fn flat_map_variant; fn visit_variant();256 fn make_variants;257 }258 WherePredicates(SmallVec<[ast::WherePredicate; 1]>) {259 "where predicate";260 many fn flat_map_where_predicate; fn visit_where_predicate();261 fn make_where_predicates;262 }263 Crate(ast::Crate) {264 "crate";265 one fn visit_crate;266 fn make_crate;267 }268}269270pub enum SupportsMacroExpansion {271 No,272 Yes { supports_inner_attrs: bool },273}274275impl AstFragmentKind {276 pub(crate) fn dummy(self, span: Span, guar: ErrorGuaranteed) -> AstFragment {277 self.make_from(DummyResult::any(span, guar)).expect("couldn't create a dummy AST fragment")278 }279280 pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {281 match self {282 AstFragmentKind::OptExpr283 | AstFragmentKind::Expr284 | AstFragmentKind::MethodReceiverExpr285 | AstFragmentKind::Stmts286 | AstFragmentKind::Ty287 | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },288 AstFragmentKind::Items289 | AstFragmentKind::TraitItems290 | AstFragmentKind::ImplItems291 | AstFragmentKind::TraitImplItems292 | AstFragmentKind::ForeignItems293 | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },294 AstFragmentKind::Arms295 | AstFragmentKind::ExprFields296 | AstFragmentKind::PatFields297 | AstFragmentKind::GenericParams298 | AstFragmentKind::Params299 | AstFragmentKind::FieldDefs300 | AstFragmentKind::Variants301 | AstFragmentKind::WherePredicates => SupportsMacroExpansion::No,302 }303 }304305 pub(crate) fn expect_from_annotatables(306 self,307 items: impl IntoIterator<Item = Annotatable>,308 ) -> AstFragment {309 let mut items = items.into_iter();310 match self {311 AstFragmentKind::Arms => {312 AstFragment::Arms(items.map(Annotatable::expect_arm).collect())313 }314 AstFragmentKind::ExprFields => {315 AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect())316 }317 AstFragmentKind::PatFields => {318 AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect())319 }320 AstFragmentKind::GenericParams => {321 AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect())322 }323 AstFragmentKind::Params => {324 AstFragment::Params(items.map(Annotatable::expect_param).collect())325 }326 AstFragmentKind::FieldDefs => {327 AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect())328 }329 AstFragmentKind::Variants => {330 AstFragment::Variants(items.map(Annotatable::expect_variant).collect())331 }332 AstFragmentKind::WherePredicates => AstFragment::WherePredicates(333 items.map(Annotatable::expect_where_predicate).collect(),334 ),335 AstFragmentKind::Items => {336 AstFragment::Items(items.map(Annotatable::expect_item).collect())337 }338 AstFragmentKind::ImplItems => {339 AstFragment::ImplItems(items.map(Annotatable::expect_impl_item).collect())340 }341 AstFragmentKind::TraitImplItems => {342 AstFragment::TraitImplItems(items.map(Annotatable::expect_impl_item).collect())343 }344 AstFragmentKind::TraitItems => {345 AstFragment::TraitItems(items.map(Annotatable::expect_trait_item).collect())346 }347 AstFragmentKind::ForeignItems => {348 AstFragment::ForeignItems(items.map(Annotatable::expect_foreign_item).collect())349 }350 AstFragmentKind::Stmts => {351 AstFragment::Stmts(items.map(Annotatable::expect_stmt).collect())352 }353 AstFragmentKind::Expr => AstFragment::Expr(354 items.next().expect("expected exactly one expression").expect_expr(),355 ),356 AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(357 items.next().expect("expected exactly one expression").expect_expr(),358 ),359 AstFragmentKind::OptExpr => {360 AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))361 }362 AstFragmentKind::Crate => {363 AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate())364 }365 AstFragmentKind::Pat | AstFragmentKind::Ty => {366 panic!("patterns and types aren't annotatable")367 }368 }369 }370}371372pub struct Invocation {373 pub kind: InvocationKind,374 pub fragment_kind: AstFragmentKind,375 pub expansion_data: ExpansionData,376}377378pub enum InvocationKind {379 Bang {380 mac: Box<ast::MacCall>,381 span: Span,382 },383 Attr {384 attr: ast::Attribute,385 /// Re-insertion position for inert attributes.386 pos: usize,387 item: Annotatable,388 /// Required for resolving derive helper attributes.389 derives: Vec<ast::Path>,390 },391 Derive {392 path: ast::Path,393 is_const: bool,394 item: Annotatable,395 },396 GlobDelegation {397 item: Box<ast::AssocItem>,398 /// Whether this is a trait impl or an inherent impl399 of_trait: bool,400 },401}402403impl InvocationKind {404 fn placeholder_visibility(&self) -> Option<ast::Visibility> {405 // HACK: For unnamed fields placeholders should have the same visibility as the actual406 // fields because for tuple structs/variants resolve determines visibilities of their407 // constructor using these field visibilities before attributes on them are expanded.408 // The assumption is that the attribute expansion cannot change field visibilities,409 // and it holds because only inert attributes are supported in this position.410 match self {411 InvocationKind::Attr { item: Annotatable::FieldDef(field), .. }412 | InvocationKind::Derive { item: Annotatable::FieldDef(field), .. }413 if field.ident.is_none() =>414 {415 Some(field.vis.clone())416 }417 _ => None,418 }419 }420}421422impl Invocation {423 pub fn span(&self) -> Span {424 match &self.kind {425 InvocationKind::Bang { span, .. } => *span,426 InvocationKind::Attr { attr, .. } => attr.span,427 InvocationKind::Derive { path, .. } => path.span,428 InvocationKind::GlobDelegation { item, .. } => item.span,429 }430 }431432 fn span_mut(&mut self) -> &mut Span {433 match &mut self.kind {434 InvocationKind::Bang { span, .. } => span,435 InvocationKind::Attr { attr, .. } => &mut attr.span,436 InvocationKind::Derive { path, .. } => &mut path.span,437 InvocationKind::GlobDelegation { item, .. } => &mut item.span,438 }439 }440}441442pub struct MacroExpander<'a, 'b> {443 pub cx: &'a mut ExtCtxt<'b>,444 monotonic: bool, // cf. `cx.monotonic_expander()`445}446447impl<'a, 'b> MacroExpander<'a, 'b> {448 pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {449 MacroExpander { cx, monotonic }450 }451452 pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {453 let file_path = match self.cx.source_map().span_to_filename(krate.spans.inner_span) {454 FileName::Real(name) => name455 .into_local_path()456 .expect("attempting to resolve a file path in an external file"),457 other => PathBuf::from(other.prefer_local_unconditionally().to_string()),458 };459 let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();460 self.cx.root_path = dir_path.clone();461 self.cx.current_expansion.module = Rc::new(ModuleData {462 mod_path: vec![Ident::with_dummy_span(self.cx.ecfg.crate_name)],463 file_path_stack: vec![file_path],464 dir_path,465 });466 let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();467 assert_eq!(krate.id, ast::CRATE_NODE_ID);468 self.cx.trace_macros_diag();469 krate470 }471472 /// Recursively expand all macro invocations in this AST fragment.473 pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {474 let orig_expansion_data = self.cx.current_expansion.clone();475 let orig_force_mode = self.cx.force_mode;476477 // Collect all macro invocations and replace them with placeholders.478 let (mut fragment_with_placeholders, mut invocations) =479 self.collect_invocations(input_fragment, &[]);480481 // Optimization: if we resolve all imports now,482 // we'll be able to immediately resolve most of imported macros.483 self.resolve_imports();484485 // Resolve paths in all invocations and produce output expanded fragments for them, but486 // do not insert them into our input AST fragment yet, only store in `expanded_fragments`.487 // The output fragments also go through expansion recursively until no invocations are left.488 // Unresolved macros produce dummy outputs as a recovery measure.489 invocations.reverse();490 let mut expanded_fragments = Vec::new();491 let mut expanded_fragments_len = 0;492 let mut undetermined_invocations = Vec::new();493 let (mut progress, mut force) = (false, !self.monotonic);494 loop {495 let Some((invoc, ext)) = invocations.pop() else {496 self.resolve_imports();497 if undetermined_invocations.is_empty() {498 break;499 }500 invocations = mem::take(&mut undetermined_invocations);501 force = !progress;502 progress = false;503 if force && self.monotonic {504 self.cx.dcx().span_delayed_bug(505 invocations.last().unwrap().0.span(),506 "expansion entered force mode without producing any errors",507 );508 }509 continue;510 };511512 let ext = match ext {513 Some(ext) => ext,514 None => {515 let eager_expansion_root = if self.monotonic {516 invoc.expansion_data.id517 } else {518 orig_expansion_data.id519 };520 match self.cx.resolver.resolve_macro_invocation(521 &invoc,522 eager_expansion_root,523 force,524 ) {525 Ok(ext) => ext,526 Err(Indeterminate) => {527 // Cannot resolve, will retry this invocation later.528 undetermined_invocations.push((invoc, None));529 continue;530 }531 }532 }533 };534535 let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;536 let depth = depth - orig_expansion_data.depth;537 self.cx.current_expansion = invoc.expansion_data.clone();538 self.cx.force_mode = force;539540 let fragment_kind = invoc.fragment_kind;541 match self.expand_invoc(invoc, &ext.kind) {542 ExpandResult::Ready(fragment) => {543 let mut derive_invocations = Vec::new();544 let derive_placeholders = self545 .cx546 .resolver547 .take_derive_resolutions(expn_id)548 .map(|derives| {549 derive_invocations.reserve(derives.len());550 derives551 .into_iter()552 .map(|DeriveResolution { path, item, exts: _, is_const }| {553 // FIXME: Consider using the derive resolutions (`_exts`)554 // instead of enqueuing the derives to be resolved again later.555 // Note that this can result in duplicate diagnostics.556 let expn_id = LocalExpnId::fresh_empty();557 derive_invocations.push((558 Invocation {559 kind: InvocationKind::Derive { path, item, is_const },560 fragment_kind,561 expansion_data: ExpansionData {562 id: expn_id,563 ..self.cx.current_expansion.clone()564 },565 },566 None,567 ));568 NodeId::placeholder_from_expn_id(expn_id)569 })570 .collect::<Vec<_>>()571 })572 .unwrap_or_default();573574 let (expanded_fragment, collected_invocations) =575 self.collect_invocations(fragment, &derive_placeholders);576 // We choose to expand any derive invocations associated with this macro577 // invocation *before* any macro invocations collected from the output578 // fragment.579 derive_invocations.extend(collected_invocations);580581 progress = true;582 if expanded_fragments.len() < depth {583 expanded_fragments.push(Vec::new());584 }585 expanded_fragments[depth - 1].push((expn_id, expanded_fragment));586 expanded_fragments_len += 1;587 invocations.extend(derive_invocations.into_iter().rev());588 }589 ExpandResult::Retry(invoc) => {590 if force {591 self.cx.dcx().span_bug(592 invoc.span(),593 "expansion entered force mode but is still stuck",594 );595 } else {596 // Cannot expand, will retry this invocation later.597 undetermined_invocations.push((invoc, Some(ext)));598 }599 }600 }601 }602603 self.cx.current_expansion = orig_expansion_data;604 self.cx.force_mode = orig_force_mode;605606 // Finally incorporate all the expanded macros into the input AST fragment.607 let mut placeholder_expander = PlaceholderExpander::with_capacity(expanded_fragments_len);608 while let Some(expanded_fragments) = expanded_fragments.pop() {609 for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {610 placeholder_expander611 .add(NodeId::placeholder_from_expn_id(expn_id), expanded_fragment);612 }613 }614 fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);615 fragment_with_placeholders616 }617618 fn resolve_imports(&mut self) {619 if self.monotonic {620 self.cx.resolver.resolve_imports();621 }622 }623624 /// Collects all macro invocations reachable at this time in this AST fragment, and replace625 /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.626 /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and627 /// prepares data for resolving paths of macro invocations.628 fn collect_invocations(629 &mut self,630 mut fragment: AstFragment,631 extra_placeholders: &[NodeId],632 ) -> (AstFragment, Vec<(Invocation, Option<Arc<SyntaxExtension>>)>) {633 // Resolve `$crate`s in the fragment for pretty-printing.634 self.cx.resolver.resolve_dollar_crates();635636 let mut invocations = {637 let mut collector = InvocationCollector {638 // Non-derive macro invocations cannot see the results of cfg expansion - they639 // will either be removed along with the item, or invoked before the cfg/cfg_attr640 // attribute is expanded. Therefore, we don't need to configure the tokens641 // Derive macros *can* see the results of cfg-expansion - they are handled642 // specially in `fully_expand_fragment`643 cx: self.cx,644 invocations: Vec::new(),645 monotonic: self.monotonic,646 };647 fragment.mut_visit_with(&mut collector);648 fragment.add_placeholders(extra_placeholders);649 collector.invocations650 };651652 if self.monotonic {653 self.cx654 .resolver655 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);656657 if self.cx.sess.opts.incremental.is_some() {658 for (invoc, _) in invocations.iter_mut() {659 let expn_id = invoc.expansion_data.id;660 let parent_def = self.cx.resolver.invocation_parent(expn_id);661 let span = invoc.span_mut();662 *span = span.with_parent(Some(parent_def));663 }664 }665 }666667 (fragment, invocations)668 }669670 fn error_recursion_limit_reached(&mut self) -> ErrorGuaranteed {671 let expn_data = self.cx.current_expansion.id.expn_data();672 let suggested_limit = match self.cx.ecfg.recursion_limit {673 Limit(0) => Limit(2),674 limit => limit * 2,675 };676677 let guar = self.cx.dcx().emit_err(RecursionLimitReached {678 span: expn_data.call_site,679 descr: expn_data.kind.descr(),680 suggested_limit,681 crate_name: self.cx.ecfg.crate_name,682 });683684 self.cx.macro_error_and_trace_macros_diag();685 guar686 }687688 /// A macro's expansion does not fit in this fragment kind.689 /// For example, a non-type macro in a type position.690 fn error_wrong_fragment_kind(691 &mut self,692 kind: AstFragmentKind,693 mac: &ast::MacCall,694 span: Span,695 ) -> ErrorGuaranteed {696 let name = pprust::path_to_string(&mac.path);697 let guar = self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name });698 self.cx.macro_error_and_trace_macros_diag();699 guar700 }701702 fn expand_invoc(703 &mut self,704 invoc: Invocation,705 ext: &SyntaxExtensionKind,706 ) -> ExpandResult<AstFragment, Invocation> {707 let recursion_limit = match self.cx.reduced_recursion_limit {708 Some((limit, _)) => limit,709 None => self.cx.ecfg.recursion_limit,710 };711712 if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) {713 let guar = match self.cx.reduced_recursion_limit {714 Some((_, guar)) => guar,715 None => self.error_recursion_limit_reached(),716 };717718 // Reduce the recursion limit by half each time it triggers.719 self.cx.reduced_recursion_limit = Some((recursion_limit / 2, guar));720721 return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar));722 }723724 let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats;725726 let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());727 ExpandResult::Ready(match invoc.kind {728 InvocationKind::Bang { mac, span } => {729 if let SyntaxExtensionKind::Bang(expander) = ext {730 match expander.expand(self.cx, span, mac.args.tokens.clone()) {731 Ok(tok_result) => {732 let fragment =733 self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span);734 if macro_stats {735 update_bang_macro_stats(736 self.cx,737 fragment_kind,738 span,739 mac,740 &fragment,741 );742 }743 fragment744 }745 Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),746 }747 } else if let Some(expander) = ext.as_legacy_bang() {748 let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {749 ExpandResult::Ready(tok_result) => tok_result,750 ExpandResult::Retry(_) => {751 // retry the original752 return ExpandResult::Retry(Invocation {753 kind: InvocationKind::Bang { mac, span },754 ..invoc755 });756 }757 };758 if let Some(fragment) = fragment_kind.make_from(tok_result) {759 if macro_stats {760 update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment);761 }762 fragment763 } else {764 let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);765 fragment_kind.dummy(span, guar)766 }767 } else {768 unreachable!();769 }770 }771 InvocationKind::Attr { attr, pos, mut item, derives } => {772 if let Some(expander) = ext.as_attr() {773 self.gate_proc_macro_input(&item);774 self.gate_proc_macro_attr_item(span, &item);775 let tokens = match &item {776 // FIXME: Collect tokens and use them instead of generating777 // fake ones. These are unstable, so it needs to be778 // fixed prior to stabilization779 // Fake tokens when we are invoking an inner attribute, and780 // we are invoking it on an out-of-line module or crate.781 Annotatable::Crate(krate) => {782 rustc_parse::fake_token_stream_for_crate(&self.cx.sess.psess, krate)783 }784 Annotatable::Item(item_inner)785 if matches!(attr.style, AttrStyle::Inner)786 && matches!(787 item_inner.kind,788 ItemKind::Mod(789 _,790 _,791 ModKind::Unloaded792 | ModKind::Loaded(_, Inline::No { .. }, _),793 )794 ) =>795 {796 rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)797 }798 Annotatable::Item(item_inner) if item_inner.tokens.is_none() => {799 rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)800 }801 // When a function has EII implementations attached (via `eii_impls`),802 // use fake tokens so the pretty-printer re-emits the EII attribute803 // (e.g. `#[hello]`) in the token stream. Without this, the EII804 // attribute is lost during the token roundtrip performed by805 // `AttrProcMacro` expanders like `contracts::requires/ensures`,806 // breaking the EII link on the resulting re-parsed item.807 Annotatable::Item(item_inner)808 if matches!(&item_inner.kind,809 ItemKind::Fn(f) if !f.eii_impls.is_empty()) =>810 {811 rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)812 }813 Annotatable::ForeignItem(item_inner) if item_inner.tokens.is_none() => {814 rustc_parse::fake_token_stream_for_foreign_item(815 &self.cx.sess.psess,816 item_inner,817 )818 }819 _ => item.to_tokens(),820 };821 let attr_item = attr.get_normal_item();822 let safety = attr_item.unsafety;823 if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {824 self.cx.dcx().emit_err(UnsupportedKeyValue { span });825 }826 let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens();827 match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) {828 Ok(tok_result) => {829 let fragment = self.parse_ast_fragment(830 tok_result,831 fragment_kind,832 &attr_item.path,833 span,834 );835 if macro_stats {836 update_attr_macro_stats(837 self.cx,838 fragment_kind,839 span,840 &attr_item.path,841 &attr,842 item,843 &fragment,844 );845 }846 fragment847 }848 Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),849 }850 } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {851 // `LegacyAttr` is only used for builtin attribute macros, which have their852 // safety checked by `check_builtin_meta_item`, so we don't need to check853 // `unsafety` here.854 match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {855 Ok(meta) => {856 let item_clone = macro_stats.then(|| item.clone());857 let items = match expander.expand(self.cx, span, &meta, item, false) {858 ExpandResult::Ready(items) => items,859 ExpandResult::Retry(item) => {860 // Reassemble the original invocation for retrying.861 return ExpandResult::Retry(Invocation {862 kind: InvocationKind::Attr { attr, pos, item, derives },863 ..invoc864 });865 }866 };867 if matches!(868 fragment_kind,869 AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr870 ) && items.is_empty()871 {872 let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span });873 fragment_kind.dummy(span, guar)874 } else {875 let fragment = fragment_kind.expect_from_annotatables(items);876 if macro_stats {877 update_attr_macro_stats(878 self.cx,879 fragment_kind,880 span,881 &meta.path,882 &attr,883 item_clone.unwrap(),884 &fragment,885 );886 }887 fragment888 }889 }890 Err(err) => {891 let _guar = err.emit();892 fragment_kind.expect_from_annotatables(iter::once(item))893 }894 }895 } else if let SyntaxExtensionKind::NonMacroAttr = ext {896 // `-Zmacro-stats` ignores these because they don't do any real expansion.897 self.cx.expanded_inert_attrs.mark(&attr);898 item.visit_attrs(|attrs| attrs.insert(pos, attr));899 fragment_kind.expect_from_annotatables(iter::once(item))900 } else {901 unreachable!();902 }903 }904 InvocationKind::Derive { path, item, is_const } => match ext {905 SyntaxExtensionKind::Derive(expander)906 | SyntaxExtensionKind::LegacyDerive(expander) => {907 if let SyntaxExtensionKind::Derive(..) = ext {908 self.gate_proc_macro_input(&item);909 }910 // The `MetaItem` representing the trait to derive can't911 // have an unsafe around it (as of now).912 let meta = ast::MetaItem {913 unsafety: ast::Safety::Default,914 kind: MetaItemKind::Word,915 span,916 path,917 };918 let items = match expander.expand(self.cx, span, &meta, item, is_const) {919 ExpandResult::Ready(items) => items,920 ExpandResult::Retry(item) => {921 // Reassemble the original invocation for retrying.922 return ExpandResult::Retry(Invocation {923 kind: InvocationKind::Derive { path: meta.path, item, is_const },924 ..invoc925 });926 }927 };928 let fragment = fragment_kind.expect_from_annotatables(items);929 if macro_stats {930 update_derive_macro_stats(931 self.cx,932 fragment_kind,933 span,934 &meta.path,935 &fragment,936 );937 }938 fragment939 }940 SyntaxExtensionKind::MacroRules(expander)941 if expander.kinds().contains(MacroKinds::DERIVE) =>942 {943 if is_const {944 let guar = self945 .cx946 .dcx()947 .span_err(span, "macro `derive` does not support const derives");948 return ExpandResult::Ready(fragment_kind.dummy(span, guar));949 }950 let body = item.to_tokens();951 match expander.expand_derive(self.cx, span, &body) {952 Ok(tok_result) => {953 let fragment =954 self.parse_ast_fragment(tok_result, fragment_kind, &path, span);955 if macro_stats {956 update_derive_macro_stats(957 self.cx,958 fragment_kind,959 span,960 &path,961 &fragment,962 );963 }964 fragment965 }966 Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),967 }968 }969 _ => unreachable!(),970 },971 InvocationKind::GlobDelegation { item, of_trait } => {972 let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };973 let suffixes = match ext {974 SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx)975 {976 ExpandResult::Ready(suffixes) => suffixes,977 ExpandResult::Retry(()) => {978 // Reassemble the original invocation for retrying.979 return ExpandResult::Retry(Invocation {980 kind: InvocationKind::GlobDelegation { item, of_trait },981 ..invoc982 });983 }984 },985 SyntaxExtensionKind::Bang(..) => {986 let msg = "expanded a dummy glob delegation";987 let guar = self.cx.dcx().span_delayed_bug(span, msg);988 return ExpandResult::Ready(fragment_kind.dummy(span, guar));989 }990 _ => unreachable!(),991 };992993 type Node = AstNodeWrapper<Box<ast::AssocItem>, ImplItemTag>;994 let single_delegations = build_single_delegations::<Node>(995 self.cx, deleg, &item, &suffixes, item.span, true,996 );997 // `-Zmacro-stats` ignores these because they don't seem important.998 fragment_kind.expect_from_annotatables(single_delegations.map(|item| {999 Annotatable::AssocItem(Box::new(item), AssocCtxt::Impl { of_trait })1000 }))1001 }1002 })1003 }10041005 fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {1006 let kind = match item {1007 Annotatable::Item(_)1008 | Annotatable::AssocItem(..)1009 | Annotatable::ForeignItem(_)1010 | Annotatable::Crate(..) => return,1011 Annotatable::Stmt(stmt) => {1012 // Attributes are stable on item statements,1013 // but unstable on all other kinds of statements1014 if stmt.is_item() {1015 return;1016 }1017 "statements"1018 }1019 Annotatable::Expr(_) => "expressions",1020 Annotatable::Arm(..)1021 | Annotatable::ExprField(..)1022 | Annotatable::PatField(..)1023 | Annotatable::GenericParam(..)1024 | Annotatable::Param(..)1025 | Annotatable::FieldDef(..)1026 | Annotatable::Variant(..)1027 | Annotatable::WherePredicate(..) => panic!("unexpected annotatable"),1028 };1029 if self.cx.ecfg.features.proc_macro_hygiene() {1030 return;1031 }1032 feature_err(1033 self.cx.sess,1034 sym::proc_macro_hygiene,1035 span,1036 format!("custom attributes cannot be applied to {kind}"),1037 )1038 .emit();1039 }10401041 fn gate_proc_macro_input(&self, annotatable: &Annotatable) {1042 struct GateProcMacroInput<'a> {1043 sess: &'a Session,1044 }10451046 impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {1047 fn visit_item(&mut self, item: &'ast ast::Item) {1048 match &item.kind {1049 ItemKind::Mod(_, _, mod_kind)1050 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>1051 {1052 feature_err(1053 self.sess,1054 sym::proc_macro_hygiene,1055 item.span,1056 msg!("file modules in proc macro input are unstable"),1057 )1058 .emit();1059 }1060 _ => {}1061 }10621063 visit::walk_item(self, item);1064 }1065 }10661067 if !self.cx.ecfg.features.proc_macro_hygiene() {1068 annotatable.visit_with(&mut GateProcMacroInput { sess: self.cx.sess });1069 }1070 }10711072 fn parse_ast_fragment(1073 &mut self,1074 toks: TokenStream,1075 kind: AstFragmentKind,1076 path: &ast::Path,1077 span: Span,1078 ) -> AstFragment {1079 let mut parser = self.cx.new_parser_from_tts(toks);1080 match parse_ast_fragment(&mut parser, kind) {1081 Ok(fragment) => {1082 ensure_complete_parse(&parser, path, kind.name(), span);1083 fragment1084 }1085 Err(mut err) => {1086 if err.span.is_dummy() {1087 err.span(span);1088 }1089 annotate_err_with_kind(&mut err, kind, span);1090 let guar = err.emit();1091 self.cx.macro_error_and_trace_macros_diag();1092 kind.dummy(span, guar)1093 }1094 }1095 }1096}10971098pub fn parse_ast_fragment<'a>(1099 this: &mut Parser<'a>,1100 kind: AstFragmentKind,1101) -> PResult<'a, AstFragment> {1102 Ok(match kind {1103 AstFragmentKind::Items => {1104 let mut items = SmallVec::new();1105 while let Some(item) = this.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)? {1106 items.push(item);1107 }1108 AstFragment::Items(items)1109 }1110 AstFragmentKind::TraitItems => {1111 let mut items = SmallVec::new();1112 while let Some(item) = this.parse_trait_item(ForceCollect::No)? {1113 items.extend(item);1114 }1115 AstFragment::TraitItems(items)1116 }1117 AstFragmentKind::ImplItems => {1118 let mut items = SmallVec::new();1119 while let Some(item) = this.parse_impl_item(ForceCollect::No)? {1120 items.extend(item);1121 }1122 AstFragment::ImplItems(items)1123 }1124 AstFragmentKind::TraitImplItems => {1125 let mut items = SmallVec::new();1126 while let Some(item) = this.parse_impl_item(ForceCollect::No)? {1127 items.extend(item);1128 }1129 AstFragment::TraitImplItems(items)1130 }1131 AstFragmentKind::ForeignItems => {1132 let mut items = SmallVec::new();1133 while let Some(item) = this.parse_foreign_item(ForceCollect::No)? {1134 items.extend(item);1135 }1136 AstFragment::ForeignItems(items)1137 }1138 AstFragmentKind::Stmts => {1139 let mut stmts = SmallVec::new();1140 // Won't make progress on a `}`.1141 while this.token != token::Eof && this.token != token::CloseBrace {1142 if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {1143 stmts.push(stmt);1144 }1145 }1146 AstFragment::Stmts(stmts)1147 }1148 AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),1149 AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?),1150 AstFragmentKind::OptExpr => {1151 if this.token != token::Eof {1152 AstFragment::OptExpr(Some(this.parse_expr()?))1153 } else {1154 AstFragment::OptExpr(None)1155 }1156 }1157 AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),1158 AstFragmentKind::Pat => AstFragment::Pat(Box::new(this.parse_pat_allow_top_guard(1159 None,1160 RecoverComma::No,1161 RecoverColon::Yes,1162 CommaRecoveryMode::LikelyTuple,1163 )?)),1164 AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),1165 AstFragmentKind::Arms1166 | AstFragmentKind::ExprFields1167 | AstFragmentKind::PatFields1168 | AstFragmentKind::GenericParams1169 | AstFragmentKind::Params1170 | AstFragmentKind::FieldDefs1171 | AstFragmentKind::Variants1172 | AstFragmentKind::WherePredicates => panic!("unexpected AST fragment kind"),1173 })1174}11751176pub(crate) fn ensure_complete_parse<'a>(1177 parser: &Parser<'a>,1178 macro_path: &ast::Path,1179 kind_name: &str,1180 span: Span,1181) {1182 if parser.token != token::Eof {1183 let descr = token_descr(&parser.token);1184 // Avoid emitting backtrace info twice.1185 let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());11861187 let semi_span = parser.psess.source_map().next_point(span);1188 let add_semicolon = match &parser.psess.source_map().span_to_snippet(semi_span) {1189 Ok(snippet) if &snippet[..] != ";" && kind_name == "expression" => {1190 Some(span.shrink_to_hi())1191 }1192 _ => None,1193 };11941195 let expands_to_match_arm = kind_name == "pattern" && parser.token == token::FatArrow;11961197 parser.dcx().emit_err(IncompleteParse {1198 span: def_site_span,1199 descr,1200 label_span: span,1201 macro_path: pprust::path_to_string(macro_path),1202 kind_name,1203 expands_to_match_arm,1204 add_semicolon,1205 });1206 }1207}12081209/// Wraps a call to `walk_*` / `walk_flat_map_*`1210/// for an AST node that supports attributes1211/// (see the `Annotatable` enum)1212/// This method assigns a `NodeId`, and sets that `NodeId`1213/// as our current 'lint node id'. If a macro call is found1214/// inside this AST node, we will use this AST node's `NodeId`1215/// to emit lints associated with that macro (allowing1216/// `#[allow]` / `#[deny]` to be applied close to1217/// the macro invocation).1218///1219/// Do *not* call this for a macro AST node1220/// (e.g. `ExprKind::MacCall`) - we cannot emit lints1221/// at these AST nodes, since they are removed and1222/// replaced with the result of macro expansion.1223///1224/// All other `NodeId`s are assigned by `visit_id`.1225/// * `self` is the 'self' parameter for the current method,1226/// * `id` is a mutable reference to the `NodeId` field1227/// of the current AST node.1228/// * `closure` is a closure that executes the1229/// `walk_*` / `walk_flat_map_*` method1230/// for the current AST node.1231macro_rules! assign_id {1232 ($self:ident, $id:expr, $closure:expr) => {{1233 let old_id = $self.cx.current_expansion.lint_node_id;1234 if $self.monotonic {1235 debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);1236 let new_id = $self.cx.resolver.next_node_id();1237 *$id = new_id;1238 $self.cx.current_expansion.lint_node_id = new_id;1239 }1240 let ret = ($closure)();1241 $self.cx.current_expansion.lint_node_id = old_id;1242 ret1243 }};1244}12451246enum AddSemicolon {1247 Yes,1248 No,1249}12501251/// A trait implemented for all `AstFragment` nodes and providing all pieces1252/// of functionality used by `InvocationCollector`.1253trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {1254 type OutputTy = SmallVec<[Self; 1]>;1255 type ItemKind = ItemKind;1256 const KIND: AstFragmentKind;1257 fn to_annotatable(self) -> Annotatable;1258 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;1259 fn descr() -> &'static str {1260 unreachable!()1261 }1262 fn walk_flat_map(self, _collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1263 unreachable!()1264 }1265 fn walk(&mut self, _collector: &mut InvocationCollector<'_, '_>) {1266 unreachable!()1267 }1268 fn is_mac_call(&self) -> bool {1269 false1270 }1271 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1272 unreachable!()1273 }1274 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1275 None1276 }1277 fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {1278 unreachable!()1279 }1280 fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {1281 unreachable!()1282 }1283 fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1284 unreachable!()1285 }1286 fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}1287 fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {1288 }1289 fn wrap_flat_map_node_walk_flat_map(1290 node: Self,1291 collector: &mut InvocationCollector<'_, '_>,1292 walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,1293 ) -> Result<Self::OutputTy, Self> {1294 Ok(walk_flat_map(node, collector))1295 }1296 fn expand_cfg_false(1297 &mut self,1298 collector: &mut InvocationCollector<'_, '_>,1299 _pos: usize,1300 span: Span,1301 ) {1302 collector.cx.dcx().emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });1303 }13041305 /// All of the identifiers (items) declared by this node.1306 /// This is an approximation and should only be used for diagnostics.1307 fn declared_idents(&self) -> Vec<Ident> {1308 vec![]1309 }13101311 fn as_target(&self) -> Target;1312}13131314impl InvocationCollectorNode for Box<ast::Item> {1315 const KIND: AstFragmentKind = AstFragmentKind::Items;1316 fn to_annotatable(self) -> Annotatable {1317 Annotatable::Item(self)1318 }1319 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1320 fragment.make_items()1321 }1322 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1323 walk_flat_map_item(collector, self)1324 }1325 fn is_mac_call(&self) -> bool {1326 matches!(self.kind, ItemKind::MacCall(..))1327 }1328 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1329 match self.kind {1330 ItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),1331 _ => unreachable!(),1332 }1333 }1334 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1335 match &self.kind {1336 ItemKind::DelegationMac(deleg) => Some((deleg, self)),1337 _ => None,1338 }1339 }1340 fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {1341 ItemKind::Delegation(deleg)1342 }1343 fn from_item(item: ast::Item<Self::ItemKind>) -> Self {1344 Box::new(item)1345 }1346 fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1347 items.flatten().collect()1348 }1349 fn wrap_flat_map_node_walk_flat_map(1350 mut node: Self,1351 collector: &mut InvocationCollector<'_, '_>,1352 walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,1353 ) -> Result<Self::OutputTy, Self> {1354 if !matches!(node.kind, ItemKind::Mod(..)) {1355 return Ok(walk_flat_map(node, collector));1356 }13571358 // Work around borrow checker not seeing through `P`'s deref.1359 let (span, mut attrs) = (node.span, mem::take(&mut node.attrs));1360 let ItemKind::Mod(_, ident, ref mut mod_kind) = node.kind else { unreachable!() };1361 let ecx = &mut collector.cx;1362 let (file_path, dir_path, dir_ownership) = match mod_kind {1363 ModKind::Loaded(_, inline, _) => {1364 // Inline `mod foo { ... }`, but we still need to push directories.1365 let (dir_path, dir_ownership) = mod_dir_path(1366 ecx.sess,1367 ident,1368 &attrs,1369 &ecx.current_expansion.module,1370 ecx.current_expansion.dir_ownership,1371 *inline,1372 );1373 // If the module was parsed from an external file, recover its path.1374 // This lets `parse_external_mod` catch cycles if it's self-referential.1375 let file_path = match inline {1376 Inline::Yes => None,1377 Inline::No { .. } => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path),1378 };1379 node.attrs = attrs;1380 (file_path, dir_path, dir_ownership)1381 }1382 ModKind::Unloaded => {1383 // We have an outline `mod foo;` so we need to parse the file.1384 let old_attrs_len = attrs.len();1385 let ParsedExternalMod {1386 items,1387 spans,1388 file_path,1389 dir_path,1390 dir_ownership,1391 had_parse_error,1392 } = parse_external_mod(1393 ecx.sess,1394 ident,1395 span,1396 &ecx.current_expansion.module,1397 ecx.current_expansion.dir_ownership,1398 &mut attrs,1399 );14001401 if let Some(lint_store) = ecx.lint_store {1402 lint_store.pre_expansion_lint(1403 ecx.sess,1404 ecx.ecfg.features,1405 ecx.resolver.registered_tools(),1406 ecx.current_expansion.lint_node_id,1407 &attrs,1408 &items,1409 ident.name,1410 );1411 }14121413 *mod_kind = ModKind::Loaded(items, Inline::No { had_parse_error }, spans);1414 node.attrs = attrs;1415 if node.attrs.len() > old_attrs_len {1416 // If we loaded an out-of-line module and added some inner attributes,1417 // then we need to re-configure it and re-collect attributes for1418 // resolution and expansion.1419 return Err(node);1420 }1421 (Some(file_path), dir_path, dir_ownership)1422 }1423 };14241425 // Set the module info before we flat map.1426 let mut module = ecx.current_expansion.module.with_dir_path(dir_path);1427 module.mod_path.push(ident);1428 if let Some(file_path) = file_path {1429 module.file_path_stack.push(file_path);1430 }14311432 let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module));1433 let orig_dir_ownership =1434 mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);14351436 let res = Ok(walk_flat_map(node, collector));14371438 collector.cx.current_expansion.dir_ownership = orig_dir_ownership;1439 collector.cx.current_expansion.module = orig_module;1440 res1441 }14421443 fn declared_idents(&self) -> Vec<Ident> {1444 if let ItemKind::Use(ut) = &self.kind {1445 fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {1446 match &ut.kind {1447 ast::UseTreeKind::Glob(_) => {}1448 ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),1449 ast::UseTreeKind::Nested { items, .. } => {1450 for (ut, _) in items {1451 collect_use_tree_leaves(ut, idents);1452 }1453 }1454 }1455 }1456 let mut idents = Vec::new();1457 collect_use_tree_leaves(ut, &mut idents);1458 idents1459 } else {1460 self.kind.ident().into_iter().collect()1461 }1462 }14631464 fn as_target(&self) -> Target {1465 Target::from_ast_item(self)1466 }1467}14681469struct TraitItemTag;1470impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, TraitItemTag> {1471 type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>;1472 type ItemKind = AssocItemKind;1473 const KIND: AstFragmentKind = AstFragmentKind::TraitItems;1474 fn to_annotatable(self) -> Annotatable {1475 Annotatable::AssocItem(self.wrapped, AssocCtxt::Trait)1476 }1477 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1478 fragment.make_trait_items()1479 }1480 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1481 walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Trait)1482 }1483 fn is_mac_call(&self) -> bool {1484 matches!(self.wrapped.kind, AssocItemKind::MacCall(..))1485 }1486 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1487 let item = self.wrapped;1488 match item.kind {1489 AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),1490 _ => unreachable!(),1491 }1492 }1493 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1494 match &self.wrapped.kind {1495 AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),1496 _ => None,1497 }1498 }1499 fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {1500 AssocItemKind::Delegation(deleg)1501 }1502 fn from_item(item: ast::Item<Self::ItemKind>) -> Self {1503 AstNodeWrapper::new(Box::new(item), TraitItemTag)1504 }1505 fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1506 items.flatten().collect()1507 }1508 fn as_target(&self) -> Target {1509 Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Trait)1510 }1511}15121513struct ImplItemTag;1514impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, ImplItemTag> {1515 type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>;1516 type ItemKind = AssocItemKind;1517 const KIND: AstFragmentKind = AstFragmentKind::ImplItems;1518 fn to_annotatable(self) -> Annotatable {1519 Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: false })1520 }1521 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1522 fragment.make_impl_items()1523 }1524 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1525 walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: false })1526 }1527 fn is_mac_call(&self) -> bool {1528 matches!(self.wrapped.kind, AssocItemKind::MacCall(..))1529 }1530 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1531 let item = self.wrapped;1532 match item.kind {1533 AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),1534 _ => unreachable!(),1535 }1536 }1537 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1538 match &self.wrapped.kind {1539 AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),1540 _ => None,1541 }1542 }1543 fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {1544 AssocItemKind::Delegation(deleg)1545 }1546 fn from_item(item: ast::Item<Self::ItemKind>) -> Self {1547 AstNodeWrapper::new(Box::new(item), ImplItemTag)1548 }1549 fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1550 items.flatten().collect()1551 }1552 fn as_target(&self) -> Target {1553 Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Impl { of_trait: false })1554 }1555}15561557struct TraitImplItemTag;1558impl InvocationCollectorNode for AstNodeWrapper<Box<ast::AssocItem>, TraitImplItemTag> {1559 type OutputTy = SmallVec<[Box<ast::AssocItem>; 1]>;1560 type ItemKind = AssocItemKind;1561 const KIND: AstFragmentKind = AstFragmentKind::TraitImplItems;1562 fn to_annotatable(self) -> Annotatable {1563 Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl { of_trait: true })1564 }1565 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1566 fragment.make_trait_impl_items()1567 }1568 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1569 walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: true })1570 }1571 fn is_mac_call(&self) -> bool {1572 matches!(self.wrapped.kind, AssocItemKind::MacCall(..))1573 }1574 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1575 let item = self.wrapped;1576 match item.kind {1577 AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),1578 _ => unreachable!(),1579 }1580 }1581 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1582 match &self.wrapped.kind {1583 AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),1584 _ => None,1585 }1586 }1587 fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {1588 AssocItemKind::Delegation(deleg)1589 }1590 fn from_item(item: ast::Item<Self::ItemKind>) -> Self {1591 AstNodeWrapper::new(Box::new(item), TraitImplItemTag)1592 }1593 fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1594 items.flatten().collect()1595 }1596 fn as_target(&self) -> Target {1597 Target::from_assoc_item_kind(&self.wrapped.kind, AssocCtxt::Impl { of_trait: true })1598 }1599}16001601impl InvocationCollectorNode for Box<ast::ForeignItem> {1602 const KIND: AstFragmentKind = AstFragmentKind::ForeignItems;1603 fn to_annotatable(self) -> Annotatable {1604 Annotatable::ForeignItem(self)1605 }1606 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1607 fragment.make_foreign_items()1608 }1609 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1610 walk_flat_map_foreign_item(collector, self)1611 }1612 fn is_mac_call(&self) -> bool {1613 matches!(self.kind, ForeignItemKind::MacCall(..))1614 }1615 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1616 match self.kind {1617 ForeignItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),1618 _ => unreachable!(),1619 }1620 }1621 fn as_target(&self) -> Target {1622 match &self.kind {1623 ForeignItemKind::Static(_) => Target::ForeignStatic,1624 ForeignItemKind::Fn(_) => Target::ForeignFn,1625 ForeignItemKind::TyAlias(_) => Target::ForeignTy,1626 ForeignItemKind::MacCall(_) => Target::MacroCall,1627 }1628 }1629}16301631impl InvocationCollectorNode for ast::Variant {1632 const KIND: AstFragmentKind = AstFragmentKind::Variants;1633 fn to_annotatable(self) -> Annotatable {1634 Annotatable::Variant(self)1635 }1636 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1637 fragment.make_variants()1638 }1639 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1640 walk_flat_map_variant(collector, self)1641 }1642 fn as_target(&self) -> Target {1643 Target::Variant1644 }1645}16461647impl InvocationCollectorNode for ast::WherePredicate {1648 const KIND: AstFragmentKind = AstFragmentKind::WherePredicates;1649 fn to_annotatable(self) -> Annotatable {1650 Annotatable::WherePredicate(self)1651 }1652 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1653 fragment.make_where_predicates()1654 }1655 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1656 walk_flat_map_where_predicate(collector, self)1657 }1658 fn as_target(&self) -> Target {1659 Target::WherePredicate1660 }1661}16621663impl InvocationCollectorNode for ast::FieldDef {1664 const KIND: AstFragmentKind = AstFragmentKind::FieldDefs;1665 fn to_annotatable(self) -> Annotatable {1666 Annotatable::FieldDef(self)1667 }1668 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1669 fragment.make_field_defs()1670 }1671 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1672 walk_flat_map_field_def(collector, self)1673 }1674 fn as_target(&self) -> Target {1675 Target::Field1676 }1677}16781679impl InvocationCollectorNode for ast::PatField {1680 const KIND: AstFragmentKind = AstFragmentKind::PatFields;1681 fn to_annotatable(self) -> Annotatable {1682 Annotatable::PatField(self)1683 }1684 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1685 fragment.make_pat_fields()1686 }1687 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1688 walk_flat_map_pat_field(collector, self)1689 }1690 fn as_target(&self) -> Target {1691 Target::PatField1692 }1693}16941695impl InvocationCollectorNode for ast::ExprField {1696 const KIND: AstFragmentKind = AstFragmentKind::ExprFields;1697 fn to_annotatable(self) -> Annotatable {1698 Annotatable::ExprField(self)1699 }1700 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1701 fragment.make_expr_fields()1702 }1703 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1704 walk_flat_map_expr_field(collector, self)1705 }1706 fn as_target(&self) -> Target {1707 Target::ExprField1708 }1709}17101711impl InvocationCollectorNode for ast::Param {1712 const KIND: AstFragmentKind = AstFragmentKind::Params;1713 fn to_annotatable(self) -> Annotatable {1714 Annotatable::Param(self)1715 }1716 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1717 fragment.make_params()1718 }1719 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1720 walk_flat_map_param(collector, self)1721 }1722 fn as_target(&self) -> Target {1723 Target::Param1724 }1725}17261727impl InvocationCollectorNode for ast::GenericParam {1728 const KIND: AstFragmentKind = AstFragmentKind::GenericParams;1729 fn to_annotatable(self) -> Annotatable {1730 Annotatable::GenericParam(self)1731 }1732 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1733 fragment.make_generic_params()1734 }1735 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1736 walk_flat_map_generic_param(collector, self)1737 }1738 fn as_target(&self) -> Target {1739 let mut has_default = false;1740 Target::GenericParam {1741 kind: match &self.kind {1742 rustc_ast::GenericParamKind::Lifetime => {1743 rustc_hir::target::GenericParamKind::Lifetime1744 }1745 rustc_ast::GenericParamKind::Type { default } => {1746 has_default = default.is_some();1747 rustc_hir::target::GenericParamKind::Type1748 }1749 rustc_ast::GenericParamKind::Const { default, .. } => {1750 has_default = default.is_some();1751 rustc_hir::target::GenericParamKind::Const1752 }1753 },1754 has_default,1755 }1756 }1757}17581759impl InvocationCollectorNode for ast::Arm {1760 const KIND: AstFragmentKind = AstFragmentKind::Arms;1761 fn to_annotatable(self) -> Annotatable {1762 Annotatable::Arm(self)1763 }1764 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1765 fragment.make_arms()1766 }1767 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1768 walk_flat_map_arm(collector, self)1769 }1770 fn as_target(&self) -> Target {1771 Target::Arm1772 }1773}17741775impl InvocationCollectorNode for ast::Stmt {1776 const KIND: AstFragmentKind = AstFragmentKind::Stmts;1777 fn to_annotatable(self) -> Annotatable {1778 Annotatable::Stmt(Box::new(self))1779 }1780 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1781 fragment.make_stmts()1782 }1783 fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1784 walk_flat_map_stmt(collector, self)1785 }1786 fn is_mac_call(&self) -> bool {1787 match &self.kind {1788 StmtKind::MacCall(..) => true,1789 StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),1790 StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),1791 StmtKind::Expr(..) => unreachable!(),1792 StmtKind::Let(..) | StmtKind::Empty => false,1793 }1794 }1795 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1796 // We pull macro invocations (both attributes and fn-like macro calls) out of their1797 // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.1798 let (add_semicolon, mac, attrs) = match self.kind {1799 StmtKind::MacCall(mac) => {1800 let ast::MacCallStmt { mac, style, attrs, .. } = *mac;1801 (style == MacStmtStyle::Semicolon, mac, attrs)1802 }1803 StmtKind::Item(item) => match *item {1804 ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {1805 (mac.args.need_semicolon(), mac, attrs)1806 }1807 _ => unreachable!(),1808 },1809 StmtKind::Semi(expr) => match *expr {1810 ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {1811 (mac.args.need_semicolon(), mac, attrs)1812 }1813 _ => unreachable!(),1814 },1815 _ => unreachable!(),1816 };1817 (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })1818 }1819 fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {1820 match &self.kind {1821 StmtKind::Item(item) => match &item.kind {1822 ItemKind::DelegationMac(deleg) => Some((deleg, item)),1823 _ => None,1824 },1825 _ => None,1826 }1827 }1828 fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {1829 ItemKind::Delegation(deleg)1830 }1831 fn from_item(item: ast::Item<Self::ItemKind>) -> Self {1832 ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(Box::new(item)) }1833 }1834 fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {1835 items.flatten().collect()1836 }1837 fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {1838 // If this is a macro invocation with a semicolon, then apply that1839 // semicolon to the final statement produced by expansion.1840 if matches!(add_semicolon, AddSemicolon::Yes) {1841 if let Some(stmt) = stmts.pop() {1842 stmts.push(stmt.add_trailing_semicolon());1843 }1844 }1845 }1846 fn as_target(&self) -> Target {1847 Target::Statement1848 }1849}18501851impl InvocationCollectorNode for ast::Crate {1852 type OutputTy = ast::Crate;1853 const KIND: AstFragmentKind = AstFragmentKind::Crate;1854 fn to_annotatable(self) -> Annotatable {1855 Annotatable::Crate(self)1856 }1857 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1858 fragment.make_crate()1859 }1860 fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) {1861 walk_crate(collector, self)1862 }1863 fn expand_cfg_false(1864 &mut self,1865 collector: &mut InvocationCollector<'_, '_>,1866 pos: usize,1867 _span: Span,1868 ) {1869 // Attributes above `cfg(FALSE)` are left in place, because we may want to configure1870 // some global crate properties even on fully unconfigured crates.1871 self.attrs.truncate(pos);1872 // Standard prelude imports are left in the crate for backward compatibility.1873 self.items.truncate(collector.cx.num_standard_library_imports);1874 }1875 fn as_target(&self) -> Target {1876 Target::Crate1877 }1878}18791880impl InvocationCollectorNode for ast::Ty {1881 type OutputTy = Box<ast::Ty>;1882 const KIND: AstFragmentKind = AstFragmentKind::Ty;1883 fn to_annotatable(self) -> Annotatable {1884 unreachable!()1885 }1886 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1887 fragment.make_ty()1888 }1889 fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) {1890 // Save the pre-expanded name of this `ImplTrait`, so that later when defining1891 // an APIT we use a name that doesn't have any placeholder fragments in it.1892 if let ast::TyKind::ImplTrait(..) = self.kind {1893 // HACK: pprust breaks strings with newlines when the type1894 // gets too long. We don't want these to show up in compiler1895 // output or built artifacts, so replace them here...1896 // Perhaps we should instead format APITs more robustly.1897 let name = Symbol::intern(&pprust::ty_to_string(self).replace('\n', " "));1898 collector.cx.resolver.insert_impl_trait_name(self.id, name);1899 }1900 walk_ty(collector, self)1901 }1902 fn is_mac_call(&self) -> bool {1903 matches!(self.kind, ast::TyKind::MacCall(..))1904 }1905 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1906 match self.kind {1907 TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),1908 _ => unreachable!(),1909 }1910 }1911 fn as_target(&self) -> Target {1912 // This is only used for attribute parsing, which are not allowed on types.1913 unreachable!()1914 }1915}19161917impl InvocationCollectorNode for ast::Pat {1918 type OutputTy = Box<ast::Pat>;1919 const KIND: AstFragmentKind = AstFragmentKind::Pat;1920 fn to_annotatable(self) -> Annotatable {1921 unreachable!()1922 }1923 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1924 fragment.make_pat()1925 }1926 fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) {1927 walk_pat(collector, self)1928 }1929 fn is_mac_call(&self) -> bool {1930 matches!(self.kind, PatKind::MacCall(..))1931 }1932 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1933 match self.kind {1934 PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),1935 _ => unreachable!(),1936 }1937 }1938 fn as_target(&self) -> Target {1939 todo!();1940 }1941}19421943impl InvocationCollectorNode for ast::Expr {1944 type OutputTy = Box<ast::Expr>;1945 const KIND: AstFragmentKind = AstFragmentKind::Expr;1946 fn to_annotatable(self) -> Annotatable {1947 Annotatable::Expr(Box::new(self))1948 }1949 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1950 fragment.make_expr()1951 }1952 fn descr() -> &'static str {1953 "an expression"1954 }1955 fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) {1956 walk_expr(collector, self)1957 }1958 fn is_mac_call(&self) -> bool {1959 matches!(self.kind, ExprKind::MacCall(..))1960 }1961 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1962 match self.kind {1963 ExprKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),1964 _ => unreachable!(),1965 }1966 }1967 fn as_target(&self) -> Target {1968 Target::Expression1969 }1970}19711972struct OptExprTag;1973impl InvocationCollectorNode for AstNodeWrapper<Box<ast::Expr>, OptExprTag> {1974 type OutputTy = Option<Box<ast::Expr>>;1975 const KIND: AstFragmentKind = AstFragmentKind::OptExpr;1976 fn to_annotatable(self) -> Annotatable {1977 Annotatable::Expr(self.wrapped)1978 }1979 fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {1980 fragment.make_opt_expr()1981 }1982 fn walk_flat_map(mut self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy {1983 walk_expr(collector, &mut self.wrapped);1984 Some(self.wrapped)1985 }1986 fn is_mac_call(&self) -> bool {1987 matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))1988 }1989 fn take_mac_call(self) -> (Box<ast::MacCall>, ast::AttrVec, AddSemicolon) {1990 let node = self.wrapped;1991 match node.kind {1992 ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),1993 _ => unreachable!(),1994 }1995 }1996 fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {1997 cfg.maybe_emit_expr_attr_err(attr);1998 }1999 fn as_target(&self) -> Target {2000 Target::Expression
Findings
✓ No findings reported for this file.