2 use crate::config
::StripUnconfigured
;
3 use crate::hygiene
::SyntaxContext
;
4 use crate::mbe
::macro_rules
::annotate_err_with_kind
;
5 use crate::module
::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}
;
6 use crate::placeholders
::{placeholder, PlaceholderExpander}
;
9 use rustc_ast
::mut_visit
::*;
10 use rustc_ast
::ptr
::P
;
11 use rustc_ast
::token
::{self, Delimiter}
;
12 use rustc_ast
::tokenstream
::TokenStream
;
13 use rustc_ast
::visit
::{self, AssocCtxt, Visitor}
;
14 use rustc_ast
::{AssocItemKind, AstNodeWrapper, AttrStyle, ExprKind, ForeignItemKind}
;
15 use rustc_ast
::{HasAttrs, HasNodeId}
;
16 use rustc_ast
::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind}
;
17 use rustc_ast
::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}
;
18 use rustc_ast_pretty
::pprust
;
19 use rustc_data_structures
::map_in_place
::MapInPlace
;
20 use rustc_data_structures
::sync
::Lrc
;
21 use rustc_errors
::{Applicability, PResult}
;
22 use rustc_feature
::Features
;
23 use rustc_parse
::parser
::{
24 AttemptLocalParseRecovery
, CommaRecoveryMode
, ForceCollect
, Parser
, RecoverColon
, RecoverComma
,
26 use rustc_parse
::validate_attr
;
27 use rustc_session
::lint
::builtin
::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}
;
28 use rustc_session
::lint
::BuiltinLintDiagnostics
;
29 use rustc_session
::parse
::{feature_err, ParseSess}
;
30 use rustc_session
::Limit
;
31 use rustc_span
::symbol
::{sym, Ident}
;
32 use rustc_span
::{FileName, LocalExpnId, Span}
;
34 use smallvec
::SmallVec
;
36 use std
::path
::PathBuf
;
40 macro_rules
! ast_fragments
{
42 $
($Kind
:ident($AstTy
:ty
) {
44 $
(one
fn $mut_visit_ast
:ident
; fn $visit_ast
:ident
;)?
45 $
(many
fn $flat_map_ast_elt
:ident
; fn $visit_ast_elt
:ident($
($args
:tt
)*);)?
49 /// A fragment of AST that can be produced by a single macro expansion.
50 /// Can also serve as an input and intermediate result for macro expansion operations.
51 pub enum AstFragment
{
52 OptExpr(Option
<P
<ast
::Expr
>>),
56 /// "Discriminant" of an AST fragment.
57 #[derive(Copy, Clone, PartialEq, Eq)]
58 pub enum AstFragmentKind
{
63 impl AstFragmentKind
{
64 pub fn name(self) -> &'
static str {
66 AstFragmentKind
::OptExpr
=> "expression",
67 $
(AstFragmentKind
::$Kind
=> $kind_name
,)*
71 fn make_from
<'a
>(self, result
: Box
<dyn MacResult
+ 'a
>) -> Option
<AstFragment
> {
73 AstFragmentKind
::OptExpr
=>
74 result
.make_expr().map(Some
).map(AstFragment
::OptExpr
),
75 $
(AstFragmentKind
::$Kind
=> result
.$
make_ast().map(AstFragment
::$Kind
),)*
81 pub fn add_placeholders(&mut self, placeholders
: &[NodeId
]) {
82 if placeholders
.is_empty() {
86 $
($
(AstFragment
::$
Kind(ast
) => ast
.extend(placeholders
.iter().flat_map(|id
| {
87 ${ignore(flat_map_ast_elt)}
88 placeholder(AstFragmentKind
::$Kind
, *id
, None
).$
make_ast()
90 _
=> panic
!("unexpected AST fragment kind")
94 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
96 AstFragment
::OptExpr(expr
) => expr
,
97 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
101 $
(pub fn $
make_ast(self) -> $AstTy
{
103 AstFragment
::$
Kind(ast
) => ast
,
104 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
108 fn make_ast
<T
: InvocationCollectorNode
>(self) -> T
::OutputTy
{
109 T
::fragment_to_output(self)
112 pub fn mut_visit_with
<F
: MutVisitor
>(&mut self, vis
: &mut F
) {
114 AstFragment
::OptExpr(opt_expr
) => {
115 visit_clobber(opt_expr
, |opt_expr
| {
116 if let Some(expr
) = opt_expr
{
117 vis
.filter_map_expr(expr
)
123 $
($
(AstFragment
::$
Kind(ast
) => vis
.$
mut_visit_ast(ast
),)?
)*
124 $
($
(AstFragment
::$
Kind(ast
) =>
125 ast
.flat_map_in_place(|ast
| vis
.$
flat_map_ast_elt(ast
)),)?
)*
129 pub fn visit_with
<'a
, V
: Visitor
<'a
>>(&'a
self, visitor
: &mut V
) {
131 AstFragment
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
132 AstFragment
::OptExpr(None
) => {}
133 $
($
(AstFragment
::$
Kind(ref ast
) => visitor
.$
visit_ast(ast
),)?
)*
134 $
($
(AstFragment
::$
Kind(ref ast
) => for ast_elt
in &ast
[..] {
135 visitor
.$
visit_ast_elt(ast_elt
, $
($args
)*);
141 impl<'a
> MacResult
for crate::mbe
::macro_rules
::ParserAnyMacro
<'a
> {
142 $
(fn $
make_ast(self: Box
<crate::mbe
::macro_rules
::ParserAnyMacro
<'a
>>)
144 Some(self.make(AstFragmentKind
::$Kind
).$
make_ast())
151 Expr(P
<ast
::Expr
>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
152 Pat(P
<ast
::Pat
>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
153 Ty(P
<ast
::Ty
>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
154 Stmts(SmallVec
<[ast
::Stmt
; 1]>) {
155 "statement"; many
fn flat_map_stmt
; fn visit_stmt(); fn make_stmts
;
157 Items(SmallVec
<[P
<ast
::Item
>; 1]>) {
158 "item"; many
fn flat_map_item
; fn visit_item(); fn make_items
;
160 TraitItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
162 many
fn flat_map_trait_item
;
163 fn visit_assoc_item(AssocCtxt
::Trait
);
166 ImplItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
168 many
fn flat_map_impl_item
;
169 fn visit_assoc_item(AssocCtxt
::Impl
);
172 ForeignItems(SmallVec
<[P
<ast
::ForeignItem
>; 1]>) {
174 many
fn flat_map_foreign_item
;
175 fn visit_foreign_item();
176 fn make_foreign_items
;
178 Arms(SmallVec
<[ast
::Arm
; 1]>) {
179 "match arm"; many
fn flat_map_arm
; fn visit_arm(); fn make_arms
;
181 ExprFields(SmallVec
<[ast
::ExprField
; 1]>) {
182 "field expression"; many
fn flat_map_expr_field
; fn visit_expr_field(); fn make_expr_fields
;
184 PatFields(SmallVec
<[ast
::PatField
; 1]>) {
186 many
fn flat_map_pat_field
;
187 fn visit_pat_field();
190 GenericParams(SmallVec
<[ast
::GenericParam
; 1]>) {
192 many
fn flat_map_generic_param
;
193 fn visit_generic_param();
194 fn make_generic_params
;
196 Params(SmallVec
<[ast
::Param
; 1]>) {
197 "function parameter"; many
fn flat_map_param
; fn visit_param(); fn make_params
;
199 FieldDefs(SmallVec
<[ast
::FieldDef
; 1]>) {
201 many
fn flat_map_field_def
;
202 fn visit_field_def();
205 Variants(SmallVec
<[ast
::Variant
; 1]>) {
206 "variant"; many
fn flat_map_variant
; fn visit_variant(); fn make_variants
;
208 Crate(ast
::Crate
) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
211 pub enum SupportsMacroExpansion
{
213 Yes { supports_inner_attrs: bool }
,
216 impl AstFragmentKind
{
217 pub(crate) fn dummy(self, span
: Span
) -> AstFragment
{
218 self.make_from(DummyResult
::any(span
)).expect("couldn't create a dummy AST fragment")
221 pub fn supports_macro_expansion(self) -> SupportsMacroExpansion
{
223 AstFragmentKind
::OptExpr
224 | AstFragmentKind
::Expr
225 | AstFragmentKind
::Stmts
226 | AstFragmentKind
::Ty
227 | AstFragmentKind
::Pat
=> SupportsMacroExpansion
::Yes { supports_inner_attrs: false }
,
228 AstFragmentKind
::Items
229 | AstFragmentKind
::TraitItems
230 | AstFragmentKind
::ImplItems
231 | AstFragmentKind
::ForeignItems
232 | AstFragmentKind
::Crate
=> SupportsMacroExpansion
::Yes { supports_inner_attrs: true }
,
233 AstFragmentKind
::Arms
234 | AstFragmentKind
::ExprFields
235 | AstFragmentKind
::PatFields
236 | AstFragmentKind
::GenericParams
237 | AstFragmentKind
::Params
238 | AstFragmentKind
::FieldDefs
239 | AstFragmentKind
::Variants
=> SupportsMacroExpansion
::No
,
243 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(
247 let mut items
= items
.into_iter();
249 AstFragmentKind
::Arms
=> {
250 AstFragment
::Arms(items
.map(Annotatable
::expect_arm
).collect())
252 AstFragmentKind
::ExprFields
=> {
253 AstFragment
::ExprFields(items
.map(Annotatable
::expect_expr_field
).collect())
255 AstFragmentKind
::PatFields
=> {
256 AstFragment
::PatFields(items
.map(Annotatable
::expect_pat_field
).collect())
258 AstFragmentKind
::GenericParams
=> {
259 AstFragment
::GenericParams(items
.map(Annotatable
::expect_generic_param
).collect())
261 AstFragmentKind
::Params
=> {
262 AstFragment
::Params(items
.map(Annotatable
::expect_param
).collect())
264 AstFragmentKind
::FieldDefs
=> {
265 AstFragment
::FieldDefs(items
.map(Annotatable
::expect_field_def
).collect())
267 AstFragmentKind
::Variants
=> {
268 AstFragment
::Variants(items
.map(Annotatable
::expect_variant
).collect())
270 AstFragmentKind
::Items
=> {
271 AstFragment
::Items(items
.map(Annotatable
::expect_item
).collect())
273 AstFragmentKind
::ImplItems
=> {
274 AstFragment
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect())
276 AstFragmentKind
::TraitItems
=> {
277 AstFragment
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect())
279 AstFragmentKind
::ForeignItems
=> {
280 AstFragment
::ForeignItems(items
.map(Annotatable
::expect_foreign_item
).collect())
282 AstFragmentKind
::Stmts
=> {
283 AstFragment
::Stmts(items
.map(Annotatable
::expect_stmt
).collect())
285 AstFragmentKind
::Expr
=> AstFragment
::Expr(
286 items
.next().expect("expected exactly one expression").expect_expr(),
288 AstFragmentKind
::OptExpr
=> {
289 AstFragment
::OptExpr(items
.next().map(Annotatable
::expect_expr
))
291 AstFragmentKind
::Crate
=> {
292 AstFragment
::Crate(items
.next().expect("expected exactly one crate").expect_crate())
294 AstFragmentKind
::Pat
| AstFragmentKind
::Ty
=> {
295 panic
!("patterns and types aren't annotatable")
301 pub struct Invocation
{
302 pub kind
: InvocationKind
,
303 pub fragment_kind
: AstFragmentKind
,
304 pub expansion_data
: ExpansionData
,
307 pub enum InvocationKind
{
313 attr
: ast
::Attribute
,
314 // Re-insertion position for inert attributes.
317 // Required for resolving derive helper attributes.
318 derives
: Vec
<ast
::Path
>,
326 impl InvocationKind
{
327 fn placeholder_visibility(&self) -> Option
<ast
::Visibility
> {
328 // HACK: For unnamed fields placeholders should have the same visibility as the actual
329 // fields because for tuple structs/variants resolve determines visibilities of their
330 // constructor using these field visibilities before attributes on them are are expanded.
331 // The assumption is that the attribute expansion cannot change field visibilities,
332 // and it holds because only inert attributes are supported in this position.
334 InvocationKind
::Attr { item: Annotatable::FieldDef(field), .. }
335 | InvocationKind
::Derive { item: Annotatable::FieldDef(field), .. }
336 if field
.ident
.is_none() =>
338 Some(field
.vis
.clone())
346 pub fn span(&self) -> Span
{
348 InvocationKind
::Bang { span, .. }
=> *span
,
349 InvocationKind
::Attr { attr, .. }
=> attr
.span
,
350 InvocationKind
::Derive { path, .. }
=> path
.span
,
355 pub struct MacroExpander
<'a
, 'b
> {
356 pub cx
: &'a
mut ExtCtxt
<'b
>,
357 monotonic
: bool
, // cf. `cx.monotonic_expander()`
360 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
361 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
362 MacroExpander { cx, monotonic }
365 pub fn expand_crate(&mut self, krate
: ast
::Crate
) -> ast
::Crate
{
366 let file_path
= match self.cx
.source_map().span_to_filename(krate
.spans
.inner_span
) {
367 FileName
::Real(name
) => name
369 .expect("attempting to resolve a file path in an external file"),
370 other
=> PathBuf
::from(other
.prefer_local().to_string()),
372 let dir_path
= file_path
.parent().unwrap_or(&file_path
).to_owned();
373 self.cx
.root_path
= dir_path
.clone();
374 self.cx
.current_expansion
.module
= Rc
::new(ModuleData
{
375 mod_path
: vec
![Ident
::from_str(&self.cx
.ecfg
.crate_name
)],
376 file_path_stack
: vec
![file_path
],
379 let krate
= self.fully_expand_fragment(AstFragment
::Crate(krate
)).make_crate();
380 assert_eq
!(krate
.id
, ast
::CRATE_NODE_ID
);
381 self.cx
.trace_macros_diag();
385 // Recursively expand all macro invocations in this AST fragment.
386 pub fn fully_expand_fragment(&mut self, input_fragment
: AstFragment
) -> AstFragment
{
387 let orig_expansion_data
= self.cx
.current_expansion
.clone();
388 let orig_force_mode
= self.cx
.force_mode
;
390 // Collect all macro invocations and replace them with placeholders.
391 let (mut fragment_with_placeholders
, mut invocations
) =
392 self.collect_invocations(input_fragment
, &[]);
394 // Optimization: if we resolve all imports now,
395 // we'll be able to immediately resolve most of imported macros.
396 self.resolve_imports();
398 // Resolve paths in all invocations and produce output expanded fragments for them, but
399 // do not insert them into our input AST fragment yet, only store in `expanded_fragments`.
400 // The output fragments also go through expansion recursively until no invocations are left.
401 // Unresolved macros produce dummy outputs as a recovery measure.
402 invocations
.reverse();
403 let mut expanded_fragments
= Vec
::new();
404 let mut undetermined_invocations
= Vec
::new();
405 let (mut progress
, mut force
) = (false, !self.monotonic
);
407 let Some((invoc
, ext
)) = invocations
.pop() else {
408 self.resolve_imports();
409 if undetermined_invocations
.is_empty() {
412 invocations
= mem
::take(&mut undetermined_invocations
);
413 force
= !mem
::replace(&mut progress
, false);
414 if force
&& self.monotonic
{
415 self.cx
.sess
.delay_span_bug(
416 invocations
.last().unwrap().0.span(),
417 "expansion entered force mode without producing any errors",
423 let ext
= match ext
{
426 let eager_expansion_root
= if self.monotonic
{
427 invoc
.expansion_data
.id
429 orig_expansion_data
.id
431 match self.cx
.resolver
.resolve_macro_invocation(
433 eager_expansion_root
,
437 Err(Indeterminate
) => {
438 // Cannot resolve, will retry this invocation later.
439 undetermined_invocations
.push((invoc
, None
));
446 let ExpansionData { depth, id: expn_id, .. }
= invoc
.expansion_data
;
447 let depth
= depth
- orig_expansion_data
.depth
;
448 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
449 self.cx
.force_mode
= force
;
451 let fragment_kind
= invoc
.fragment_kind
;
452 let (expanded_fragment
, new_invocations
) = match self.expand_invoc(invoc
, &ext
.kind
) {
453 ExpandResult
::Ready(fragment
) => {
454 let mut derive_invocations
= Vec
::new();
455 let derive_placeholders
= self
458 .take_derive_resolutions(expn_id
)
460 derive_invocations
.reserve(derives
.len());
463 .map(|(path
, item
, _exts
)| {
464 // FIXME: Consider using the derive resolutions (`_exts`)
465 // instead of enqueuing the derives to be resolved again later.
466 let expn_id
= LocalExpnId
::fresh_empty();
467 derive_invocations
.push((
469 kind
: InvocationKind
::Derive { path, item }
,
471 expansion_data
: ExpansionData
{
473 ..self.cx
.current_expansion
.clone()
478 NodeId
::placeholder_from_expn_id(expn_id
)
482 .unwrap_or_default();
484 let (fragment
, collected_invocations
) =
485 self.collect_invocations(fragment
, &derive_placeholders
);
486 // We choose to expand any derive invocations associated with this macro invocation
487 // *before* any macro invocations collected from the output fragment
488 derive_invocations
.extend(collected_invocations
);
489 (fragment
, derive_invocations
)
491 ExpandResult
::Retry(invoc
) => {
495 "expansion entered force mode but is still stuck",
498 // Cannot expand, will retry this invocation later.
499 undetermined_invocations
.push((invoc
, Some(ext
)));
506 if expanded_fragments
.len() < depth
{
507 expanded_fragments
.push(Vec
::new());
509 expanded_fragments
[depth
- 1].push((expn_id
, expanded_fragment
));
510 invocations
.extend(new_invocations
.into_iter().rev());
513 self.cx
.current_expansion
= orig_expansion_data
;
514 self.cx
.force_mode
= orig_force_mode
;
516 // Finally incorporate all the expanded macros into the input AST fragment.
517 let mut placeholder_expander
= PlaceholderExpander
::default();
518 while let Some(expanded_fragments
) = expanded_fragments
.pop() {
519 for (expn_id
, expanded_fragment
) in expanded_fragments
.into_iter().rev() {
521 .add(NodeId
::placeholder_from_expn_id(expn_id
), expanded_fragment
);
524 fragment_with_placeholders
.mut_visit_with(&mut placeholder_expander
);
525 fragment_with_placeholders
528 fn resolve_imports(&mut self) {
530 self.cx
.resolver
.resolve_imports();
534 /// Collects all macro invocations reachable at this time in this AST fragment, and replace
535 /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
536 /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
537 /// prepares data for resolving paths of macro invocations.
538 fn collect_invocations(
540 mut fragment
: AstFragment
,
541 extra_placeholders
: &[NodeId
],
542 ) -> (AstFragment
, Vec
<(Invocation
, Option
<Lrc
<SyntaxExtension
>>)>) {
543 // Resolve `$crate`s in the fragment for pretty-printing.
544 self.cx
.resolver
.resolve_dollar_crates();
546 let mut invocations
= {
547 let mut collector
= InvocationCollector
{
548 // Non-derive macro invocations cannot see the results of cfg expansion - they
549 // will either be removed along with the item, or invoked before the cfg/cfg_attr
550 // attribute is expanded. Therefore, we don't need to configure the tokens
551 // Derive macros *can* see the results of cfg-expansion - they are handled
552 // specially in `fully_expand_fragment`
554 invocations
: Vec
::new(),
555 monotonic
: self.monotonic
,
557 fragment
.mut_visit_with(&mut collector
);
558 fragment
.add_placeholders(extra_placeholders
);
559 collector
.invocations
565 .visit_ast_fragment_with_placeholders(self.cx
.current_expansion
.id
, &fragment
);
567 if self.cx
.sess
.opts
.debugging_opts
.incremental_relative_spans
{
568 for (invoc
, _
) in invocations
.iter_mut() {
569 let expn_id
= invoc
.expansion_data
.id
;
570 let parent_def
= self.cx
.resolver
.invocation_parent(expn_id
);
571 let span
= match &mut invoc
.kind
{
572 InvocationKind
::Bang { ref mut span, .. }
=> span
,
573 InvocationKind
::Attr { attr, .. }
=> &mut attr
.span
,
574 InvocationKind
::Derive { path, .. }
=> &mut path
.span
,
576 *span
= span
.with_parent(Some(parent_def
));
581 (fragment
, invocations
)
584 fn error_recursion_limit_reached(&mut self) {
585 let expn_data
= self.cx
.current_expansion
.id
.expn_data();
586 let suggested_limit
= match self.cx
.ecfg
.recursion_limit
{
587 Limit(0) => Limit(2),
593 &format
!("recursion limit reached while expanding `{}`", expn_data
.kind
.descr()),
596 "consider increasing the recursion limit by adding a \
597 `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
598 suggested_limit
, self.cx
.ecfg
.crate_name
,
601 self.cx
.trace_macros_diag();
604 /// A macro's expansion does not fit in this fragment kind.
605 /// For example, a non-type macro in a type position.
606 fn error_wrong_fragment_kind(&mut self, kind
: AstFragmentKind
, mac
: &ast
::MacCall
, span
: Span
) {
608 "non-{kind} macro in {kind} position: {path}",
610 path
= pprust
::path_to_string(&mac
.path
),
612 self.cx
.span_err(span
, &msg
);
613 self.cx
.trace_macros_diag();
619 ext
: &SyntaxExtensionKind
,
620 ) -> ExpandResult
<AstFragment
, Invocation
> {
621 let recursion_limit
=
622 self.cx
.reduced_recursion_limit
.unwrap_or(self.cx
.ecfg
.recursion_limit
);
623 if !recursion_limit
.value_within_limit(self.cx
.current_expansion
.depth
) {
624 if self.cx
.reduced_recursion_limit
.is_none() {
625 self.error_recursion_limit_reached();
628 // Reduce the recursion limit by half each time it triggers.
629 self.cx
.reduced_recursion_limit
= Some(recursion_limit
/ 2);
631 return ExpandResult
::Ready(invoc
.fragment_kind
.dummy(invoc
.span()));
634 let (fragment_kind
, span
) = (invoc
.fragment_kind
, invoc
.span());
635 ExpandResult
::Ready(match invoc
.kind
{
636 InvocationKind
::Bang { mac, .. }
=> match ext
{
637 SyntaxExtensionKind
::Bang(expander
) => {
638 let Ok(tok_result
) = expander
.expand(self.cx
, span
, mac
.args
.inner_tokens()) else {
639 return ExpandResult
::Ready(fragment_kind
.dummy(span
));
641 self.parse_ast_fragment(tok_result
, fragment_kind
, &mac
.path
, span
)
643 SyntaxExtensionKind
::LegacyBang(expander
) => {
644 let prev
= self.cx
.current_expansion
.prior_type_ascription
;
645 self.cx
.current_expansion
.prior_type_ascription
= mac
.prior_type_ascription
;
646 let tok_result
= expander
.expand(self.cx
, span
, mac
.args
.inner_tokens());
647 let result
= if let Some(result
) = fragment_kind
.make_from(tok_result
) {
650 self.error_wrong_fragment_kind(fragment_kind
, &mac
, span
);
651 fragment_kind
.dummy(span
)
653 self.cx
.current_expansion
.prior_type_ascription
= prev
;
658 InvocationKind
::Attr { attr, pos, mut item, derives }
=> match ext
{
659 SyntaxExtensionKind
::Attr(expander
) => {
660 self.gate_proc_macro_input(&item
);
661 self.gate_proc_macro_attr_item(span
, &item
);
662 let tokens
= match &item
{
663 // FIXME: Collect tokens and use them instead of generating
664 // fake ones. These are unstable, so it needs to be
665 // fixed prior to stabilization
666 // Fake tokens when we are invoking an inner attribute, and
667 // we are invoking it on an out-of-line module or crate.
668 Annotatable
::Crate(krate
) => rustc_parse
::fake_token_stream_for_crate(
669 &self.cx
.sess
.parse_sess
,
672 Annotatable
::Item(item_inner
)
673 if matches
!(attr
.style
, AttrStyle
::Inner
)
678 ModKind
::Unloaded
| ModKind
::Loaded(_
, Inline
::No
, _
),
682 rustc_parse
::fake_token_stream_for_item(
683 &self.cx
.sess
.parse_sess
,
687 _
=> item
.to_tokens(),
689 let attr_item
= attr
.unwrap_normal_item();
690 if let MacArgs
::Eq(..) = attr_item
.args
{
691 self.cx
.span_err(span
, "key-value macro attributes are not supported");
693 let inner_tokens
= attr_item
.args
.inner_tokens();
694 let Ok(tok_result
) = expander
.expand(self.cx
, span
, inner_tokens
, tokens
) else {
695 return ExpandResult
::Ready(fragment_kind
.dummy(span
));
697 self.parse_ast_fragment(tok_result
, fragment_kind
, &attr_item
.path
, span
)
699 SyntaxExtensionKind
::LegacyAttr(expander
) => {
700 match validate_attr
::parse_meta(&self.cx
.sess
.parse_sess
, &attr
) {
702 let items
= match expander
.expand(self.cx
, span
, &meta
, item
) {
703 ExpandResult
::Ready(items
) => items
,
704 ExpandResult
::Retry(item
) => {
705 // Reassemble the original invocation for retrying.
706 return ExpandResult
::Retry(Invocation
{
707 kind
: InvocationKind
::Attr { attr, pos, item, derives }
,
712 if fragment_kind
== AstFragmentKind
::Expr
&& items
.is_empty() {
714 "removing an expression is not supported in this position";
715 self.cx
.span_err(span
, msg
);
716 fragment_kind
.dummy(span
)
718 fragment_kind
.expect_from_annotatables(items
)
723 fragment_kind
.dummy(span
)
727 SyntaxExtensionKind
::NonMacroAttr
=> {
728 self.cx
.expanded_inert_attrs
.mark(&attr
);
729 item
.visit_attrs(|attrs
| attrs
.insert(pos
, attr
));
730 fragment_kind
.expect_from_annotatables(iter
::once(item
))
734 InvocationKind
::Derive { path, item }
=> match ext
{
735 SyntaxExtensionKind
::Derive(expander
)
736 | SyntaxExtensionKind
::LegacyDerive(expander
) => {
737 if let SyntaxExtensionKind
::Derive(..) = ext
{
738 self.gate_proc_macro_input(&item
);
740 let meta
= ast
::MetaItem { kind: MetaItemKind::Word, span, path }
;
741 let items
= match expander
.expand(self.cx
, span
, &meta
, item
) {
742 ExpandResult
::Ready(items
) => items
,
743 ExpandResult
::Retry(item
) => {
744 // Reassemble the original invocation for retrying.
745 return ExpandResult
::Retry(Invocation
{
746 kind
: InvocationKind
::Derive { path: meta.path, item }
,
751 fragment_kind
.expect_from_annotatables(items
)
758 fn gate_proc_macro_attr_item(&self, span
: Span
, item
: &Annotatable
) {
759 let kind
= match item
{
761 | Annotatable
::TraitItem(_
)
762 | Annotatable
::ImplItem(_
)
763 | Annotatable
::ForeignItem(_
)
764 | Annotatable
::Crate(..) => return,
765 Annotatable
::Stmt(stmt
) => {
766 // Attributes are stable on item statements,
767 // but unstable on all other kinds of statements
773 Annotatable
::Expr(_
) => "expressions",
775 | Annotatable
::ExprField(..)
776 | Annotatable
::PatField(..)
777 | Annotatable
::GenericParam(..)
778 | Annotatable
::Param(..)
779 | Annotatable
::FieldDef(..)
780 | Annotatable
::Variant(..) => panic
!("unexpected annotatable"),
782 if self.cx
.ecfg
.proc_macro_hygiene() {
786 &self.cx
.sess
.parse_sess
,
787 sym
::proc_macro_hygiene
,
789 &format
!("custom attributes cannot be applied to {}", kind
),
794 fn gate_proc_macro_input(&self, annotatable
: &Annotatable
) {
795 struct GateProcMacroInput
<'a
> {
796 parse_sess
: &'a ParseSess
,
799 impl<'ast
, 'a
> Visitor
<'ast
> for GateProcMacroInput
<'a
> {
800 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
802 ItemKind
::Mod(_
, mod_kind
)
803 if !matches
!(mod_kind
, ModKind
::Loaded(_
, Inline
::Yes
, _
)) =>
807 sym
::proc_macro_hygiene
,
809 "non-inline modules in proc macro input are unstable",
816 visit
::walk_item(self, item
);
820 if !self.cx
.ecfg
.proc_macro_hygiene() {
822 .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess }
);
826 fn parse_ast_fragment(
829 kind
: AstFragmentKind
,
833 let mut parser
= self.cx
.new_parser_from_tts(toks
);
834 match parse_ast_fragment(&mut parser
, kind
) {
836 ensure_complete_parse(&mut parser
, path
, kind
.name(), span
);
840 if err
.span
.is_dummy() {
843 annotate_err_with_kind(&mut err
, kind
, span
);
845 self.cx
.trace_macros_diag();
852 pub fn parse_ast_fragment
<'a
>(
853 this
: &mut Parser
<'a
>,
854 kind
: AstFragmentKind
,
855 ) -> PResult
<'a
, AstFragment
> {
857 AstFragmentKind
::Items
=> {
858 let mut items
= SmallVec
::new();
859 while let Some(item
) = this
.parse_item(ForceCollect
::No
)?
{
862 AstFragment
::Items(items
)
864 AstFragmentKind
::TraitItems
=> {
865 let mut items
= SmallVec
::new();
866 while let Some(item
) = this
.parse_trait_item(ForceCollect
::No
)?
{
869 AstFragment
::TraitItems(items
)
871 AstFragmentKind
::ImplItems
=> {
872 let mut items
= SmallVec
::new();
873 while let Some(item
) = this
.parse_impl_item(ForceCollect
::No
)?
{
876 AstFragment
::ImplItems(items
)
878 AstFragmentKind
::ForeignItems
=> {
879 let mut items
= SmallVec
::new();
880 while let Some(item
) = this
.parse_foreign_item(ForceCollect
::No
)?
{
883 AstFragment
::ForeignItems(items
)
885 AstFragmentKind
::Stmts
=> {
886 let mut stmts
= SmallVec
::new();
887 // Won't make progress on a `}`.
888 while this
.token
!= token
::Eof
&& this
.token
!= token
::CloseDelim(Delimiter
::Brace
) {
889 if let Some(stmt
) = this
.parse_full_stmt(AttemptLocalParseRecovery
::Yes
)?
{
893 AstFragment
::Stmts(stmts
)
895 AstFragmentKind
::Expr
=> AstFragment
::Expr(this
.parse_expr()?
),
896 AstFragmentKind
::OptExpr
=> {
897 if this
.token
!= token
::Eof
{
898 AstFragment
::OptExpr(Some(this
.parse_expr()?
))
900 AstFragment
::OptExpr(None
)
903 AstFragmentKind
::Ty
=> AstFragment
::Ty(this
.parse_ty()?
),
904 AstFragmentKind
::Pat
=> AstFragment
::Pat(this
.parse_pat_allow_top_alt(
908 CommaRecoveryMode
::LikelyTuple
,
910 AstFragmentKind
::Crate
=> AstFragment
::Crate(this
.parse_crate_mod()?
),
911 AstFragmentKind
::Arms
912 | AstFragmentKind
::ExprFields
913 | AstFragmentKind
::PatFields
914 | AstFragmentKind
::GenericParams
915 | AstFragmentKind
::Params
916 | AstFragmentKind
::FieldDefs
917 | AstFragmentKind
::Variants
=> panic
!("unexpected AST fragment kind"),
921 pub fn ensure_complete_parse
<'a
>(
922 this
: &mut Parser
<'a
>,
923 macro_path
: &ast
::Path
,
927 if this
.token
!= token
::Eof
{
928 let token
= pprust
::token_to_string(&this
.token
);
929 let msg
= format
!("macro expansion ignores token `{}` and any following", token
);
930 // Avoid emitting backtrace info twice.
931 let def_site_span
= this
.token
.span
.with_ctxt(SyntaxContext
::root());
932 let mut err
= this
.struct_span_err(def_site_span
, &msg
);
933 err
.span_label(span
, "caused by the macro expansion here");
935 "the usage of `{}!` is likely invalid in {} context",
936 pprust
::path_to_string(macro_path
),
940 let semi_span
= this
.sess
.source_map().next_point(span
);
942 let semi_full_span
= semi_span
.to(this
.sess
.source_map().next_point(semi_span
));
943 match this
.sess
.source_map().span_to_snippet(semi_full_span
) {
944 Ok(ref snippet
) if &snippet
[..] != ";" && kind_name
== "expression" => {
947 "you might be missing a semicolon here",
949 Applicability
::MaybeIncorrect
,
958 /// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
959 /// for an AST node that supports attributes
960 /// (see the `Annotatable` enum)
961 /// This method assigns a `NodeId`, and sets that `NodeId`
962 /// as our current 'lint node id'. If a macro call is found
963 /// inside this AST node, we will use this AST node's `NodeId`
964 /// to emit lints associated with that macro (allowing
965 /// `#[allow]` / `#[deny]` to be applied close to
966 /// the macro invocation).
968 /// Do *not* call this for a macro AST node
969 /// (e.g. `ExprKind::MacCall`) - we cannot emit lints
970 /// at these AST nodes, since they are removed and
971 /// replaced with the result of macro expansion.
973 /// All other `NodeId`s are assigned by `visit_id`.
974 /// * `self` is the 'self' parameter for the current method,
975 /// * `id` is a mutable reference to the `NodeId` field
976 /// of the current AST node.
977 /// * `closure` is a closure that executes the
978 /// `noop_visit_*` / `noop_flat_map_*` method
979 /// for the current AST node.
980 macro_rules
! assign_id
{
981 ($
self:ident
, $id
:expr
, $closure
:expr
) => {{
982 let old_id
= $
self.cx
.current_expansion
.lint_node_id
;
984 debug_assert_eq
!(*$id
, ast
::DUMMY_NODE_ID
);
985 let new_id
= $
self.cx
.resolver
.next_node_id();
987 $
self.cx
.current_expansion
.lint_node_id
= new_id
;
989 let ret
= ($closure
)();
990 $
self.cx
.current_expansion
.lint_node_id
= old_id
;
1000 /// A trait implemented for all `AstFragment` nodes and providing all pieces
1001 /// of functionality used by `InvocationCollector`.
1002 trait InvocationCollectorNode
: HasAttrs
+ HasNodeId
+ Sized
{
1003 type OutputTy
= SmallVec
<[Self; 1]>;
1004 type AttrsTy
: Deref
<Target
= [ast
::Attribute
]> = Vec
<ast
::Attribute
>;
1005 const KIND
: AstFragmentKind
;
1006 fn to_annotatable(self) -> Annotatable
;
1007 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
;
1008 fn descr() -> &'
static str {
1011 fn noop_flat_map
<V
: MutVisitor
>(self, _visitor
: &mut V
) -> Self::OutputTy
{
1014 fn noop_visit
<V
: MutVisitor
>(&mut self, _visitor
: &mut V
) {
1017 fn is_mac_call(&self) -> bool
{
1020 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1023 fn pre_flat_map_node_collect_attr(_cfg
: &StripUnconfigured
<'_
>, _attr
: &ast
::Attribute
) {}
1024 fn post_flat_map_node_collect_bang(_output
: &mut Self::OutputTy
, _add_semicolon
: AddSemicolon
) {
1026 fn wrap_flat_map_node_noop_flat_map(
1028 collector
: &mut InvocationCollector
<'_
, '_
>,
1029 noop_flat_map
: impl FnOnce(Self, &mut InvocationCollector
<'_
, '_
>) -> Self::OutputTy
,
1030 ) -> Result
<Self::OutputTy
, Self> {
1031 Ok(noop_flat_map(node
, collector
))
1035 impl InvocationCollectorNode
for P
<ast
::Item
> {
1036 const KIND
: AstFragmentKind
= AstFragmentKind
::Items
;
1037 fn to_annotatable(self) -> Annotatable
{
1038 Annotatable
::Item(self)
1040 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1041 fragment
.make_items()
1043 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1044 noop_flat_map_item(self, visitor
)
1046 fn is_mac_call(&self) -> bool
{
1047 matches
!(self.kind
, ItemKind
::MacCall(..))
1049 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1050 let node
= self.into_inner();
1052 ItemKind
::MacCall(mac
) => (mac
, node
.attrs
, AddSemicolon
::No
),
1053 _
=> unreachable
!(),
1056 fn wrap_flat_map_node_noop_flat_map(
1058 collector
: &mut InvocationCollector
<'_
, '_
>,
1059 noop_flat_map
: impl FnOnce(Self, &mut InvocationCollector
<'_
, '_
>) -> Self::OutputTy
,
1060 ) -> Result
<Self::OutputTy
, Self> {
1061 if !matches
!(node
.kind
, ItemKind
::Mod(..)) {
1062 return Ok(noop_flat_map(node
, collector
));
1065 // Work around borrow checker not seeing through `P`'s deref.
1066 let (ident
, span
, mut attrs
) = (node
.ident
, node
.span
, mem
::take(&mut node
.attrs
));
1067 let ItemKind
::Mod(_
, mod_kind
) = &mut node
.kind
else {
1071 let ecx
= &mut collector
.cx
;
1072 let (file_path
, dir_path
, dir_ownership
) = match mod_kind
{
1073 ModKind
::Loaded(_
, inline
, _
) => {
1074 // Inline `mod foo { ... }`, but we still need to push directories.
1075 let (dir_path
, dir_ownership
) = mod_dir_path(
1079 &ecx
.current_expansion
.module
,
1080 ecx
.current_expansion
.dir_ownership
,
1084 (None
, dir_path
, dir_ownership
)
1086 ModKind
::Unloaded
=> {
1087 // We have an outline `mod foo;` so we need to parse the file.
1088 let old_attrs_len
= attrs
.len();
1089 let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
=
1094 &ecx
.current_expansion
.module
,
1095 ecx
.current_expansion
.dir_ownership
,
1099 if let Some(lint_store
) = ecx
.lint_store
{
1100 lint_store
.pre_expansion_lint(
1102 ecx
.resolver
.registered_tools(),
1103 ecx
.current_expansion
.lint_node_id
,
1106 ident
.name
.as_str(),
1110 *mod_kind
= ModKind
::Loaded(items
, Inline
::No
, spans
);
1112 if node
.attrs
.len() > old_attrs_len
{
1113 // If we loaded an out-of-line module and added some inner attributes,
1114 // then we need to re-configure it and re-collect attributes for
1115 // resolution and expansion.
1118 (Some(file_path
), dir_path
, dir_ownership
)
1122 // Set the module info before we flat map.
1123 let mut module
= ecx
.current_expansion
.module
.with_dir_path(dir_path
);
1124 module
.mod_path
.push(ident
);
1125 if let Some(file_path
) = file_path
{
1126 module
.file_path_stack
.push(file_path
);
1129 let orig_module
= mem
::replace(&mut ecx
.current_expansion
.module
, Rc
::new(module
));
1130 let orig_dir_ownership
=
1131 mem
::replace(&mut ecx
.current_expansion
.dir_ownership
, dir_ownership
);
1133 let res
= Ok(noop_flat_map(node
, collector
));
1135 collector
.cx
.current_expansion
.dir_ownership
= orig_dir_ownership
;
1136 collector
.cx
.current_expansion
.module
= orig_module
;
1141 struct TraitItemTag
;
1142 impl InvocationCollectorNode
for AstNodeWrapper
<P
<ast
::AssocItem
>, TraitItemTag
> {
1143 type OutputTy
= SmallVec
<[P
<ast
::AssocItem
>; 1]>;
1144 const KIND
: AstFragmentKind
= AstFragmentKind
::TraitItems
;
1145 fn to_annotatable(self) -> Annotatable
{
1146 Annotatable
::TraitItem(self.wrapped
)
1148 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1149 fragment
.make_trait_items()
1151 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1152 noop_flat_map_assoc_item(self.wrapped
, visitor
)
1154 fn is_mac_call(&self) -> bool
{
1155 matches
!(self.wrapped
.kind
, AssocItemKind
::MacCall(..))
1157 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1158 let item
= self.wrapped
.into_inner();
1160 AssocItemKind
::MacCall(mac
) => (mac
, item
.attrs
, AddSemicolon
::No
),
1161 _
=> unreachable
!(),
1167 impl InvocationCollectorNode
for AstNodeWrapper
<P
<ast
::AssocItem
>, ImplItemTag
> {
1168 type OutputTy
= SmallVec
<[P
<ast
::AssocItem
>; 1]>;
1169 const KIND
: AstFragmentKind
= AstFragmentKind
::ImplItems
;
1170 fn to_annotatable(self) -> Annotatable
{
1171 Annotatable
::ImplItem(self.wrapped
)
1173 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1174 fragment
.make_impl_items()
1176 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1177 noop_flat_map_assoc_item(self.wrapped
, visitor
)
1179 fn is_mac_call(&self) -> bool
{
1180 matches
!(self.wrapped
.kind
, AssocItemKind
::MacCall(..))
1182 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1183 let item
= self.wrapped
.into_inner();
1185 AssocItemKind
::MacCall(mac
) => (mac
, item
.attrs
, AddSemicolon
::No
),
1186 _
=> unreachable
!(),
1191 impl InvocationCollectorNode
for P
<ast
::ForeignItem
> {
1192 const KIND
: AstFragmentKind
= AstFragmentKind
::ForeignItems
;
1193 fn to_annotatable(self) -> Annotatable
{
1194 Annotatable
::ForeignItem(self)
1196 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1197 fragment
.make_foreign_items()
1199 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1200 noop_flat_map_foreign_item(self, visitor
)
1202 fn is_mac_call(&self) -> bool
{
1203 matches
!(self.kind
, ForeignItemKind
::MacCall(..))
1205 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1206 let node
= self.into_inner();
1208 ForeignItemKind
::MacCall(mac
) => (mac
, node
.attrs
, AddSemicolon
::No
),
1209 _
=> unreachable
!(),
1214 impl InvocationCollectorNode
for ast
::Variant
{
1215 const KIND
: AstFragmentKind
= AstFragmentKind
::Variants
;
1216 fn to_annotatable(self) -> Annotatable
{
1217 Annotatable
::Variant(self)
1219 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1220 fragment
.make_variants()
1222 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1223 noop_flat_map_variant(self, visitor
)
1227 impl InvocationCollectorNode
for ast
::FieldDef
{
1228 const KIND
: AstFragmentKind
= AstFragmentKind
::FieldDefs
;
1229 fn to_annotatable(self) -> Annotatable
{
1230 Annotatable
::FieldDef(self)
1232 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1233 fragment
.make_field_defs()
1235 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1236 noop_flat_map_field_def(self, visitor
)
1240 impl InvocationCollectorNode
for ast
::PatField
{
1241 const KIND
: AstFragmentKind
= AstFragmentKind
::PatFields
;
1242 fn to_annotatable(self) -> Annotatable
{
1243 Annotatable
::PatField(self)
1245 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1246 fragment
.make_pat_fields()
1248 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1249 noop_flat_map_pat_field(self, visitor
)
1253 impl InvocationCollectorNode
for ast
::ExprField
{
1254 const KIND
: AstFragmentKind
= AstFragmentKind
::ExprFields
;
1255 fn to_annotatable(self) -> Annotatable
{
1256 Annotatable
::ExprField(self)
1258 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1259 fragment
.make_expr_fields()
1261 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1262 noop_flat_map_expr_field(self, visitor
)
1266 impl InvocationCollectorNode
for ast
::Param
{
1267 const KIND
: AstFragmentKind
= AstFragmentKind
::Params
;
1268 fn to_annotatable(self) -> Annotatable
{
1269 Annotatable
::Param(self)
1271 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1272 fragment
.make_params()
1274 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1275 noop_flat_map_param(self, visitor
)
1279 impl InvocationCollectorNode
for ast
::GenericParam
{
1280 const KIND
: AstFragmentKind
= AstFragmentKind
::GenericParams
;
1281 fn to_annotatable(self) -> Annotatable
{
1282 Annotatable
::GenericParam(self)
1284 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1285 fragment
.make_generic_params()
1287 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1288 noop_flat_map_generic_param(self, visitor
)
1292 impl InvocationCollectorNode
for ast
::Arm
{
1293 const KIND
: AstFragmentKind
= AstFragmentKind
::Arms
;
1294 fn to_annotatable(self) -> Annotatable
{
1295 Annotatable
::Arm(self)
1297 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1298 fragment
.make_arms()
1300 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1301 noop_flat_map_arm(self, visitor
)
1305 impl InvocationCollectorNode
for ast
::Stmt
{
1306 type AttrsTy
= ast
::AttrVec
;
1307 const KIND
: AstFragmentKind
= AstFragmentKind
::Stmts
;
1308 fn to_annotatable(self) -> Annotatable
{
1309 Annotatable
::Stmt(P(self))
1311 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1312 fragment
.make_stmts()
1314 fn noop_flat_map
<V
: MutVisitor
>(self, visitor
: &mut V
) -> Self::OutputTy
{
1315 noop_flat_map_stmt(self, visitor
)
1317 fn is_mac_call(&self) -> bool
{
1319 StmtKind
::MacCall(..) => true,
1320 StmtKind
::Item(item
) => matches
!(item
.kind
, ItemKind
::MacCall(..)),
1321 StmtKind
::Semi(expr
) => matches
!(expr
.kind
, ExprKind
::MacCall(..)),
1322 StmtKind
::Expr(..) => unreachable
!(),
1323 StmtKind
::Local(..) | StmtKind
::Empty
=> false,
1326 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1327 // We pull macro invocations (both attributes and fn-like macro calls) out of their
1328 // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
1329 let (add_semicolon
, mac
, attrs
) = match self.kind
{
1330 StmtKind
::MacCall(mac
) => {
1331 let ast
::MacCallStmt { mac, style, attrs, .. }
= mac
.into_inner();
1332 (style
== MacStmtStyle
::Semicolon
, mac
, attrs
)
1334 StmtKind
::Item(item
) => match item
.into_inner() {
1335 ast
::Item { kind: ItemKind::MacCall(mac), attrs, .. }
=> {
1336 (mac
.args
.need_semicolon(), mac
, attrs
.into())
1338 _
=> unreachable
!(),
1340 StmtKind
::Semi(expr
) => match expr
.into_inner() {
1341 ast
::Expr { kind: ExprKind::MacCall(mac), attrs, .. }
=> {
1342 (mac
.args
.need_semicolon(), mac
, attrs
)
1344 _
=> unreachable
!(),
1346 _
=> unreachable
!(),
1348 (mac
, attrs
, if add_semicolon { AddSemicolon::Yes }
else { AddSemicolon::No }
)
1350 fn post_flat_map_node_collect_bang(stmts
: &mut Self::OutputTy
, add_semicolon
: AddSemicolon
) {
1351 // If this is a macro invocation with a semicolon, then apply that
1352 // semicolon to the final statement produced by expansion.
1353 if matches
!(add_semicolon
, AddSemicolon
::Yes
) {
1354 if let Some(stmt
) = stmts
.pop() {
1355 stmts
.push(stmt
.add_trailing_semicolon());
1361 impl InvocationCollectorNode
for ast
::Crate
{
1362 type OutputTy
= ast
::Crate
;
1363 const KIND
: AstFragmentKind
= AstFragmentKind
::Crate
;
1364 fn to_annotatable(self) -> Annotatable
{
1365 Annotatable
::Crate(self)
1367 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1368 fragment
.make_crate()
1370 fn noop_visit
<V
: MutVisitor
>(&mut self, visitor
: &mut V
) {
1371 noop_visit_crate(self, visitor
)
1375 impl InvocationCollectorNode
for P
<ast
::Ty
> {
1376 type OutputTy
= P
<ast
::Ty
>;
1377 const KIND
: AstFragmentKind
= AstFragmentKind
::Ty
;
1378 fn to_annotatable(self) -> Annotatable
{
1381 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1384 fn noop_visit
<V
: MutVisitor
>(&mut self, visitor
: &mut V
) {
1385 noop_visit_ty(self, visitor
)
1387 fn is_mac_call(&self) -> bool
{
1388 matches
!(self.kind
, ast
::TyKind
::MacCall(..))
1390 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1391 let node
= self.into_inner();
1393 TyKind
::MacCall(mac
) => (mac
, Vec
::new(), AddSemicolon
::No
),
1394 _
=> unreachable
!(),
1399 impl InvocationCollectorNode
for P
<ast
::Pat
> {
1400 type OutputTy
= P
<ast
::Pat
>;
1401 const KIND
: AstFragmentKind
= AstFragmentKind
::Pat
;
1402 fn to_annotatable(self) -> Annotatable
{
1405 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1408 fn noop_visit
<V
: MutVisitor
>(&mut self, visitor
: &mut V
) {
1409 noop_visit_pat(self, visitor
)
1411 fn is_mac_call(&self) -> bool
{
1412 matches
!(self.kind
, PatKind
::MacCall(..))
1414 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1415 let node
= self.into_inner();
1417 PatKind
::MacCall(mac
) => (mac
, Vec
::new(), AddSemicolon
::No
),
1418 _
=> unreachable
!(),
1423 impl InvocationCollectorNode
for P
<ast
::Expr
> {
1424 type OutputTy
= P
<ast
::Expr
>;
1425 type AttrsTy
= ast
::AttrVec
;
1426 const KIND
: AstFragmentKind
= AstFragmentKind
::Expr
;
1427 fn to_annotatable(self) -> Annotatable
{
1428 Annotatable
::Expr(self)
1430 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1431 fragment
.make_expr()
1433 fn descr() -> &'
static str {
1436 fn noop_visit
<V
: MutVisitor
>(&mut self, visitor
: &mut V
) {
1437 noop_visit_expr(self, visitor
)
1439 fn is_mac_call(&self) -> bool
{
1440 matches
!(self.kind
, ExprKind
::MacCall(..))
1442 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1443 let node
= self.into_inner();
1445 ExprKind
::MacCall(mac
) => (mac
, node
.attrs
, AddSemicolon
::No
),
1446 _
=> unreachable
!(),
1452 impl InvocationCollectorNode
for AstNodeWrapper
<P
<ast
::Expr
>, OptExprTag
> {
1453 type OutputTy
= Option
<P
<ast
::Expr
>>;
1454 type AttrsTy
= ast
::AttrVec
;
1455 const KIND
: AstFragmentKind
= AstFragmentKind
::OptExpr
;
1456 fn to_annotatable(self) -> Annotatable
{
1457 Annotatable
::Expr(self.wrapped
)
1459 fn fragment_to_output(fragment
: AstFragment
) -> Self::OutputTy
{
1460 fragment
.make_opt_expr()
1462 fn noop_flat_map
<V
: MutVisitor
>(mut self, visitor
: &mut V
) -> Self::OutputTy
{
1463 noop_visit_expr(&mut self.wrapped
, visitor
);
1466 fn is_mac_call(&self) -> bool
{
1467 matches
!(self.wrapped
.kind
, ast
::ExprKind
::MacCall(..))
1469 fn take_mac_call(self) -> (ast
::MacCall
, Self::AttrsTy
, AddSemicolon
) {
1470 let node
= self.wrapped
.into_inner();
1472 ExprKind
::MacCall(mac
) => (mac
, node
.attrs
, AddSemicolon
::No
),
1473 _
=> unreachable
!(),
1476 fn pre_flat_map_node_collect_attr(cfg
: &StripUnconfigured
<'_
>, attr
: &ast
::Attribute
) {
1477 cfg
.maybe_emit_expr_attr_err(&attr
);
1481 struct InvocationCollector
<'a
, 'b
> {
1482 cx
: &'a
mut ExtCtxt
<'b
>,
1483 invocations
: Vec
<(Invocation
, Option
<Lrc
<SyntaxExtension
>>)>,
1487 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
1488 fn cfg(&self) -> StripUnconfigured
<'_
> {
1490 sess
: &self.cx
.sess
,
1491 features
: self.cx
.ecfg
.features
,
1492 config_tokens
: false,
1493 lint_node_id
: self.cx
.current_expansion
.lint_node_id
,
1497 fn collect(&mut self, fragment_kind
: AstFragmentKind
, kind
: InvocationKind
) -> AstFragment
{
1498 let expn_id
= LocalExpnId
::fresh_empty();
1499 let vis
= kind
.placeholder_visibility();
1500 self.invocations
.push((
1504 expansion_data
: ExpansionData
{
1506 depth
: self.cx
.current_expansion
.depth
+ 1,
1507 ..self.cx
.current_expansion
.clone()
1512 placeholder(fragment_kind
, NodeId
::placeholder_from_expn_id(expn_id
), vis
)
1515 fn collect_bang(&mut self, mac
: ast
::MacCall
, kind
: AstFragmentKind
) -> AstFragment
{
1516 // cache the macro call span so that it can be
1517 // easily adjusted for incremental compilation
1518 let span
= mac
.span();
1519 self.collect(kind
, InvocationKind
::Bang { mac, span }
)
1524 (attr
, pos
, derives
): (ast
::Attribute
, usize, Vec
<ast
::Path
>),
1526 kind
: AstFragmentKind
,
1528 self.collect(kind
, InvocationKind
::Attr { attr, pos, item, derives }
)
1531 /// If `item` is an attribute invocation, remove the attribute and return it together with
1532 /// its position and derives following it. We have to collect the derives in order to resolve
1533 /// legacy derive helpers (helpers written before derives that introduce them).
1536 item
: &mut impl HasAttrs
,
1537 ) -> Option
<(ast
::Attribute
, usize, Vec
<ast
::Path
>)> {
1538 let mut attr
= None
;
1540 let mut cfg_pos
= None
;
1541 let mut attr_pos
= None
;
1542 for (pos
, attr
) in item
.attrs().iter().enumerate() {
1543 if !attr
.is_doc_comment() && !self.cx
.expanded_inert_attrs
.is_marked(attr
) {
1544 let name
= attr
.ident().map(|ident
| ident
.name
);
1545 if name
== Some(sym
::cfg
) || name
== Some(sym
::cfg_attr
) {
1546 cfg_pos
= Some(pos
); // a cfg attr found, no need to search anymore
1548 } else if attr_pos
.is_none()
1549 && !name
.map_or(false, rustc_feature
::is_builtin_attr_name
)
1551 attr_pos
= Some(pos
); // a non-cfg attr found, still may find a cfg attr
1556 item
.visit_attrs(|attrs
| {
1557 attr
= Some(match (cfg_pos
, attr_pos
) {
1558 (Some(pos
), _
) => (attrs
.remove(pos
), pos
, Vec
::new()),
1560 let attr
= attrs
.remove(pos
);
1561 let following_derives
= attrs
[pos
..]
1563 .filter(|a
| a
.has_name(sym
::derive
))
1564 .flat_map(|a
| a
.meta_item_list().unwrap_or_default())
1565 .filter_map(|nested_meta
| match nested_meta
{
1566 NestedMetaItem
::MetaItem(ast
::MetaItem
{
1567 kind
: MetaItemKind
::Word
,
1575 (attr
, pos
, following_derives
)
1584 // Detect use of feature-gated or invalid attributes on macro invocations
1585 // since they will not be detected after macro expansion.
1586 fn check_attributes(&self, attrs
: &[ast
::Attribute
], call
: &ast
::MacCall
) {
1587 let features
= self.cx
.ecfg
.features
.unwrap();
1588 let mut attrs
= attrs
.iter().peekable();
1589 let mut span
: Option
<Span
> = None
;
1590 while let Some(attr
) = attrs
.next() {
1591 rustc_ast_passes
::feature_gate
::check_attribute(attr
, self.cx
.sess
, features
);
1592 validate_attr
::check_meta(&self.cx
.sess
.parse_sess
, attr
);
1594 let current_span
= if let Some(sp
) = span { sp.to(attr.span) }
else { attr.span }
;
1595 span
= Some(current_span
);
1597 if attrs
.peek().map_or(false, |next_attr
| next_attr
.doc_str().is_some()) {
1601 if attr
.is_doc_comment() {
1602 self.cx
.sess
.parse_sess
.buffer_lint_with_diagnostic(
1603 &UNUSED_DOC_COMMENTS
,
1605 self.cx
.current_expansion
.lint_node_id
,
1606 "unused doc comment",
1607 BuiltinLintDiagnostics
::UnusedDocComment(attr
.span
),
1609 } else if rustc_attr
::is_builtin_attr(attr
) {
1610 let attr_name
= attr
.ident().unwrap().name
;
1611 // `#[cfg]` and `#[cfg_attr]` are special - they are
1612 // eagerly evaluated.
1613 if attr_name
!= sym
::cfg
&& attr_name
!= sym
::cfg_attr
{
1614 self.cx
.sess
.parse_sess
.buffer_lint_with_diagnostic(
1617 self.cx
.current_expansion
.lint_node_id
,
1618 &format
!("unused attribute `{}`", attr_name
),
1619 BuiltinLintDiagnostics
::UnusedBuiltinAttribute
{
1621 macro_name
: pprust
::path_to_string(&call
.path
),
1622 invoc_span
: call
.path
.span
,
1632 node
: &mut impl HasAttrs
,
1633 attr
: ast
::Attribute
,
1636 let res
= self.cfg().cfg_true(&attr
);
1638 // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
1639 // and some tools like rustdoc and clippy rely on that. Find a way to remove them
1640 // while keeping the tools working.
1641 self.cx
.expanded_inert_attrs
.mark(&attr
);
1642 node
.visit_attrs(|attrs
| attrs
.insert(pos
, attr
));
1647 fn expand_cfg_attr(&self, node
: &mut impl HasAttrs
, attr
: ast
::Attribute
, pos
: usize) {
1648 node
.visit_attrs(|attrs
| {
1649 attrs
.splice(pos
..pos
, self.cfg().expand_cfg_attr(attr
, false));
1653 fn flat_map_node
<Node
: InvocationCollectorNode
<OutputTy
: Default
>>(
1656 ) -> Node
::OutputTy
{
1658 return match self.take_first_attr(&mut node
) {
1659 Some((attr
, pos
, derives
)) => match attr
.name_or_empty() {
1661 if self.expand_cfg_true(&mut node
, attr
, pos
) {
1667 self.expand_cfg_attr(&mut node
, attr
, pos
);
1671 Node
::pre_flat_map_node_collect_attr(&self.cfg(), &attr
);
1672 self.collect_attr((attr
, pos
, derives
), node
.to_annotatable(), Node
::KIND
)
1676 None
if node
.is_mac_call() => {
1677 let (mac
, attrs
, add_semicolon
) = node
.take_mac_call();
1678 self.check_attributes(&attrs
, &mac
);
1679 let mut res
= self.collect_bang(mac
, Node
::KIND
).make_ast
::<Node
>();
1680 Node
::post_flat_map_node_collect_bang(&mut res
, add_semicolon
);
1684 match Node
::wrap_flat_map_node_noop_flat_map(node
, self, |mut node
, this
| {
1685 assign_id
!(this
, node
.node_id_mut(), || node
.noop_flat_map(this
))
1687 Ok(output
) => output
,
1688 Err(returned_node
) => {
1689 node
= returned_node
;
1698 fn visit_node
<Node
: InvocationCollectorNode
<OutputTy
= Node
> + DummyAstNode
>(
1703 return match self.take_first_attr(node
) {
1704 Some((attr
, pos
, derives
)) => match attr
.name_or_empty() {
1706 let span
= attr
.span
;
1707 if self.expand_cfg_true(node
, attr
, pos
) {
1711 format
!("removing {} is not supported in this position", Node
::descr());
1712 self.cx
.span_err(span
, &msg
);
1716 self.expand_cfg_attr(node
, attr
, pos
);
1719 _
=> visit_clobber(node
, |node
| {
1720 self.collect_attr((attr
, pos
, derives
), node
.to_annotatable(), Node
::KIND
)
1724 None
if node
.is_mac_call() => {
1725 visit_clobber(node
, |node
| {
1726 // Do not clobber unless it's actually a macro (uncommon case).
1727 let (mac
, attrs
, _
) = node
.take_mac_call();
1728 self.check_attributes(&attrs
, &mac
);
1729 self.collect_bang(mac
, Node
::KIND
).make_ast
::<Node
>()
1733 assign_id
!(self, node
.node_id_mut(), || node
.noop_visit(self))
1740 impl<'a
, 'b
> MutVisitor
for InvocationCollector
<'a
, 'b
> {
1741 fn flat_map_item(&mut self, node
: P
<ast
::Item
>) -> SmallVec
<[P
<ast
::Item
>; 1]> {
1742 self.flat_map_node(node
)
1745 fn flat_map_trait_item(&mut self, node
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1746 self.flat_map_node(AstNodeWrapper
::new(node
, TraitItemTag
))
1749 fn flat_map_impl_item(&mut self, node
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1750 self.flat_map_node(AstNodeWrapper
::new(node
, ImplItemTag
))
1753 fn flat_map_foreign_item(
1755 node
: P
<ast
::ForeignItem
>,
1756 ) -> SmallVec
<[P
<ast
::ForeignItem
>; 1]> {
1757 self.flat_map_node(node
)
1760 fn flat_map_variant(&mut self, node
: ast
::Variant
) -> SmallVec
<[ast
::Variant
; 1]> {
1761 self.flat_map_node(node
)
1764 fn flat_map_field_def(&mut self, node
: ast
::FieldDef
) -> SmallVec
<[ast
::FieldDef
; 1]> {
1765 self.flat_map_node(node
)
1768 fn flat_map_pat_field(&mut self, node
: ast
::PatField
) -> SmallVec
<[ast
::PatField
; 1]> {
1769 self.flat_map_node(node
)
1772 fn flat_map_expr_field(&mut self, node
: ast
::ExprField
) -> SmallVec
<[ast
::ExprField
; 1]> {
1773 self.flat_map_node(node
)
1776 fn flat_map_param(&mut self, node
: ast
::Param
) -> SmallVec
<[ast
::Param
; 1]> {
1777 self.flat_map_node(node
)
1780 fn flat_map_generic_param(
1782 node
: ast
::GenericParam
,
1783 ) -> SmallVec
<[ast
::GenericParam
; 1]> {
1784 self.flat_map_node(node
)
1787 fn flat_map_arm(&mut self, node
: ast
::Arm
) -> SmallVec
<[ast
::Arm
; 1]> {
1788 self.flat_map_node(node
)
1791 fn flat_map_stmt(&mut self, node
: ast
::Stmt
) -> SmallVec
<[ast
::Stmt
; 1]> {
1792 // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
1793 // changing that requires some compatibility measures.
1795 // The only way that we can end up with a `MacCall` expression statement,
1796 // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
1797 // trailing expression in a block (e.g. `fn foo() { my_macro!() }`).
1798 // Record this information, so that we can report a more specific
1799 // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
1800 // See #78991 for an investigation of treating macros in this position
1801 // as statements, rather than expressions, during parsing.
1802 return match &node
.kind
{
1803 StmtKind
::Expr(expr
)
1804 if matches
!(**expr
, ast
::Expr { kind: ExprKind::MacCall(..), .. }
) =>
1806 self.cx
.current_expansion
.is_trailing_mac
= true;
1807 // Don't use `assign_id` for this statement - it may get removed
1808 // entirely due to a `#[cfg]` on the contained expression
1809 let res
= noop_flat_map_stmt(node
, self);
1810 self.cx
.current_expansion
.is_trailing_mac
= false;
1813 _
=> noop_flat_map_stmt(node
, self),
1817 self.flat_map_node(node
)
1820 fn visit_crate(&mut self, node
: &mut ast
::Crate
) {
1821 self.visit_node(node
)
1824 fn visit_ty(&mut self, node
: &mut P
<ast
::Ty
>) {
1825 self.visit_node(node
)
1828 fn visit_pat(&mut self, node
: &mut P
<ast
::Pat
>) {
1829 self.visit_node(node
)
1832 fn visit_expr(&mut self, node
: &mut P
<ast
::Expr
>) {
1833 // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
1834 if let Some(attr
) = node
.attrs
.first() {
1835 self.cfg().maybe_emit_expr_attr_err(attr
);
1837 self.visit_node(node
)
1840 fn filter_map_expr(&mut self, node
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
1841 self.flat_map_node(AstNodeWrapper
::new(node
, OptExprTag
))
1844 fn visit_block(&mut self, node
: &mut P
<ast
::Block
>) {
1845 let orig_dir_ownership
= mem
::replace(
1846 &mut self.cx
.current_expansion
.dir_ownership
,
1847 DirOwnership
::UnownedViaBlock
,
1849 noop_visit_block(node
, self);
1850 self.cx
.current_expansion
.dir_ownership
= orig_dir_ownership
;
1853 fn visit_id(&mut self, id
: &mut NodeId
) {
1854 // We may have already assigned a `NodeId`
1855 // by calling `assign_id`
1856 if self.monotonic
&& *id
== ast
::DUMMY_NODE_ID
{
1857 *id
= self.cx
.resolver
.next_node_id();
1862 pub struct ExpansionConfig
<'feat
> {
1863 pub crate_name
: String
,
1864 pub features
: Option
<&'feat Features
>,
1865 pub recursion_limit
: Limit
,
1866 pub trace_mac
: bool
,
1867 pub should_test
: bool
, // If false, strip `#[test]` nodes
1868 pub span_debug
: bool
, // If true, use verbose debugging for `proc_macro::Span`
1869 pub proc_macro_backtrace
: bool
, // If true, show backtraces for proc-macro panics
1872 impl<'feat
> ExpansionConfig
<'feat
> {
1873 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1877 recursion_limit
: Limit
::new(1024),
1881 proc_macro_backtrace
: false,
1885 fn proc_macro_hygiene(&self) -> bool
{
1886 self.features
.map_or(false, |features
| features
.proc_macro_hygiene
)