2 use crate::config
::StripUnconfigured
;
4 use crate::hygiene
::SyntaxContext
;
5 use crate::mbe
::macro_rules
::annotate_err_with_kind
;
6 use crate::module
::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}
;
7 use crate::placeholders
::{placeholder, PlaceholderExpander}
;
10 use rustc_ast
::mut_visit
::*;
11 use rustc_ast
::ptr
::P
;
13 use rustc_ast
::tokenstream
::TokenStream
;
14 use rustc_ast
::visit
::{self, AssocCtxt, Visitor}
;
15 use rustc_ast
::{AstLike, AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs}
;
16 use rustc_ast
::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}
;
17 use rustc_ast
::{NodeId, PatKind, Path, StmtKind, Unsafe}
;
18 use rustc_ast_pretty
::pprust
;
19 use rustc_attr
::{self as attr, is_builtin_attr}
;
20 use rustc_data_structures
::map_in_place
::MapInPlace
;
21 use rustc_data_structures
::stack
::ensure_sufficient_stack
;
22 use rustc_data_structures
::sync
::Lrc
;
23 use rustc_errors
::{Applicability, PResult}
;
24 use rustc_feature
::Features
;
25 use rustc_parse
::parser
::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma}
;
26 use rustc_parse
::validate_attr
;
27 use rustc_session
::lint
::builtin
::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, Symbol}
;
32 use rustc_span
::{ExpnId, FileName, Span, DUMMY_SP}
;
34 use smallvec
::{smallvec, SmallVec}
;
35 use std
::io
::ErrorKind
;
36 use std
::ops
::DerefMut
;
37 use std
::path
::PathBuf
;
39 use std
::{iter, mem, slice}
;
41 macro_rules
! ast_fragments
{
43 $
($Kind
:ident($AstTy
:ty
) {
45 $
(one
fn $mut_visit_ast
:ident
; fn $visit_ast
:ident
;)?
46 $
(many
fn $flat_map_ast_elt
:ident
; fn $visit_ast_elt
:ident($
($args
:tt
)*);)?
50 /// A fragment of AST that can be produced by a single macro expansion.
51 /// Can also serve as an input and intermediate result for macro expansion operations.
52 pub enum AstFragment
{
53 OptExpr(Option
<P
<ast
::Expr
>>),
57 /// "Discriminant" of an AST fragment.
58 #[derive(Copy, Clone, PartialEq, Eq)]
59 pub enum AstFragmentKind
{
64 impl AstFragmentKind
{
65 pub fn name(self) -> &'
static str {
67 AstFragmentKind
::OptExpr
=> "expression",
68 $
(AstFragmentKind
::$Kind
=> $kind_name
,)*
72 fn make_from
<'a
>(self, result
: Box
<dyn MacResult
+ 'a
>) -> Option
<AstFragment
> {
74 AstFragmentKind
::OptExpr
=>
75 result
.make_expr().map(Some
).map(AstFragment
::OptExpr
),
76 $
(AstFragmentKind
::$Kind
=> result
.$
make_ast().map(AstFragment
::$Kind
),)*
82 pub fn add_placeholders(&mut self, placeholders
: &[NodeId
]) {
83 if placeholders
.is_empty() {
87 $
($
(AstFragment
::$
Kind(ast
) => ast
.extend(placeholders
.iter().flat_map(|id
| {
88 // We are repeating through arguments with `many`, to do that we have to
89 // mention some macro variable from those arguments even if it's not used.
90 macro _repeating($flat_map_ast_elt
) {}
91 placeholder(AstFragmentKind
::$Kind
, *id
, None
).$
make_ast()
93 _
=> panic
!("unexpected AST fragment kind")
97 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
99 AstFragment
::OptExpr(expr
) => expr
,
100 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
104 $
(pub fn $
make_ast(self) -> $AstTy
{
106 AstFragment
::$
Kind(ast
) => ast
,
107 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
111 pub fn mut_visit_with
<F
: MutVisitor
>(&mut self, vis
: &mut F
) {
113 AstFragment
::OptExpr(opt_expr
) => {
114 visit_clobber(opt_expr
, |opt_expr
| {
115 if let Some(expr
) = opt_expr
{
116 vis
.filter_map_expr(expr
)
122 $
($
(AstFragment
::$
Kind(ast
) => vis
.$
mut_visit_ast(ast
),)?
)*
123 $
($
(AstFragment
::$
Kind(ast
) =>
124 ast
.flat_map_in_place(|ast
| vis
.$
flat_map_ast_elt(ast
)),)?
)*
128 pub fn visit_with
<'a
, V
: Visitor
<'a
>>(&'a
self, visitor
: &mut V
) {
130 AstFragment
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
131 AstFragment
::OptExpr(None
) => {}
132 $
($
(AstFragment
::$
Kind(ref ast
) => visitor
.$
visit_ast(ast
),)?
)*
133 $
($
(AstFragment
::$
Kind(ref ast
) => for ast_elt
in &ast
[..] {
134 visitor
.$
visit_ast_elt(ast_elt
, $
($args
)*);
140 impl<'a
> MacResult
for crate::mbe
::macro_rules
::ParserAnyMacro
<'a
> {
141 $
(fn $
make_ast(self: Box
<crate::mbe
::macro_rules
::ParserAnyMacro
<'a
>>)
143 Some(self.make(AstFragmentKind
::$Kind
).$
make_ast())
150 Expr(P
<ast
::Expr
>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
151 Pat(P
<ast
::Pat
>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
152 Ty(P
<ast
::Ty
>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
153 Stmts(SmallVec
<[ast
::Stmt
; 1]>) {
154 "statement"; many
fn flat_map_stmt
; fn visit_stmt(); fn make_stmts
;
156 Items(SmallVec
<[P
<ast
::Item
>; 1]>) {
157 "item"; many
fn flat_map_item
; fn visit_item(); fn make_items
;
159 TraitItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
161 many
fn flat_map_trait_item
;
162 fn visit_assoc_item(AssocCtxt
::Trait
);
165 ImplItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
167 many
fn flat_map_impl_item
;
168 fn visit_assoc_item(AssocCtxt
::Impl
);
171 ForeignItems(SmallVec
<[P
<ast
::ForeignItem
>; 1]>) {
173 many
fn flat_map_foreign_item
;
174 fn visit_foreign_item();
175 fn make_foreign_items
;
177 Arms(SmallVec
<[ast
::Arm
; 1]>) {
178 "match arm"; many
fn flat_map_arm
; fn visit_arm(); fn make_arms
;
180 Fields(SmallVec
<[ast
::ExprField
; 1]>) {
181 "field expression"; many
fn flat_map_expr_field
; fn visit_expr_field(); fn make_expr_fields
;
183 FieldPats(SmallVec
<[ast
::PatField
; 1]>) {
185 many
fn flat_map_pat_field
;
186 fn visit_pat_field();
189 GenericParams(SmallVec
<[ast
::GenericParam
; 1]>) {
191 many
fn flat_map_generic_param
;
192 fn visit_generic_param();
193 fn make_generic_params
;
195 Params(SmallVec
<[ast
::Param
; 1]>) {
196 "function parameter"; many
fn flat_map_param
; fn visit_param(); fn make_params
;
198 StructFields(SmallVec
<[ast
::FieldDef
; 1]>) {
200 many
fn flat_map_field_def
;
201 fn visit_field_def();
204 Variants(SmallVec
<[ast
::Variant
; 1]>) {
205 "variant"; many
fn flat_map_variant
; fn visit_variant(); fn make_variants
;
209 impl AstFragmentKind
{
210 crate fn dummy(self, span
: Span
) -> AstFragment
{
211 self.make_from(DummyResult
::any(span
)).expect("couldn't create a dummy AST fragment")
214 /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
215 pub fn supports_macro_expansion(self) -> bool
{
217 AstFragmentKind
::OptExpr
218 | AstFragmentKind
::Expr
219 | AstFragmentKind
::Pat
220 | AstFragmentKind
::Ty
221 | AstFragmentKind
::Stmts
222 | AstFragmentKind
::Items
223 | AstFragmentKind
::TraitItems
224 | AstFragmentKind
::ImplItems
225 | AstFragmentKind
::ForeignItems
=> true,
226 AstFragmentKind
::Arms
227 | AstFragmentKind
::Fields
228 | AstFragmentKind
::FieldPats
229 | AstFragmentKind
::GenericParams
230 | AstFragmentKind
::Params
231 | AstFragmentKind
::StructFields
232 | AstFragmentKind
::Variants
=> false,
236 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(
240 let mut items
= items
.into_iter();
242 AstFragmentKind
::Arms
=> {
243 AstFragment
::Arms(items
.map(Annotatable
::expect_arm
).collect())
245 AstFragmentKind
::Fields
=> {
246 AstFragment
::Fields(items
.map(Annotatable
::expect_expr_field
).collect())
248 AstFragmentKind
::FieldPats
=> {
249 AstFragment
::FieldPats(items
.map(Annotatable
::expect_pat_field
).collect())
251 AstFragmentKind
::GenericParams
=> {
252 AstFragment
::GenericParams(items
.map(Annotatable
::expect_generic_param
).collect())
254 AstFragmentKind
::Params
=> {
255 AstFragment
::Params(items
.map(Annotatable
::expect_param
).collect())
257 AstFragmentKind
::StructFields
=> {
258 AstFragment
::StructFields(items
.map(Annotatable
::expect_field_def
).collect())
260 AstFragmentKind
::Variants
=> {
261 AstFragment
::Variants(items
.map(Annotatable
::expect_variant
).collect())
263 AstFragmentKind
::Items
=> {
264 AstFragment
::Items(items
.map(Annotatable
::expect_item
).collect())
266 AstFragmentKind
::ImplItems
=> {
267 AstFragment
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect())
269 AstFragmentKind
::TraitItems
=> {
270 AstFragment
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect())
272 AstFragmentKind
::ForeignItems
=> {
273 AstFragment
::ForeignItems(items
.map(Annotatable
::expect_foreign_item
).collect())
275 AstFragmentKind
::Stmts
=> {
276 AstFragment
::Stmts(items
.map(Annotatable
::expect_stmt
).collect())
278 AstFragmentKind
::Expr
=> AstFragment
::Expr(
279 items
.next().expect("expected exactly one expression").expect_expr(),
281 AstFragmentKind
::OptExpr
=> {
282 AstFragment
::OptExpr(items
.next().map(Annotatable
::expect_expr
))
284 AstFragmentKind
::Pat
| AstFragmentKind
::Ty
=> {
285 panic
!("patterns and types aren't annotatable")
291 pub struct Invocation
{
292 pub kind
: InvocationKind
,
293 pub fragment_kind
: AstFragmentKind
,
294 pub expansion_data
: ExpansionData
,
297 pub enum InvocationKind
{
303 attr
: ast
::Attribute
,
304 // Re-insertion position for inert attributes.
307 // Required for resolving derive helper attributes.
316 impl InvocationKind
{
317 fn placeholder_visibility(&self) -> Option
<ast
::Visibility
> {
318 // HACK: For unnamed fields placeholders should have the same visibility as the actual
319 // fields because for tuple structs/variants resolve determines visibilities of their
320 // constructor using these field visibilities before attributes on them are are expanded.
321 // The assumption is that the attribute expansion cannot change field visibilities,
322 // and it holds because only inert attributes are supported in this position.
324 InvocationKind
::Attr { item: Annotatable::FieldDef(field), .. }
325 | InvocationKind
::Derive { item: Annotatable::FieldDef(field), .. }
326 if field
.ident
.is_none() =>
328 Some(field
.vis
.clone())
336 pub fn span(&self) -> Span
{
338 InvocationKind
::Bang { span, .. }
=> *span
,
339 InvocationKind
::Attr { attr, .. }
=> attr
.span
,
340 InvocationKind
::Derive { path, .. }
=> path
.span
,
345 pub struct MacroExpander
<'a
, 'b
> {
346 pub cx
: &'a
mut ExtCtxt
<'b
>,
347 monotonic
: bool
, // cf. `cx.monotonic_expander()`
350 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
351 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
352 MacroExpander { cx, monotonic }
355 // FIXME: Avoid visiting the crate as a `Mod` item,
356 // make crate a first class expansion target instead.
357 pub fn expand_crate(&mut self, mut krate
: ast
::Crate
) -> ast
::Crate
{
358 let file_path
= match self.cx
.source_map().span_to_unmapped_path(krate
.span
) {
359 FileName
::Real(name
) => name
.into_local_path(),
360 other
=> PathBuf
::from(other
.to_string()),
362 let dir_path
= file_path
.parent().unwrap_or(&file_path
).to_owned();
363 self.cx
.root_path
= dir_path
.clone();
364 self.cx
.current_expansion
.module
= Rc
::new(ModuleData
{
365 mod_path
: vec
![Ident
::from_str(&self.cx
.ecfg
.crate_name
)],
366 file_path_stack
: vec
![file_path
],
370 let krate_item
= AstFragment
::Items(smallvec
![P(ast
::Item
{
373 kind
: ast
::ItemKind
::Mod(
375 ModKind
::Loaded(krate
.items
, Inline
::Yes
, krate
.span
)
377 ident
: Ident
::invalid(),
378 id
: ast
::DUMMY_NODE_ID
,
379 vis
: ast
::Visibility
{
380 span
: krate
.span
.shrink_to_lo(),
381 kind
: ast
::VisibilityKind
::Public
,
387 match self.fully_expand_fragment(krate_item
).make_items().pop().map(P
::into_inner
) {
390 kind
: ast
::ItemKind
::Mod(_
, ModKind
::Loaded(items
, ..)),
397 // Resolution failed so we return an empty expansion
398 krate
.attrs
= vec
![];
399 krate
.items
= vec
![];
401 Some(ast
::Item { span, kind, .. }
) => {
402 krate
.attrs
= vec
![];
403 krate
.items
= vec
![];
407 "expected crate top-level item to be a module after macro expansion, found {} {}",
408 kind
.article(), kind
.descr()
413 self.cx
.trace_macros_diag();
417 // Recursively expand all macro invocations in this AST fragment.
418 pub fn fully_expand_fragment(&mut self, input_fragment
: AstFragment
) -> AstFragment
{
419 let orig_expansion_data
= self.cx
.current_expansion
.clone();
420 let orig_force_mode
= self.cx
.force_mode
;
421 self.cx
.current_expansion
.depth
= 0;
423 // Collect all macro invocations and replace them with placeholders.
424 let (mut fragment_with_placeholders
, mut invocations
) =
425 self.collect_invocations(input_fragment
, &[]);
427 // Optimization: if we resolve all imports now,
428 // we'll be able to immediately resolve most of imported macros.
429 self.resolve_imports();
431 // Resolve paths in all invocations and produce output expanded fragments for them, but
432 // do not insert them into our input AST fragment yet, only store in `expanded_fragments`.
433 // The output fragments also go through expansion recursively until no invocations are left.
434 // Unresolved macros produce dummy outputs as a recovery measure.
435 invocations
.reverse();
436 let mut expanded_fragments
= Vec
::new();
437 let mut undetermined_invocations
= Vec
::new();
438 let (mut progress
, mut force
) = (false, !self.monotonic
);
440 let (invoc
, ext
) = if let Some(invoc
) = invocations
.pop() {
443 self.resolve_imports();
444 if undetermined_invocations
.is_empty() {
447 invocations
= mem
::take(&mut undetermined_invocations
);
448 force
= !mem
::replace(&mut progress
, false);
449 if force
&& self.monotonic
{
450 self.cx
.sess
.delay_span_bug(
451 invocations
.last().unwrap().0.span(),
452 "expansion entered force mode without producing any errors",
458 let ext
= match ext
{
461 let eager_expansion_root
= if self.monotonic
{
462 invoc
.expansion_data
.id
464 orig_expansion_data
.id
466 match self.cx
.resolver
.resolve_macro_invocation(
468 eager_expansion_root
,
472 Err(Indeterminate
) => {
473 // Cannot resolve, will retry this invocation later.
474 undetermined_invocations
.push((invoc
, None
));
481 let ExpansionData { depth, id: expn_id, .. }
= invoc
.expansion_data
;
482 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
483 self.cx
.force_mode
= force
;
485 let fragment_kind
= invoc
.fragment_kind
;
486 let (expanded_fragment
, new_invocations
) = match self.expand_invoc(invoc
, &ext
.kind
) {
487 ExpandResult
::Ready(fragment
) => {
488 let derive_placeholders
= self
491 .take_derive_resolutions(expn_id
)
493 enum AnnotatableRef
<'a
> {
494 Item(&'a P
<ast
::Item
>),
497 let item
= match &fragment
{
498 AstFragment
::Items(items
) => match &items
[..] {
499 [item
] => AnnotatableRef
::Item(item
),
502 AstFragment
::Stmts(stmts
) => match &stmts
[..] {
503 [stmt
] => AnnotatableRef
::Stmt(stmt
),
509 invocations
.reserve(derives
.len());
512 .map(|(_exts
, path
)| {
513 // FIXME: Consider using the derive resolutions (`_exts`)
514 // instead of enqueuing the derives to be resolved again later.
515 let expn_id
= ExpnId
::fresh(None
);
518 kind
: InvocationKind
::Derive
{
521 AnnotatableRef
::Item(item
) => {
522 Annotatable
::Item(item
.clone())
524 AnnotatableRef
::Stmt(stmt
) => {
525 Annotatable
::Stmt(P(stmt
.clone()))
530 expansion_data
: ExpansionData
{
532 ..self.cx
.current_expansion
.clone()
537 NodeId
::placeholder_from_expn_id(expn_id
)
541 .unwrap_or_default();
543 self.collect_invocations(fragment
, &derive_placeholders
)
545 ExpandResult
::Retry(invoc
) => {
549 "expansion entered force mode but is still stuck",
552 // Cannot expand, will retry this invocation later.
553 undetermined_invocations
.push((invoc
, Some(ext
)));
560 if expanded_fragments
.len() < depth
{
561 expanded_fragments
.push(Vec
::new());
563 expanded_fragments
[depth
- 1].push((expn_id
, expanded_fragment
));
564 invocations
.extend(new_invocations
.into_iter().rev());
567 self.cx
.current_expansion
= orig_expansion_data
;
568 self.cx
.force_mode
= orig_force_mode
;
570 // Finally incorporate all the expanded macros into the input AST fragment.
571 let mut placeholder_expander
= PlaceholderExpander
::new(self.cx
, self.monotonic
);
572 while let Some(expanded_fragments
) = expanded_fragments
.pop() {
573 for (expn_id
, expanded_fragment
) in expanded_fragments
.into_iter().rev() {
575 .add(NodeId
::placeholder_from_expn_id(expn_id
), expanded_fragment
);
578 fragment_with_placeholders
.mut_visit_with(&mut placeholder_expander
);
579 fragment_with_placeholders
582 fn resolve_imports(&mut self) {
584 self.cx
.resolver
.resolve_imports();
588 /// Collects all macro invocations reachable at this time in this AST fragment, and replace
589 /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
590 /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
591 /// prepares data for resolving paths of macro invocations.
592 fn collect_invocations(
594 mut fragment
: AstFragment
,
595 extra_placeholders
: &[NodeId
],
596 ) -> (AstFragment
, Vec
<(Invocation
, Option
<Lrc
<SyntaxExtension
>>)>) {
597 // Resolve `$crate`s in the fragment for pretty-printing.
598 self.cx
.resolver
.resolve_dollar_crates();
601 let mut collector
= InvocationCollector
{
602 cfg
: StripUnconfigured
{
604 features
: self.cx
.ecfg
.features
,
608 invocations
: Vec
::new(),
609 monotonic
: self.monotonic
,
611 fragment
.mut_visit_with(&mut collector
);
612 fragment
.add_placeholders(extra_placeholders
);
613 collector
.invocations
619 .visit_ast_fragment_with_placeholders(self.cx
.current_expansion
.id
, &fragment
);
622 (fragment
, invocations
)
625 fn error_recursion_limit_reached(&mut self) {
626 let expn_data
= self.cx
.current_expansion
.id
.expn_data();
627 let suggested_limit
= self.cx
.ecfg
.recursion_limit
* 2;
631 &format
!("recursion limit reached while expanding `{}`", expn_data
.kind
.descr()),
634 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
635 suggested_limit
, self.cx
.ecfg
.crate_name
,
638 self.cx
.trace_macros_diag();
641 /// A macro's expansion does not fit in this fragment kind.
642 /// For example, a non-type macro in a type position.
643 fn error_wrong_fragment_kind(&mut self, kind
: AstFragmentKind
, mac
: &ast
::MacCall
, span
: Span
) {
645 "non-{kind} macro in {kind} position: {path}",
647 path
= pprust
::path_to_string(&mac
.path
),
649 self.cx
.span_err(span
, &msg
);
650 self.cx
.trace_macros_diag();
656 ext
: &SyntaxExtensionKind
,
657 ) -> ExpandResult
<AstFragment
, Invocation
> {
658 let recursion_limit
=
659 self.cx
.reduced_recursion_limit
.unwrap_or(self.cx
.ecfg
.recursion_limit
);
660 if !recursion_limit
.value_within_limit(self.cx
.current_expansion
.depth
) {
661 if self.cx
.reduced_recursion_limit
.is_none() {
662 self.error_recursion_limit_reached();
665 // Reduce the recursion limit by half each time it triggers.
666 self.cx
.reduced_recursion_limit
= Some(recursion_limit
/ 2);
668 return ExpandResult
::Ready(invoc
.fragment_kind
.dummy(invoc
.span()));
671 let (fragment_kind
, span
) = (invoc
.fragment_kind
, invoc
.span());
672 ExpandResult
::Ready(match invoc
.kind
{
673 InvocationKind
::Bang { mac, .. }
=> match ext
{
674 SyntaxExtensionKind
::Bang(expander
) => {
675 let tok_result
= match expander
.expand(self.cx
, span
, mac
.args
.inner_tokens()) {
676 Err(_
) => return ExpandResult
::Ready(fragment_kind
.dummy(span
)),
679 self.parse_ast_fragment(tok_result
, fragment_kind
, &mac
.path
, span
)
681 SyntaxExtensionKind
::LegacyBang(expander
) => {
682 let prev
= self.cx
.current_expansion
.prior_type_ascription
;
683 self.cx
.current_expansion
.prior_type_ascription
= mac
.prior_type_ascription
;
684 let tok_result
= expander
.expand(self.cx
, span
, mac
.args
.inner_tokens());
685 let result
= if let Some(result
) = fragment_kind
.make_from(tok_result
) {
688 self.error_wrong_fragment_kind(fragment_kind
, &mac
, span
);
689 fragment_kind
.dummy(span
)
691 self.cx
.current_expansion
.prior_type_ascription
= prev
;
696 InvocationKind
::Attr { attr, pos, mut item, derives }
=> match ext
{
697 SyntaxExtensionKind
::Attr(expander
) => {
698 self.gate_proc_macro_input(&item
);
699 self.gate_proc_macro_attr_item(span
, &item
);
700 let tokens
= match attr
.style
{
701 AttrStyle
::Outer
=> item
.into_tokens(&self.cx
.sess
.parse_sess
),
702 // FIXME: Properly collect tokens for inner attributes
703 AttrStyle
::Inner
=> rustc_parse
::fake_token_stream(
704 &self.cx
.sess
.parse_sess
,
705 &item
.into_nonterminal(),
708 let attr_item
= attr
.unwrap_normal_item();
709 if let MacArgs
::Eq(..) = attr_item
.args
{
710 self.cx
.span_err(span
, "key-value macro attributes are not supported");
712 let inner_tokens
= attr_item
.args
.inner_tokens();
713 let tok_result
= match expander
.expand(self.cx
, span
, inner_tokens
, tokens
) {
714 Err(_
) => return ExpandResult
::Ready(fragment_kind
.dummy(span
)),
717 self.parse_ast_fragment(tok_result
, fragment_kind
, &attr_item
.path
, span
)
719 SyntaxExtensionKind
::LegacyAttr(expander
) => {
720 match validate_attr
::parse_meta(&self.cx
.sess
.parse_sess
, &attr
) {
722 let items
= match expander
.expand(self.cx
, span
, &meta
, item
) {
723 ExpandResult
::Ready(items
) => items
,
724 ExpandResult
::Retry(item
) => {
725 // Reassemble the original invocation for retrying.
726 return ExpandResult
::Retry(Invocation
{
727 kind
: InvocationKind
::Attr { attr, pos, item, derives }
,
732 fragment_kind
.expect_from_annotatables(items
)
736 fragment_kind
.dummy(span
)
740 SyntaxExtensionKind
::NonMacroAttr { mark_used }
=> {
741 self.cx
.sess
.mark_attr_known(&attr
);
743 self.cx
.sess
.mark_attr_used(&attr
);
745 item
.visit_attrs(|attrs
| attrs
.insert(pos
, attr
));
746 fragment_kind
.expect_from_annotatables(iter
::once(item
))
750 InvocationKind
::Derive { path, item }
=> match ext
{
751 SyntaxExtensionKind
::Derive(expander
)
752 | SyntaxExtensionKind
::LegacyDerive(expander
) => {
753 if let SyntaxExtensionKind
::Derive(..) = ext
{
754 self.gate_proc_macro_input(&item
);
756 let meta
= ast
::MetaItem { kind: ast::MetaItemKind::Word, span, path }
;
757 let items
= match expander
.expand(self.cx
, span
, &meta
, item
) {
758 ExpandResult
::Ready(items
) => items
,
759 ExpandResult
::Retry(item
) => {
760 // Reassemble the original invocation for retrying.
761 return ExpandResult
::Retry(Invocation
{
762 kind
: InvocationKind
::Derive { path: meta.path, item }
,
767 fragment_kind
.expect_from_annotatables(items
)
774 fn gate_proc_macro_attr_item(&self, span
: Span
, item
: &Annotatable
) {
775 let kind
= match item
{
777 | Annotatable
::TraitItem(_
)
778 | Annotatable
::ImplItem(_
)
779 | Annotatable
::ForeignItem(_
) => return,
780 Annotatable
::Stmt(stmt
) => {
781 // Attributes are stable on item statements,
782 // but unstable on all other kinds of statements
788 Annotatable
::Expr(_
) => "expressions",
790 | Annotatable
::ExprField(..)
791 | Annotatable
::PatField(..)
792 | Annotatable
::GenericParam(..)
793 | Annotatable
::Param(..)
794 | Annotatable
::FieldDef(..)
795 | Annotatable
::Variant(..) => panic
!("unexpected annotatable"),
797 if self.cx
.ecfg
.proc_macro_hygiene() {
801 &self.cx
.sess
.parse_sess
,
802 sym
::proc_macro_hygiene
,
804 &format
!("custom attributes cannot be applied to {}", kind
),
809 fn gate_proc_macro_input(&self, annotatable
: &Annotatable
) {
810 struct GateProcMacroInput
<'a
> {
811 parse_sess
: &'a ParseSess
,
814 impl<'ast
, 'a
> Visitor
<'ast
> for GateProcMacroInput
<'a
> {
815 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
817 ast
::ItemKind
::Mod(_
, mod_kind
)
818 if !matches
!(mod_kind
, ModKind
::Loaded(_
, Inline
::Yes
, _
)) =>
822 sym
::proc_macro_hygiene
,
824 "non-inline modules in proc macro input are unstable",
831 visit
::walk_item(self, item
);
835 if !self.cx
.ecfg
.proc_macro_hygiene() {
837 .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess }
);
841 fn parse_ast_fragment(
844 kind
: AstFragmentKind
,
848 let mut parser
= self.cx
.new_parser_from_tts(toks
);
849 match parse_ast_fragment(&mut parser
, kind
) {
851 ensure_complete_parse(&mut parser
, path
, kind
.name(), span
);
855 if err
.span
.is_dummy() {
858 annotate_err_with_kind(&mut err
, kind
, span
);
860 self.cx
.trace_macros_diag();
867 pub fn parse_ast_fragment
<'a
>(
868 this
: &mut Parser
<'a
>,
869 kind
: AstFragmentKind
,
870 ) -> PResult
<'a
, AstFragment
> {
872 AstFragmentKind
::Items
=> {
873 let mut items
= SmallVec
::new();
874 while let Some(item
) = this
.parse_item(ForceCollect
::No
)?
{
877 AstFragment
::Items(items
)
879 AstFragmentKind
::TraitItems
=> {
880 let mut items
= SmallVec
::new();
881 while let Some(item
) = this
.parse_trait_item()?
{
884 AstFragment
::TraitItems(items
)
886 AstFragmentKind
::ImplItems
=> {
887 let mut items
= SmallVec
::new();
888 while let Some(item
) = this
.parse_impl_item()?
{
891 AstFragment
::ImplItems(items
)
893 AstFragmentKind
::ForeignItems
=> {
894 let mut items
= SmallVec
::new();
895 while let Some(item
) = this
.parse_foreign_item()?
{
898 AstFragment
::ForeignItems(items
)
900 AstFragmentKind
::Stmts
=> {
901 let mut stmts
= SmallVec
::new();
902 // Won't make progress on a `}`.
903 while this
.token
!= token
::Eof
&& this
.token
!= token
::CloseDelim(token
::Brace
) {
904 if let Some(stmt
) = this
.parse_full_stmt(AttemptLocalParseRecovery
::Yes
)?
{
908 AstFragment
::Stmts(stmts
)
910 AstFragmentKind
::Expr
=> AstFragment
::Expr(this
.parse_expr()?
),
911 AstFragmentKind
::OptExpr
=> {
912 if this
.token
!= token
::Eof
{
913 AstFragment
::OptExpr(Some(this
.parse_expr()?
))
915 AstFragment
::OptExpr(None
)
918 AstFragmentKind
::Ty
=> AstFragment
::Ty(this
.parse_ty()?
),
919 AstFragmentKind
::Pat
=> {
920 AstFragment
::Pat(this
.parse_pat_allow_top_alt(None
, GateOr
::Yes
, RecoverComma
::No
)?
)
922 AstFragmentKind
::Arms
923 | AstFragmentKind
::Fields
924 | AstFragmentKind
::FieldPats
925 | AstFragmentKind
::GenericParams
926 | AstFragmentKind
::Params
927 | AstFragmentKind
::StructFields
928 | AstFragmentKind
::Variants
=> panic
!("unexpected AST fragment kind"),
932 pub fn ensure_complete_parse
<'a
>(
933 this
: &mut Parser
<'a
>,
938 if this
.token
!= token
::Eof
{
939 let token
= pprust
::token_to_string(&this
.token
);
940 let msg
= format
!("macro expansion ignores token `{}` and any following", token
);
941 // Avoid emitting backtrace info twice.
942 let def_site_span
= this
.token
.span
.with_ctxt(SyntaxContext
::root());
943 let mut err
= this
.struct_span_err(def_site_span
, &msg
);
944 err
.span_label(span
, "caused by the macro expansion here");
946 "the usage of `{}!` is likely invalid in {} context",
947 pprust
::path_to_string(macro_path
),
951 let semi_span
= this
.sess
.source_map().next_point(span
);
953 let semi_full_span
= semi_span
.to(this
.sess
.source_map().next_point(semi_span
));
954 match this
.sess
.source_map().span_to_snippet(semi_full_span
) {
955 Ok(ref snippet
) if &snippet
[..] != ";" && kind_name
== "expression" => {
958 "you might be missing a semicolon here",
960 Applicability
::MaybeIncorrect
,
969 struct InvocationCollector
<'a
, 'b
> {
970 cx
: &'a
mut ExtCtxt
<'b
>,
971 cfg
: StripUnconfigured
<'a
>,
972 invocations
: Vec
<(Invocation
, Option
<Lrc
<SyntaxExtension
>>)>,
976 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
977 fn collect(&mut self, fragment_kind
: AstFragmentKind
, kind
: InvocationKind
) -> AstFragment
{
978 let expn_id
= ExpnId
::fresh(None
);
979 let vis
= kind
.placeholder_visibility();
980 self.invocations
.push((
984 expansion_data
: ExpansionData
{
986 depth
: self.cx
.current_expansion
.depth
+ 1,
987 ..self.cx
.current_expansion
.clone()
992 placeholder(fragment_kind
, NodeId
::placeholder_from_expn_id(expn_id
), vis
)
999 kind
: AstFragmentKind
,
1001 self.collect(kind
, InvocationKind
::Bang { mac, span }
)
1006 (attr
, pos
, derives
): (ast
::Attribute
, usize, Vec
<Path
>),
1008 kind
: AstFragmentKind
,
1010 self.collect(kind
, InvocationKind
::Attr { attr, pos, item, derives }
)
1013 /// If `item` is an attribute invocation, remove the attribute and return it together with
1014 /// its position and derives following it. We have to collect the derives in order to resolve
1015 /// legacy derive helpers (helpers written before derives that introduce them).
1018 item
: &mut impl AstLike
,
1019 ) -> Option
<(ast
::Attribute
, usize, Vec
<Path
>)> {
1020 let mut attr
= None
;
1022 item
.visit_attrs(|attrs
| {
1025 .position(|a
| !self.cx
.sess
.is_attr_known(a
) && !is_builtin_attr(a
))
1027 let attr
= attrs
.remove(attr_pos
);
1028 let following_derives
= attrs
[attr_pos
..]
1030 .filter(|a
| a
.has_name(sym
::derive
))
1031 .flat_map(|a
| a
.meta_item_list().unwrap_or_default())
1032 .filter_map(|nested_meta
| match nested_meta
{
1033 NestedMetaItem
::MetaItem(ast
::MetaItem
{
1034 kind
: MetaItemKind
::Word
,
1042 (attr
, attr_pos
, following_derives
)
1049 fn configure
<T
: AstLike
>(&mut self, node
: T
) -> Option
<T
> {
1050 self.cfg
.configure(node
)
1053 // Detect use of feature-gated or invalid attributes on macro invocations
1054 // since they will not be detected after macro expansion.
1055 fn check_attributes(&mut self, attrs
: &[ast
::Attribute
]) {
1056 let features
= self.cx
.ecfg
.features
.unwrap();
1057 for attr
in attrs
.iter() {
1058 rustc_ast_passes
::feature_gate
::check_attribute(attr
, self.cx
.sess
, features
);
1059 validate_attr
::check_meta(&self.cx
.sess
.parse_sess
, attr
);
1060 if attr
.doc_str().is_some() {
1061 self.cx
.sess
.parse_sess
.buffer_lint_with_diagnostic(
1062 &UNUSED_DOC_COMMENTS
,
1065 "unused doc comment",
1066 BuiltinLintDiagnostics
::UnusedDocComment(attr
.span
),
1073 impl<'a
, 'b
> MutVisitor
for InvocationCollector
<'a
, 'b
> {
1074 fn visit_expr(&mut self, expr
: &mut P
<ast
::Expr
>) {
1075 self.cfg
.configure_expr(expr
);
1076 visit_clobber(expr
.deref_mut(), |mut expr
| {
1077 if let Some(attr
) = self.take_first_attr(&mut expr
) {
1078 // Collect the invoc regardless of whether or not attributes are permitted here
1079 // expansion will eat the attribute so it won't error later.
1080 self.cfg
.maybe_emit_expr_attr_err(&attr
.0);
1082 // AstFragmentKind::Expr requires the macro to emit an expression.
1084 .collect_attr(attr
, Annotatable
::Expr(P(expr
)), AstFragmentKind
::Expr
)
1089 if let ast
::ExprKind
::MacCall(mac
) = expr
.kind
{
1090 self.check_attributes(&expr
.attrs
);
1091 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::Expr
).make_expr().into_inner()
1093 ensure_sufficient_stack(|| noop_visit_expr(&mut expr
, self));
1099 fn flat_map_arm(&mut self, arm
: ast
::Arm
) -> SmallVec
<[ast
::Arm
; 1]> {
1100 let mut arm
= configure
!(self, arm
);
1102 if let Some(attr
) = self.take_first_attr(&mut arm
) {
1104 .collect_attr(attr
, Annotatable
::Arm(arm
), AstFragmentKind
::Arms
)
1108 noop_flat_map_arm(arm
, self)
1111 fn flat_map_expr_field(&mut self, field
: ast
::ExprField
) -> SmallVec
<[ast
::ExprField
; 1]> {
1112 let mut field
= configure
!(self, field
);
1114 if let Some(attr
) = self.take_first_attr(&mut field
) {
1116 .collect_attr(attr
, Annotatable
::ExprField(field
), AstFragmentKind
::Fields
)
1117 .make_expr_fields();
1120 noop_flat_map_expr_field(field
, self)
1123 fn flat_map_pat_field(&mut self, fp
: ast
::PatField
) -> SmallVec
<[ast
::PatField
; 1]> {
1124 let mut fp
= configure
!(self, fp
);
1126 if let Some(attr
) = self.take_first_attr(&mut fp
) {
1128 .collect_attr(attr
, Annotatable
::PatField(fp
), AstFragmentKind
::FieldPats
)
1132 noop_flat_map_pat_field(fp
, self)
1135 fn flat_map_param(&mut self, p
: ast
::Param
) -> SmallVec
<[ast
::Param
; 1]> {
1136 let mut p
= configure
!(self, p
);
1138 if let Some(attr
) = self.take_first_attr(&mut p
) {
1140 .collect_attr(attr
, Annotatable
::Param(p
), AstFragmentKind
::Params
)
1144 noop_flat_map_param(p
, self)
1147 fn flat_map_field_def(&mut self, sf
: ast
::FieldDef
) -> SmallVec
<[ast
::FieldDef
; 1]> {
1148 let mut sf
= configure
!(self, sf
);
1150 if let Some(attr
) = self.take_first_attr(&mut sf
) {
1152 .collect_attr(attr
, Annotatable
::FieldDef(sf
), AstFragmentKind
::StructFields
)
1156 noop_flat_map_field_def(sf
, self)
1159 fn flat_map_variant(&mut self, variant
: ast
::Variant
) -> SmallVec
<[ast
::Variant
; 1]> {
1160 let mut variant
= configure
!(self, variant
);
1162 if let Some(attr
) = self.take_first_attr(&mut variant
) {
1164 .collect_attr(attr
, Annotatable
::Variant(variant
), AstFragmentKind
::Variants
)
1168 noop_flat_map_variant(variant
, self)
1171 fn filter_map_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
1172 let expr
= configure
!(self, expr
);
1173 expr
.filter_map(|mut expr
| {
1174 if let Some(attr
) = self.take_first_attr(&mut expr
) {
1175 self.cfg
.maybe_emit_expr_attr_err(&attr
.0);
1178 .collect_attr(attr
, Annotatable
::Expr(P(expr
)), AstFragmentKind
::OptExpr
)
1180 .map(|expr
| expr
.into_inner());
1183 if let ast
::ExprKind
::MacCall(mac
) = expr
.kind
{
1184 self.check_attributes(&expr
.attrs
);
1185 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::OptExpr
)
1187 .map(|expr
| expr
.into_inner())
1190 noop_visit_expr(&mut expr
, self);
1197 fn visit_pat(&mut self, pat
: &mut P
<ast
::Pat
>) {
1199 PatKind
::MacCall(_
) => {}
1200 _
=> return noop_visit_pat(pat
, self),
1203 visit_clobber(pat
, |mut pat
| match mem
::replace(&mut pat
.kind
, PatKind
::Wild
) {
1204 PatKind
::MacCall(mac
) => {
1205 self.collect_bang(mac
, pat
.span
, AstFragmentKind
::Pat
).make_pat()
1207 _
=> unreachable
!(),
1211 fn flat_map_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVec
<[ast
::Stmt
; 1]> {
1212 let mut stmt
= configure
!(self, stmt
);
1214 // we'll expand attributes on expressions separately
1215 if !stmt
.is_expr() {
1216 if let Some(attr
) = self.take_first_attr(&mut stmt
) {
1218 .collect_attr(attr
, Annotatable
::Stmt(P(stmt
)), AstFragmentKind
::Stmts
)
1223 if let StmtKind
::MacCall(mac
) = stmt
.kind
{
1224 let MacCallStmt { mac, style, attrs, tokens: _ }
= mac
.into_inner();
1225 self.check_attributes(&attrs
);
1226 let mut placeholder
=
1227 self.collect_bang(mac
, stmt
.span
, AstFragmentKind
::Stmts
).make_stmts();
1229 // If this is a macro invocation with a semicolon, then apply that
1230 // semicolon to the final statement produced by expansion.
1231 if style
== MacStmtStyle
::Semicolon
{
1232 if let Some(stmt
) = placeholder
.pop() {
1233 placeholder
.push(stmt
.add_trailing_semicolon());
1240 // The placeholder expander gives ids to statements, so we avoid folding the id here.
1241 let ast
::Stmt { id, kind, span }
= stmt
;
1242 noop_flat_map_stmt_kind(kind
, self)
1244 .map(|kind
| ast
::Stmt { id, kind, span }
)
1248 fn visit_block(&mut self, block
: &mut P
<Block
>) {
1249 let orig_dir_ownership
= mem
::replace(
1250 &mut self.cx
.current_expansion
.dir_ownership
,
1251 DirOwnership
::UnownedViaBlock
,
1253 noop_visit_block(block
, self);
1254 self.cx
.current_expansion
.dir_ownership
= orig_dir_ownership
;
1257 fn flat_map_item(&mut self, item
: P
<ast
::Item
>) -> SmallVec
<[P
<ast
::Item
>; 1]> {
1258 let mut item
= configure
!(self, item
);
1260 if let Some(attr
) = self.take_first_attr(&mut item
) {
1262 .collect_attr(attr
, Annotatable
::Item(item
), AstFragmentKind
::Items
)
1266 let mut attrs
= mem
::take(&mut item
.attrs
); // We do this to please borrowck.
1267 let ident
= item
.ident
;
1268 let span
= item
.span
;
1271 ast
::ItemKind
::MacCall(..) => {
1273 self.check_attributes(&item
.attrs
);
1274 item
.and_then(|item
| match item
.kind
{
1275 ItemKind
::MacCall(mac
) => {
1276 self.collect_bang(mac
, span
, AstFragmentKind
::Items
).make_items()
1278 _
=> unreachable
!(),
1281 ast
::ItemKind
::Mod(_
, ref mut mod_kind
) if ident
!= Ident
::invalid() => {
1282 let (file_path
, dir_path
, dir_ownership
) = match mod_kind
{
1283 ModKind
::Loaded(_
, inline
, _
) => {
1284 // Inline `mod foo { ... }`, but we still need to push directories.
1285 let (dir_path
, dir_ownership
) = mod_dir_path(
1289 &self.cx
.current_expansion
.module
,
1290 self.cx
.current_expansion
.dir_ownership
,
1294 (None
, dir_path
, dir_ownership
)
1296 ModKind
::Unloaded
=> {
1297 // We have an outline `mod foo;` so we need to parse the file.
1298 let old_attrs_len
= attrs
.len();
1299 let ParsedExternalMod
{
1305 } = parse_external_mod(
1309 &self.cx
.current_expansion
.module
,
1310 self.cx
.current_expansion
.dir_ownership
,
1314 if let Some(extern_mod_loaded
) = self.cx
.extern_mod_loaded
{
1315 (attrs
, items
) = extern_mod_loaded(ident
, attrs
, items
, inner_span
);
1318 *mod_kind
= ModKind
::Loaded(items
, Inline
::No
, inner_span
);
1320 if item
.attrs
.len() > old_attrs_len
{
1321 // If we loaded an out-of-line module and added some inner attributes,
1322 // then we need to re-configure it and re-collect attributes for
1323 // resolution and expansion.
1324 item
= configure
!(self, item
);
1326 if let Some(attr
) = self.take_first_attr(&mut item
) {
1330 Annotatable
::Item(item
),
1331 AstFragmentKind
::Items
,
1336 (Some(file_path
), dir_path
, dir_ownership
)
1340 // Set the module info before we flat map.
1341 let mut module
= self.cx
.current_expansion
.module
.with_dir_path(dir_path
);
1342 module
.mod_path
.push(ident
);
1343 if let Some(file_path
) = file_path
{
1344 module
.file_path_stack
.push(file_path
);
1348 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
1349 let orig_dir_ownership
=
1350 mem
::replace(&mut self.cx
.current_expansion
.dir_ownership
, dir_ownership
);
1352 let result
= noop_flat_map_item(item
, self);
1354 // Restore the module info.
1355 self.cx
.current_expansion
.dir_ownership
= orig_dir_ownership
;
1356 self.cx
.current_expansion
.module
= orig_module
;
1362 noop_flat_map_item(item
, self)
1367 fn flat_map_trait_item(&mut self, item
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1368 let mut item
= configure
!(self, item
);
1370 if let Some(attr
) = self.take_first_attr(&mut item
) {
1372 .collect_attr(attr
, Annotatable
::TraitItem(item
), AstFragmentKind
::TraitItems
)
1373 .make_trait_items();
1377 ast
::AssocItemKind
::MacCall(..) => {
1378 self.check_attributes(&item
.attrs
);
1379 item
.and_then(|item
| match item
.kind
{
1380 ast
::AssocItemKind
::MacCall(mac
) => self
1381 .collect_bang(mac
, item
.span
, AstFragmentKind
::TraitItems
)
1382 .make_trait_items(),
1383 _
=> unreachable
!(),
1386 _
=> noop_flat_map_assoc_item(item
, self),
1390 fn flat_map_impl_item(&mut self, item
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1391 let mut item
= configure
!(self, item
);
1393 if let Some(attr
) = self.take_first_attr(&mut item
) {
1395 .collect_attr(attr
, Annotatable
::ImplItem(item
), AstFragmentKind
::ImplItems
)
1400 ast
::AssocItemKind
::MacCall(..) => {
1401 self.check_attributes(&item
.attrs
);
1402 item
.and_then(|item
| match item
.kind
{
1403 ast
::AssocItemKind
::MacCall(mac
) => self
1404 .collect_bang(mac
, item
.span
, AstFragmentKind
::ImplItems
)
1406 _
=> unreachable
!(),
1409 _
=> noop_flat_map_assoc_item(item
, self),
1413 fn visit_ty(&mut self, ty
: &mut P
<ast
::Ty
>) {
1415 ast
::TyKind
::MacCall(_
) => {}
1416 _
=> return noop_visit_ty(ty
, self),
1419 visit_clobber(ty
, |mut ty
| match mem
::replace(&mut ty
.kind
, ast
::TyKind
::Err
) {
1420 ast
::TyKind
::MacCall(mac
) => {
1421 self.collect_bang(mac
, ty
.span
, AstFragmentKind
::Ty
).make_ty()
1423 _
=> unreachable
!(),
1427 fn flat_map_foreign_item(
1429 foreign_item
: P
<ast
::ForeignItem
>,
1430 ) -> SmallVec
<[P
<ast
::ForeignItem
>; 1]> {
1431 let mut foreign_item
= configure
!(self, foreign_item
);
1433 if let Some(attr
) = self.take_first_attr(&mut foreign_item
) {
1437 Annotatable
::ForeignItem(foreign_item
),
1438 AstFragmentKind
::ForeignItems
,
1440 .make_foreign_items();
1443 match foreign_item
.kind
{
1444 ast
::ForeignItemKind
::MacCall(..) => {
1445 self.check_attributes(&foreign_item
.attrs
);
1446 foreign_item
.and_then(|item
| match item
.kind
{
1447 ast
::ForeignItemKind
::MacCall(mac
) => self
1448 .collect_bang(mac
, item
.span
, AstFragmentKind
::ForeignItems
)
1449 .make_foreign_items(),
1450 _
=> unreachable
!(),
1453 _
=> noop_flat_map_foreign_item(foreign_item
, self),
1457 fn flat_map_generic_param(
1459 param
: ast
::GenericParam
,
1460 ) -> SmallVec
<[ast
::GenericParam
; 1]> {
1461 let mut param
= configure
!(self, param
);
1463 if let Some(attr
) = self.take_first_attr(&mut param
) {
1467 Annotatable
::GenericParam(param
),
1468 AstFragmentKind
::GenericParams
,
1470 .make_generic_params();
1473 noop_flat_map_generic_param(param
, self)
1476 fn visit_attribute(&mut self, at
: &mut ast
::Attribute
) {
1477 // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
1478 // contents="file contents")]` attributes
1479 if !self.cx
.sess
.check_name(at
, sym
::doc
) {
1480 return noop_visit_attribute(at
, self);
1483 if let Some(list
) = at
.meta_item_list() {
1484 if !list
.iter().any(|it
| it
.has_name(sym
::include
)) {
1485 return noop_visit_attribute(at
, self);
1488 let mut items
= vec
![];
1490 for mut it
in list
{
1491 if !it
.has_name(sym
::include
) {
1493 noop_visit_meta_list_item(&mut it
, self);
1499 if let Some(file
) = it
.value_str() {
1500 let err_count
= self.cx
.sess
.parse_sess
.span_diagnostic
.err_count();
1501 self.check_attributes(slice
::from_ref(at
));
1502 if self.cx
.sess
.parse_sess
.span_diagnostic
.err_count() > err_count
{
1503 // avoid loading the file if they haven't enabled the feature
1504 return noop_visit_attribute(at
, self);
1507 let filename
= match self.cx
.resolve_path(&*file
.as_str(), it
.span()) {
1508 Ok(filename
) => filename
,
1515 match self.cx
.source_map().load_file(&filename
) {
1516 Ok(source_file
) => {
1517 let src
= source_file
1520 .expect("freshly loaded file should have a source");
1521 let src_interned
= Symbol
::intern(src
.as_str());
1523 let include_info
= vec
![
1524 ast
::NestedMetaItem
::MetaItem(attr
::mk_name_value_item_str(
1525 Ident
::with_dummy_span(sym
::file
),
1529 ast
::NestedMetaItem
::MetaItem(attr
::mk_name_value_item_str(
1530 Ident
::with_dummy_span(sym
::contents
),
1536 let include_ident
= Ident
::with_dummy_span(sym
::include
);
1537 let item
= attr
::mk_list_item(include_ident
, include_info
);
1538 items
.push(ast
::NestedMetaItem
::MetaItem(item
));
1541 let lit_span
= it
.name_value_literal_span().unwrap();
1543 if e
.kind() == ErrorKind
::InvalidData
{
1547 &format
!("{} wasn't a utf-8 file", filename
.display()),
1549 .span_label(lit_span
, "contains invalid utf-8")
1552 let mut err
= self.cx
.struct_span_err(
1554 &format
!("couldn't read {}: {}", filename
.display(), e
),
1556 err
.span_label(lit_span
, "couldn't read file");
1565 .struct_span_err(it
.span(), "expected path to external documentation");
1567 // Check if the user erroneously used `doc(include(...))` syntax.
1568 let literal
= it
.meta_item_list().and_then(|list
| {
1569 if list
.len() == 1 {
1570 list
[0].literal().map(|literal
| &literal
.kind
)
1576 let (path
, applicability
) = match &literal
{
1577 Some(LitKind
::Str(path
, ..)) => {
1578 (path
.to_string(), Applicability
::MachineApplicable
)
1580 _
=> (String
::from("<path>"), Applicability
::HasPlaceholders
),
1583 err
.span_suggestion(
1585 "provide a file path with `=`",
1586 format
!("include = \"{}\"", path
),
1594 let meta
= attr
::mk_list_item(Ident
::with_dummy_span(sym
::doc
), items
);
1595 *at
= ast
::Attribute
{
1596 kind
: ast
::AttrKind
::Normal(
1597 AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None }
,
1605 noop_visit_attribute(at
, self)
1609 fn visit_id(&mut self, id
: &mut ast
::NodeId
) {
1611 debug_assert_eq
!(*id
, ast
::DUMMY_NODE_ID
);
1612 *id
= self.cx
.resolver
.next_node_id()
1617 pub struct ExpansionConfig
<'feat
> {
1618 pub crate_name
: String
,
1619 pub features
: Option
<&'feat Features
>,
1620 pub recursion_limit
: Limit
,
1621 pub trace_mac
: bool
,
1622 pub should_test
: bool
, // If false, strip `#[test]` nodes
1623 pub span_debug
: bool
, // If true, use verbose debugging for `proc_macro::Span`
1624 pub proc_macro_backtrace
: bool
, // If true, show backtraces for proc-macro panics
1627 impl<'feat
> ExpansionConfig
<'feat
> {
1628 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1632 recursion_limit
: Limit
::new(1024),
1636 proc_macro_backtrace
: false,
1640 fn proc_macro_hygiene(&self) -> bool
{
1641 self.features
.map_or(false, |features
| features
.proc_macro_hygiene
)