1 use crate::ast
::{self, Block, Ident, LitKind, NodeId, PatKind, Path}
;
2 use crate::ast
::{MacStmtStyle, StmtKind, ItemKind}
;
3 use crate::attr
::{self, HasAttrs}
;
4 use crate::source_map
::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan}
;
5 use crate::config
::StripUnconfigured
;
6 use crate::ext
::base
::*;
7 use crate::ext
::derive
::{add_derived_markers, collect_derives}
;
8 use crate::ext
::hygiene
::{self, Mark, SyntaxContext}
;
9 use crate::ext
::placeholders
::{placeholder, PlaceholderExpander}
;
10 use crate::feature_gate
::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}
;
11 use crate::mut_visit
::*;
12 use crate::parse
::{DirectoryOwnership, PResult, ParseSess}
;
13 use crate::parse
::token
::{self, Token}
;
14 use crate::parse
::parser
::Parser
;
16 use crate::symbol
::Symbol
;
17 use crate::symbol
::keywords
;
18 use crate::tokenstream
::{TokenStream, TokenTree}
;
19 use crate::visit
::{self, Visitor}
;
20 use crate::util
::map_in_place
::MapInPlace
;
22 use errors
::{Applicability, FatalError}
;
23 use smallvec
::{smallvec, SmallVec}
;
24 use syntax_pos
::{Span, DUMMY_SP, FileName}
;
25 use syntax_pos
::hygiene
::ExpnFormat
;
27 use rustc_data_structures
::fx
::FxHashMap
;
28 use rustc_data_structures
::sync
::Lrc
;
30 use std
::io
::ErrorKind
;
32 use std
::ops
::DerefMut
;
34 use std
::path
::PathBuf
;
36 macro_rules
! ast_fragments
{
38 $
($Kind
:ident($AstTy
:ty
) {
40 $
(one
fn $mut_visit_ast
:ident
; fn $visit_ast
:ident
;)?
41 $
(many
fn $flat_map_ast_elt
:ident
; fn $visit_ast_elt
:ident
;)?
45 /// A fragment of AST that can be produced by a single macro expansion.
46 /// Can also serve as an input and intermediate result for macro expansion operations.
47 pub enum AstFragment
{
48 OptExpr(Option
<P
<ast
::Expr
>>),
52 /// "Discriminant" of an AST fragment.
53 #[derive(Copy, Clone, PartialEq, Eq)]
54 pub enum AstFragmentKind
{
59 impl AstFragmentKind
{
60 pub fn name(self) -> &'
static str {
62 AstFragmentKind
::OptExpr
=> "expression",
63 $
(AstFragmentKind
::$Kind
=> $kind_name
,)*
67 fn make_from
<'a
>(self, result
: Box
<dyn MacResult
+ 'a
>) -> Option
<AstFragment
> {
69 AstFragmentKind
::OptExpr
=>
70 result
.make_expr().map(Some
).map(AstFragment
::OptExpr
),
71 $
(AstFragmentKind
::$Kind
=> result
.$
make_ast().map(AstFragment
::$Kind
),)*
77 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
79 AstFragment
::OptExpr(expr
) => expr
,
80 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
84 $
(pub fn $
make_ast(self) -> $AstTy
{
86 AstFragment
::$
Kind(ast
) => ast
,
87 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
91 pub fn mut_visit_with
<F
: MutVisitor
>(&mut self, vis
: &mut F
) {
93 AstFragment
::OptExpr(opt_expr
) => {
94 visit_clobber(opt_expr
, |opt_expr
| {
95 if let Some(expr
) = opt_expr
{
96 vis
.filter_map_expr(expr
)
102 $
($
(AstFragment
::$
Kind(ast
) => vis
.$
mut_visit_ast(ast
),)*)*
103 $
($
(AstFragment
::$
Kind(ast
) =>
104 ast
.flat_map_in_place(|ast
| vis
.$
flat_map_ast_elt(ast
)),)*)*
108 pub fn visit_with
<'a
, V
: Visitor
<'a
>>(&'a
self, visitor
: &mut V
) {
110 AstFragment
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
111 AstFragment
::OptExpr(None
) => {}
112 $
($
(AstFragment
::$
Kind(ref ast
) => visitor
.$
visit_ast(ast
),)*)*
113 $
($
(AstFragment
::$
Kind(ref ast
) => for ast_elt
in &ast
[..] {
114 visitor
.$
visit_ast_elt(ast_elt
);
120 impl<'a
, 'b
> MutVisitor
for MacroExpander
<'a
, 'b
> {
121 fn filter_map_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
122 self.expand_fragment(AstFragment
::OptExpr(Some(expr
))).make_opt_expr()
124 $
($
(fn $
mut_visit_ast(&mut self, ast
: &mut $AstTy
) {
125 visit_clobber(ast
, |ast
| self.expand_fragment(AstFragment
::$
Kind(ast
)).$
make_ast());
127 $
($
(fn $
flat_map_ast_elt(&mut self, ast_elt
: <$AstTy
as IntoIterator
>::Item
) -> $AstTy
{
128 self.expand_fragment(AstFragment
::$
Kind(smallvec
![ast_elt
])).$
make_ast()
132 impl<'a
> MacResult
for crate::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
> {
133 $
(fn $
make_ast(self: Box
<crate::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
>>)
135 Some(self.make(AstFragmentKind
::$Kind
).$
make_ast())
142 Expr(P
<ast
::Expr
>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
143 Pat(P
<ast
::Pat
>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
144 Ty(P
<ast
::Ty
>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
145 Stmts(SmallVec
<[ast
::Stmt
; 1]>) {
146 "statement"; many
fn flat_map_stmt
; fn visit_stmt
; fn make_stmts
;
148 Items(SmallVec
<[P
<ast
::Item
>; 1]>) {
149 "item"; many
fn flat_map_item
; fn visit_item
; fn make_items
;
151 TraitItems(SmallVec
<[ast
::TraitItem
; 1]>) {
152 "trait item"; many
fn flat_map_trait_item
; fn visit_trait_item
; fn make_trait_items
;
154 ImplItems(SmallVec
<[ast
::ImplItem
; 1]>) {
155 "impl item"; many
fn flat_map_impl_item
; fn visit_impl_item
; fn make_impl_items
;
157 ForeignItems(SmallVec
<[ast
::ForeignItem
; 1]>) {
158 "foreign item"; many
fn flat_map_foreign_item
; fn visit_foreign_item
; fn make_foreign_items
;
162 impl AstFragmentKind
{
163 fn dummy(self, span
: Span
) -> Option
<AstFragment
> {
164 self.make_from(DummyResult
::any(span
))
167 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(self, items
: I
)
169 let mut items
= items
.into_iter();
171 AstFragmentKind
::Items
=>
172 AstFragment
::Items(items
.map(Annotatable
::expect_item
).collect()),
173 AstFragmentKind
::ImplItems
=>
174 AstFragment
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect()),
175 AstFragmentKind
::TraitItems
=>
176 AstFragment
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect()),
177 AstFragmentKind
::ForeignItems
=>
178 AstFragment
::ForeignItems(items
.map(Annotatable
::expect_foreign_item
).collect()),
179 AstFragmentKind
::Stmts
=>
180 AstFragment
::Stmts(items
.map(Annotatable
::expect_stmt
).collect()),
181 AstFragmentKind
::Expr
=> AstFragment
::Expr(
182 items
.next().expect("expected exactly one expression").expect_expr()
184 AstFragmentKind
::OptExpr
=>
185 AstFragment
::OptExpr(items
.next().map(Annotatable
::expect_expr
)),
186 AstFragmentKind
::Pat
| AstFragmentKind
::Ty
=>
187 panic
!("patterns and types aren't annotatable"),
192 fn macro_bang_format(path
: &ast
::Path
) -> ExpnFormat
{
193 // We don't want to format a path using pretty-printing,
194 // `format!("{}", path)`, because that tries to insert
195 // line-breaks and is slow.
196 let mut path_str
= String
::with_capacity(64);
197 for (i
, segment
) in path
.segments
.iter().enumerate() {
199 path_str
.push_str("::");
201 if segment
.ident
.name
!= keywords
::PathRoot
.name() {
202 path_str
.push_str(&segment
.ident
.as_str())
206 MacroBang(Symbol
::intern(&path_str
))
209 pub struct Invocation
{
210 pub kind
: InvocationKind
,
211 fragment_kind
: AstFragmentKind
,
212 pub expansion_data
: ExpansionData
,
215 pub enum InvocationKind
{
218 ident
: Option
<Ident
>,
222 attr
: Option
<ast
::Attribute
>,
225 // We temporarily report errors for attribute macros placed after derives
235 pub fn span(&self) -> Span
{
237 InvocationKind
::Bang { span, .. }
=> span
,
238 InvocationKind
::Attr { attr: Some(ref attr), .. }
=> attr
.span
,
239 InvocationKind
::Attr { attr: None, .. }
=> DUMMY_SP
,
240 InvocationKind
::Derive { ref path, .. }
=> path
.span
,
245 pub struct MacroExpander
<'a
, 'b
:'a
> {
246 pub cx
: &'a
mut ExtCtxt
<'b
>,
247 monotonic
: bool
, // cf. `cx.monotonic_expander()`
250 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
251 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
252 MacroExpander { cx: cx, monotonic: monotonic }
255 pub fn expand_crate(&mut self, mut krate
: ast
::Crate
) -> ast
::Crate
{
256 let mut module
= ModuleData
{
257 mod_path
: vec
![Ident
::from_str(&self.cx
.ecfg
.crate_name
)],
258 directory
: match self.cx
.source_map().span_to_unmapped_path(krate
.span
) {
259 FileName
::Real(path
) => path
,
260 other
=> PathBuf
::from(other
.to_string()),
263 module
.directory
.pop();
264 self.cx
.root_path
= module
.directory
.clone();
265 self.cx
.current_expansion
.module
= Rc
::new(module
);
266 self.cx
.current_expansion
.crate_span
= Some(krate
.span
);
268 let orig_mod_span
= krate
.module
.inner
;
270 let krate_item
= AstFragment
::Items(smallvec
![P(ast
::Item
{
273 node
: ast
::ItemKind
::Mod(krate
.module
),
274 ident
: keywords
::Invalid
.ident(),
275 id
: ast
::DUMMY_NODE_ID
,
276 vis
: respan(krate
.span
.shrink_to_lo(), ast
::VisibilityKind
::Public
),
280 match self.expand_fragment(krate_item
).make_items().pop().map(P
::into_inner
) {
281 Some(ast
::Item { attrs, node: ast::ItemKind::Mod(module), .. }
) => {
283 krate
.module
= module
;
286 // Resolution failed so we return an empty expansion
287 krate
.attrs
= vec
![];
288 krate
.module
= ast
::Mod
{
289 inner
: orig_mod_span
,
296 self.cx
.trace_macros_diag();
300 // Fully expand all macro invocations in this AST fragment.
301 fn expand_fragment(&mut self, input_fragment
: AstFragment
) -> AstFragment
{
302 let orig_expansion_data
= self.cx
.current_expansion
.clone();
303 self.cx
.current_expansion
.depth
= 0;
305 // Collect all macro invocations and replace them with placeholders.
306 let (mut fragment_with_placeholders
, mut invocations
)
307 = self.collect_invocations(input_fragment
, &[]);
309 // Optimization: if we resolve all imports now,
310 // we'll be able to immediately resolve most of imported macros.
311 self.resolve_imports();
313 // Resolve paths in all invocations and produce output expanded fragments for them, but
314 // do not insert them into our input AST fragment yet, only store in `expanded_fragments`.
315 // The output fragments also go through expansion recursively until no invocations are left.
316 // Unresolved macros produce dummy outputs as a recovery measure.
317 invocations
.reverse();
318 let mut expanded_fragments
= Vec
::new();
319 let mut derives
: FxHashMap
<Mark
, Vec
<_
>> = FxHashMap
::default();
320 let mut undetermined_invocations
= Vec
::new();
321 let (mut progress
, mut force
) = (false, !self.monotonic
);
323 let invoc
= if let Some(invoc
) = invocations
.pop() {
326 self.resolve_imports();
327 if undetermined_invocations
.is_empty() { break }
328 invocations
= mem
::replace(&mut undetermined_invocations
, Vec
::new());
329 force
= !mem
::replace(&mut progress
, false);
334 if self.monotonic { invoc.expansion_data.mark }
else { orig_expansion_data.mark }
;
335 let ext
= match self.cx
.resolver
.resolve_macro_invocation(&invoc
, scope
, force
) {
336 Ok(ext
) => Some(ext
),
337 Err(Determinacy
::Determined
) => None
,
338 Err(Determinacy
::Undetermined
) => {
339 undetermined_invocations
.push(invoc
);
345 let ExpansionData { depth, mark, .. }
= invoc
.expansion_data
;
346 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
348 self.cx
.current_expansion
.mark
= scope
;
349 // FIXME(jseyfried): Refactor out the following logic
350 let (expanded_fragment
, new_invocations
) = if let Some(ext
) = ext
{
351 if let Some(ext
) = ext
{
352 let (invoc_fragment_kind
, invoc_span
) = (invoc
.fragment_kind
, invoc
.span());
353 let fragment
= self.expand_invoc(invoc
, &*ext
).unwrap_or_else(|| {
354 invoc_fragment_kind
.dummy(invoc_span
).unwrap()
356 self.collect_invocations(fragment
, &[])
357 } else if let InvocationKind
::Attr { attr: None, traits, item, .. }
= invoc
.kind
{
358 if !item
.derive_allowed() {
359 let attr
= attr
::find_by_name(item
.attrs(), "derive")
360 .expect("`derive` attribute should exist");
361 let span
= attr
.span
;
362 let mut err
= self.cx
.mut_span_err(span
,
363 "`derive` may only be applied to \
364 structs, enums and unions");
365 if let ast
::AttrStyle
::Inner
= attr
.style
{
366 let trait_list
= traits
.iter()
367 .map(|t
| t
.to_string()).collect
::<Vec
<_
>>();
368 let suggestion
= format
!("#[derive({})]", trait_list
.join(", "));
370 span
, "try an outer attribute", suggestion
,
371 // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
372 Applicability
::MaybeIncorrect
378 let mut item
= self.fully_configure(item
);
379 item
.visit_attrs(|attrs
| attrs
.retain(|a
| a
.path
!= "derive"));
380 let mut item_with_markers
= item
.clone();
381 add_derived_markers(&mut self.cx
, item
.span(), &traits
, &mut item_with_markers
);
382 let derives
= derives
.entry(invoc
.expansion_data
.mark
).or_default();
384 derives
.reserve(traits
.len());
385 invocations
.reserve(traits
.len());
386 for path
in &traits
{
387 let mark
= Mark
::fresh(self.cx
.current_expansion
.mark
);
389 let item
= match self.cx
.resolver
.resolve_macro_path(
390 path
, MacroKind
::Derive
, Mark
::root(), Vec
::new(), false) {
391 Ok(ext
) => match *ext
{
392 BuiltinDerive(..) => item_with_markers
.clone(),
397 invocations
.push(Invocation
{
398 kind
: InvocationKind
::Derive { path: path.clone(), item: item }
,
399 fragment_kind
: invoc
.fragment_kind
,
400 expansion_data
: ExpansionData
{
402 ..invoc
.expansion_data
.clone()
406 let fragment
= invoc
.fragment_kind
407 .expect_from_annotatables(::std
::iter
::once(item_with_markers
));
408 self.collect_invocations(fragment
, derives
)
413 self.collect_invocations(invoc
.fragment_kind
.dummy(invoc
.span()).unwrap(), &[])
416 if expanded_fragments
.len() < depth
{
417 expanded_fragments
.push(Vec
::new());
419 expanded_fragments
[depth
- 1].push((mark
, expanded_fragment
));
420 if !self.cx
.ecfg
.single_step
{
421 invocations
.extend(new_invocations
.into_iter().rev());
425 self.cx
.current_expansion
= orig_expansion_data
;
427 // Finally incorporate all the expanded macros into the input AST fragment.
428 let mut placeholder_expander
= PlaceholderExpander
::new(self.cx
, self.monotonic
);
429 while let Some(expanded_fragments
) = expanded_fragments
.pop() {
430 for (mark
, expanded_fragment
) in expanded_fragments
.into_iter().rev() {
431 let derives
= derives
.remove(&mark
).unwrap_or_else(Vec
::new
);
432 placeholder_expander
.add(NodeId
::placeholder_from_mark(mark
),
433 expanded_fragment
, derives
);
436 fragment_with_placeholders
.mut_visit_with(&mut placeholder_expander
);
437 fragment_with_placeholders
440 fn resolve_imports(&mut self) {
442 self.cx
.resolver
.resolve_imports();
446 /// Collects all macro invocations reachable at this time in this AST fragment, and replace
447 /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
448 /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
449 /// prepares data for resolving paths of macro invocations.
450 fn collect_invocations(&mut self, mut fragment
: AstFragment
, derives
: &[Mark
])
451 -> (AstFragment
, Vec
<Invocation
>) {
452 // Resolve `$crate`s in the fragment for pretty-printing.
453 self.cx
.resolver
.resolve_dollar_crates(&fragment
);
456 let mut collector
= InvocationCollector
{
457 cfg
: StripUnconfigured
{
458 sess
: self.cx
.parse_sess
,
459 features
: self.cx
.ecfg
.features
,
462 invocations
: Vec
::new(),
463 monotonic
: self.monotonic
,
465 fragment
.mut_visit_with(&mut collector
);
466 collector
.invocations
470 self.cx
.resolver
.visit_ast_fragment_with_placeholders(
471 self.cx
.current_expansion
.mark
, &fragment
, derives
);
474 (fragment
, invocations
)
477 fn fully_configure(&mut self, item
: Annotatable
) -> Annotatable
{
478 let mut cfg
= StripUnconfigured
{
479 sess
: self.cx
.parse_sess
,
480 features
: self.cx
.ecfg
.features
,
482 // Since the item itself has already been configured by the InvocationCollector,
483 // we know that fold result vector will contain exactly one element
485 Annotatable
::Item(item
) => {
486 Annotatable
::Item(cfg
.flat_map_item(item
).pop().unwrap())
488 Annotatable
::TraitItem(item
) => {
489 Annotatable
::TraitItem(
490 item
.map(|item
| cfg
.flat_map_trait_item(item
).pop().unwrap()))
492 Annotatable
::ImplItem(item
) => {
493 Annotatable
::ImplItem(item
.map(|item
| cfg
.flat_map_impl_item(item
).pop().unwrap()))
495 Annotatable
::ForeignItem(item
) => {
496 Annotatable
::ForeignItem(
497 item
.map(|item
| cfg
.flat_map_foreign_item(item
).pop().unwrap())
500 Annotatable
::Stmt(stmt
) => {
501 Annotatable
::Stmt(stmt
.map(|stmt
| cfg
.flat_map_stmt(stmt
).pop().unwrap()))
503 Annotatable
::Expr(mut expr
) => {
504 Annotatable
::Expr({ cfg.visit_expr(&mut expr); expr }
)
509 fn expand_invoc(&mut self, invoc
: Invocation
, ext
: &SyntaxExtension
) -> Option
<AstFragment
> {
510 if invoc
.fragment_kind
== AstFragmentKind
::ForeignItems
&&
511 !self.cx
.ecfg
.macros_in_extern_enabled() {
512 if let SyntaxExtension
::NonMacroAttr { .. }
= *ext {}
else {
513 emit_feature_err(&self.cx
.parse_sess
, "macros_in_extern",
514 invoc
.span(), GateIssue
::Language
,
515 "macro invocations in `extern {}` blocks are experimental");
519 let result
= match invoc
.kind
{
520 InvocationKind
::Bang { .. }
=> self.expand_bang_invoc(invoc
, ext
)?
,
521 InvocationKind
::Attr { .. }
=> self.expand_attr_invoc(invoc
, ext
)?
,
522 InvocationKind
::Derive { .. }
=> self.expand_derive_invoc(invoc
, ext
)?
,
525 if self.cx
.current_expansion
.depth
> self.cx
.ecfg
.recursion_limit
{
526 let info
= self.cx
.current_expansion
.mark
.expn_info().unwrap();
527 let suggested_limit
= self.cx
.ecfg
.recursion_limit
* 2;
528 let mut err
= self.cx
.struct_span_err(info
.call_site
,
529 &format
!("recursion limit reached while expanding the macro `{}`",
530 info
.format
.name()));
532 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
535 self.cx
.trace_macros_diag();
542 fn expand_attr_invoc(&mut self,
544 ext
: &SyntaxExtension
)
545 -> Option
<AstFragment
> {
546 let (attr
, mut item
) = match invoc
.kind
{
547 InvocationKind
::Attr { attr, item, .. }
=> (attr?
, item
),
551 if let NonMacroAttr { mark_used: false }
= *ext {}
else {
552 // Macro attrs are always used when expanded,
553 // non-macro attrs are considered used when the field says so.
554 attr
::mark_used(&attr
);
556 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
557 call_site
: attr
.span
,
559 format
: MacroAttribute(Symbol
::intern(&attr
.path
.to_string())),
560 allow_internal_unstable
: None
,
561 allow_internal_unsafe
: false,
562 local_inner_macros
: false,
563 edition
: ext
.edition(),
567 NonMacroAttr { .. }
=> {
568 attr
::mark_known(&attr
);
569 item
.visit_attrs(|attrs
| attrs
.push(attr
));
570 Some(invoc
.fragment_kind
.expect_from_annotatables(iter
::once(item
)))
572 MultiModifier(ref mac
) => {
573 let meta
= attr
.parse_meta(self.cx
.parse_sess
)
574 .map_err(|mut e
| { e.emit(); }
).ok()?
;
575 let item
= mac
.expand(self.cx
, attr
.span
, &meta
, item
);
576 Some(invoc
.fragment_kind
.expect_from_annotatables(item
))
578 MultiDecorator(ref mac
) => {
579 let mut items
= Vec
::new();
580 let meta
= attr
.parse_meta(self.cx
.parse_sess
)
581 .expect("derive meta should already have been parsed");
582 mac
.expand(self.cx
, attr
.span
, &meta
, &item
, &mut |item
| items
.push(item
));
584 Some(invoc
.fragment_kind
.expect_from_annotatables(items
))
586 AttrProcMacro(ref mac
, ..) => {
587 self.gate_proc_macro_attr_item(attr
.span
, &item
);
588 let item_tok
= TokenTree
::Token(DUMMY_SP
, Token
::Interpolated(Lrc
::new(match item
{
589 Annotatable
::Item(item
) => token
::NtItem(item
),
590 Annotatable
::TraitItem(item
) => token
::NtTraitItem(item
.into_inner()),
591 Annotatable
::ImplItem(item
) => token
::NtImplItem(item
.into_inner()),
592 Annotatable
::ForeignItem(item
) => token
::NtForeignItem(item
.into_inner()),
593 Annotatable
::Stmt(stmt
) => token
::NtStmt(stmt
.into_inner()),
594 Annotatable
::Expr(expr
) => token
::NtExpr(expr
),
596 let input
= self.extract_proc_macro_attr_input(attr
.tokens
, attr
.span
);
597 let tok_result
= mac
.expand(self.cx
, attr
.span
, input
, item_tok
);
598 let res
= self.parse_ast_fragment(tok_result
, invoc
.fragment_kind
,
599 &attr
.path
, attr
.span
);
600 self.gate_proc_macro_expansion(attr
.span
, &res
);
603 ProcMacroDerive(..) | BuiltinDerive(..) => {
604 self.cx
.span_err(attr
.span
, &format
!("`{}` is a derive macro", attr
.path
));
605 self.cx
.trace_macros_diag();
606 invoc
.fragment_kind
.dummy(attr
.span
)
609 let msg
= &format
!("macro `{}` may not be used in attributes", attr
.path
);
610 self.cx
.span_err(attr
.span
, msg
);
611 self.cx
.trace_macros_diag();
612 invoc
.fragment_kind
.dummy(attr
.span
)
617 fn extract_proc_macro_attr_input(&self, tokens
: TokenStream
, span
: Span
) -> TokenStream
{
618 let mut trees
= tokens
.trees();
620 Some(TokenTree
::Delimited(_
, _
, tts
)) => {
621 if trees
.next().is_none() {
625 Some(TokenTree
::Token(..)) => {}
626 None
=> return TokenStream
::empty(),
628 self.cx
.span_err(span
, "custom attribute invocations must be \
629 of the form #[foo] or #[foo(..)], the macro name must only be \
630 followed by a delimiter token");
634 fn gate_proc_macro_attr_item(&self, span
: Span
, item
: &Annotatable
) {
635 let (kind
, gate
) = match *item
{
636 Annotatable
::Item(ref item
) => {
638 ItemKind
::Mod(_
) if self.cx
.ecfg
.proc_macro_hygiene() => return,
639 ItemKind
::Mod(_
) => ("modules", "proc_macro_hygiene"),
643 Annotatable
::TraitItem(_
) => return,
644 Annotatable
::ImplItem(_
) => return,
645 Annotatable
::ForeignItem(_
) => return,
646 Annotatable
::Stmt(_
) |
647 Annotatable
::Expr(_
) if self.cx
.ecfg
.proc_macro_hygiene() => return,
648 Annotatable
::Stmt(_
) => ("statements", "proc_macro_hygiene"),
649 Annotatable
::Expr(_
) => ("expressions", "proc_macro_hygiene"),
656 &format
!("custom attributes cannot be applied to {}", kind
),
660 fn gate_proc_macro_expansion(&self, span
: Span
, fragment
: &Option
<AstFragment
>) {
661 if self.cx
.ecfg
.proc_macro_hygiene() {
664 let fragment
= match fragment
{
665 Some(fragment
) => fragment
,
669 fragment
.visit_with(&mut DisallowMacros
{
671 parse_sess
: self.cx
.parse_sess
,
674 struct DisallowMacros
<'a
> {
676 parse_sess
: &'a ParseSess
,
679 impl<'ast
, 'a
> Visitor
<'ast
> for DisallowMacros
<'a
> {
680 fn visit_item(&mut self, i
: &'ast ast
::Item
) {
681 if let ast
::ItemKind
::MacroDef(_
) = i
.node
{
684 "proc_macro_hygiene",
687 "procedural macros cannot expand to macro definitions",
690 visit
::walk_item(self, i
);
693 fn visit_mac(&mut self, _mac
: &'ast ast
::Mac
) {
699 /// Expand a macro invocation. Returns the resulting expanded AST fragment.
700 fn expand_bang_invoc(&mut self,
702 ext
: &SyntaxExtension
)
703 -> Option
<AstFragment
> {
704 let (mark
, kind
) = (invoc
.expansion_data
.mark
, invoc
.fragment_kind
);
705 let (mac
, ident
, span
) = match invoc
.kind
{
706 InvocationKind
::Bang { mac, ident, span }
=> (mac
, ident
, span
),
709 let path
= &mac
.node
.path
;
711 let ident
= ident
.unwrap_or_else(|| keywords
::Invalid
.ident());
712 let validate_and_set_expn_info
= |this
: &mut Self, // arg instead of capture
713 def_site_span
: Option
<Span
>,
714 allow_internal_unstable
,
715 allow_internal_unsafe
,
717 // can't infer this type
718 unstable_feature
: Option
<(Symbol
, u32)>,
721 // feature-gate the macro invocation
722 if let Some((feature
, issue
)) = unstable_feature
{
723 let crate_span
= this
.cx
.current_expansion
.crate_span
.unwrap();
724 // don't stability-check macros in the same crate
725 // (the only time this is null is for syntax extensions registered as macros)
726 if def_site_span
.map_or(false, |def_span
| !crate_span
.contains(def_span
))
727 && !span
.allows_unstable(&feature
.as_str())
728 && this
.cx
.ecfg
.features
.map_or(true, |feats
| {
729 // macro features will count as lib features
730 !feats
.declared_lib_features
.iter().any(|&(feat
, _
)| feat
== feature
)
732 let explain
= format
!("macro {}! is unstable", path
);
733 emit_feature_err(this
.cx
.parse_sess
, &*feature
.as_str(), span
,
734 GateIssue
::Library(Some(issue
)), &explain
);
735 this
.cx
.trace_macros_diag();
739 if ident
.name
!= keywords
::Invalid
.name() {
740 let msg
= format
!("macro {}! expects no ident argument, given '{}'", path
, ident
);
741 this
.cx
.span_err(path
.span
, &msg
);
742 this
.cx
.trace_macros_diag();
743 return Err(kind
.dummy(span
));
745 mark
.set_expn_info(ExpnInfo
{
747 def_site
: def_site_span
,
748 format
: macro_bang_format(path
),
749 allow_internal_unstable
,
750 allow_internal_unsafe
,
757 let opt_expanded
= match *ext
{
758 DeclMacro { ref expander, def_info, edition, .. }
=> {
759 if let Err(dummy_span
) = validate_and_set_expn_info(self, def_info
.map(|(_
, s
)| s
),
760 None
, false, false, None
,
764 kind
.make_from(expander
.expand(self.cx
, span
, mac
.node
.stream(), None
))
771 ref allow_internal_unstable
,
772 allow_internal_unsafe
,
777 if let Err(dummy_span
) = validate_and_set_expn_info(self, def_info
.map(|(_
, s
)| s
),
778 allow_internal_unstable
.clone(),
779 allow_internal_unsafe
,
785 kind
.make_from(expander
.expand(
789 def_info
.map(|(_
, s
)| s
),
794 IdentTT { ref expander, span: tt_span, ref allow_internal_unstable }
=> {
795 if ident
.name
== keywords
::Invalid
.name() {
796 self.cx
.span_err(path
.span
,
797 &format
!("macro {}! expects an ident argument", path
));
798 self.cx
.trace_macros_diag();
801 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
804 format
: macro_bang_format(path
),
805 allow_internal_unstable
: allow_internal_unstable
.clone(),
806 allow_internal_unsafe
: false,
807 local_inner_macros
: false,
808 edition
: hygiene
::default_edition(),
811 let input
: Vec
<_
> = mac
.node
.stream().into_trees().collect();
812 kind
.make_from(expander
.expand(self.cx
, span
, ident
, input
))
816 MultiDecorator(..) | MultiModifier(..) |
817 AttrProcMacro(..) | SyntaxExtension
::NonMacroAttr { .. }
=> {
818 self.cx
.span_err(path
.span
,
819 &format
!("`{}` can only be used in attributes", path
));
820 self.cx
.trace_macros_diag();
824 ProcMacroDerive(..) | BuiltinDerive(..) => {
825 self.cx
.span_err(path
.span
, &format
!("`{}` is a derive macro", path
));
826 self.cx
.trace_macros_diag();
830 SyntaxExtension
::ProcMacro { ref expander, ref allow_internal_unstable, edition }
=> {
831 if ident
.name
!= keywords
::Invalid
.name() {
833 format
!("macro {}! expects no ident argument, given '{}'", path
, ident
);
834 self.cx
.span_err(path
.span
, &msg
);
835 self.cx
.trace_macros_diag();
838 self.gate_proc_macro_expansion_kind(span
, kind
);
839 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
841 // FIXME procedural macros do not have proper span info
842 // yet, when they do, we should use it here.
844 format
: macro_bang_format(path
),
845 // FIXME probably want to follow macro_rules macros here.
846 allow_internal_unstable
: allow_internal_unstable
.clone(),
847 allow_internal_unsafe
: false,
848 local_inner_macros
: false,
852 let tok_result
= expander
.expand(self.cx
, span
, mac
.node
.stream());
853 let result
= self.parse_ast_fragment(tok_result
, kind
, path
, span
);
854 self.gate_proc_macro_expansion(span
, &result
);
860 if opt_expanded
.is_some() {
863 let msg
= format
!("non-{kind} macro in {kind} position: {name}",
864 name
= path
.segments
[0].ident
.name
, kind
= kind
.name());
865 self.cx
.span_err(path
.span
, &msg
);
866 self.cx
.trace_macros_diag();
871 fn gate_proc_macro_expansion_kind(&self, span
: Span
, kind
: AstFragmentKind
) {
872 let kind
= match kind
{
873 AstFragmentKind
::Expr
=> "expressions",
874 AstFragmentKind
::OptExpr
=> "expressions",
875 AstFragmentKind
::Pat
=> "patterns",
876 AstFragmentKind
::Ty
=> "types",
877 AstFragmentKind
::Stmts
=> "statements",
878 AstFragmentKind
::Items
=> return,
879 AstFragmentKind
::TraitItems
=> return,
880 AstFragmentKind
::ImplItems
=> return,
881 AstFragmentKind
::ForeignItems
=> return,
883 if self.cx
.ecfg
.proc_macro_hygiene() {
888 "proc_macro_hygiene",
891 &format
!("procedural macros cannot be expanded to {}", kind
),
895 /// Expand a derive invocation. Returns the resulting expanded AST fragment.
896 fn expand_derive_invoc(&mut self,
898 ext
: &SyntaxExtension
)
899 -> Option
<AstFragment
> {
900 let (path
, item
) = match invoc
.kind
{
901 InvocationKind
::Derive { path, item }
=> (path
, item
),
904 if !item
.derive_allowed() {
908 let pretty_name
= Symbol
::intern(&format
!("derive({})", path
));
909 let span
= path
.span
;
910 let attr
= ast
::Attribute
{
912 tokens
: TokenStream
::empty(),
914 id
: ast
::AttrId(0), style
: ast
::AttrStyle
::Outer
, is_sugared_doc
: false,
917 let mut expn_info
= ExpnInfo
{
920 format
: MacroAttribute(pretty_name
),
921 allow_internal_unstable
: None
,
922 allow_internal_unsafe
: false,
923 local_inner_macros
: false,
924 edition
: ext
.edition(),
928 ProcMacroDerive(ref ext
, ..) => {
929 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
930 let span
= span
.with_ctxt(self.cx
.backtrace());
931 let dummy
= ast
::MetaItem
{ // FIXME(jseyfried) avoid this
932 ident
: Path
::from_ident(keywords
::Invalid
.ident()),
934 node
: ast
::MetaItemKind
::Word
,
936 let items
= ext
.expand(self.cx
, span
, &dummy
, item
);
937 Some(invoc
.fragment_kind
.expect_from_annotatables(items
))
939 BuiltinDerive(func
) => {
940 expn_info
.allow_internal_unstable
= Some(vec
![
941 Symbol
::intern("rustc_attrs"),
942 Symbol
::intern("derive_clone_copy"),
943 Symbol
::intern("derive_eq"),
944 Symbol
::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
946 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
947 let span
= span
.with_ctxt(self.cx
.backtrace());
948 let mut items
= Vec
::new();
949 func(self.cx
, span
, &attr
.meta()?
, &item
, &mut |a
| items
.push(a
));
950 Some(invoc
.fragment_kind
.expect_from_annotatables(items
))
953 let msg
= &format
!("macro `{}` may not be used for derive attributes", attr
.path
);
954 self.cx
.span_err(span
, msg
);
955 self.cx
.trace_macros_diag();
956 invoc
.fragment_kind
.dummy(span
)
961 fn parse_ast_fragment(&mut self,
963 kind
: AstFragmentKind
,
966 -> Option
<AstFragment
> {
967 let mut parser
= self.cx
.new_parser_from_tts(&toks
.into_trees().collect
::<Vec
<_
>>());
968 match parser
.parse_ast_fragment(kind
, false) {
970 parser
.ensure_complete_parse(path
, kind
.name(), span
);
976 self.cx
.trace_macros_diag();
983 impl<'a
> Parser
<'a
> {
984 pub fn parse_ast_fragment(&mut self, kind
: AstFragmentKind
, macro_legacy_warnings
: bool
)
985 -> PResult
<'a
, AstFragment
> {
987 AstFragmentKind
::Items
=> {
988 let mut items
= SmallVec
::new();
989 while let Some(item
) = self.parse_item()?
{
992 AstFragment
::Items(items
)
994 AstFragmentKind
::TraitItems
=> {
995 let mut items
= SmallVec
::new();
996 while self.token
!= token
::Eof
{
997 items
.push(self.parse_trait_item(&mut false)?
);
999 AstFragment
::TraitItems(items
)
1001 AstFragmentKind
::ImplItems
=> {
1002 let mut items
= SmallVec
::new();
1003 while self.token
!= token
::Eof
{
1004 items
.push(self.parse_impl_item(&mut false)?
);
1006 AstFragment
::ImplItems(items
)
1008 AstFragmentKind
::ForeignItems
=> {
1009 let mut items
= SmallVec
::new();
1010 while self.token
!= token
::Eof
{
1011 items
.push(self.parse_foreign_item()?
);
1013 AstFragment
::ForeignItems(items
)
1015 AstFragmentKind
::Stmts
=> {
1016 let mut stmts
= SmallVec
::new();
1017 while self.token
!= token
::Eof
&&
1018 // won't make progress on a `}`
1019 self.token
!= token
::CloseDelim(token
::Brace
) {
1020 if let Some(stmt
) = self.parse_full_stmt(macro_legacy_warnings
)?
{
1024 AstFragment
::Stmts(stmts
)
1026 AstFragmentKind
::Expr
=> AstFragment
::Expr(self.parse_expr()?
),
1027 AstFragmentKind
::OptExpr
=> {
1028 if self.token
!= token
::Eof
{
1029 AstFragment
::OptExpr(Some(self.parse_expr()?
))
1031 AstFragment
::OptExpr(None
)
1034 AstFragmentKind
::Ty
=> AstFragment
::Ty(self.parse_ty()?
),
1035 AstFragmentKind
::Pat
=> AstFragment
::Pat(self.parse_pat(None
)?
),
1039 pub fn ensure_complete_parse(&mut self, macro_path
: &Path
, kind_name
: &str, span
: Span
) {
1040 if self.token
!= token
::Eof
{
1041 let msg
= format
!("macro expansion ignores token `{}` and any following",
1042 self.this_token_to_string());
1043 // Avoid emitting backtrace info twice.
1044 let def_site_span
= self.span
.with_ctxt(SyntaxContext
::empty());
1045 let mut err
= self.diagnostic().struct_span_err(def_site_span
, &msg
);
1046 err
.span_label(span
, "caused by the macro expansion here");
1048 "the usage of `{}!` is likely invalid in {} context",
1053 let semi_span
= self.sess
.source_map().next_point(span
);
1055 let semi_full_span
= semi_span
.to(self.sess
.source_map().next_point(semi_span
));
1056 match self.sess
.source_map().span_to_snippet(semi_full_span
) {
1057 Ok(ref snippet
) if &snippet
[..] != ";" && kind_name
== "expression" => {
1058 err
.span_suggestion(
1060 "you might be missing a semicolon here",
1062 Applicability
::MaybeIncorrect
,
1072 struct InvocationCollector
<'a
, 'b
: 'a
> {
1073 cx
: &'a
mut ExtCtxt
<'b
>,
1074 cfg
: StripUnconfigured
<'a
>,
1075 invocations
: Vec
<Invocation
>,
1079 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
1080 fn collect(&mut self, fragment_kind
: AstFragmentKind
, kind
: InvocationKind
) -> AstFragment
{
1081 let mark
= Mark
::fresh(self.cx
.current_expansion
.mark
);
1082 self.invocations
.push(Invocation
{
1085 expansion_data
: ExpansionData
{
1087 depth
: self.cx
.current_expansion
.depth
+ 1,
1088 ..self.cx
.current_expansion
.clone()
1091 placeholder(fragment_kind
, NodeId
::placeholder_from_mark(mark
))
1094 fn collect_bang(&mut self, mac
: ast
::Mac
, span
: Span
, kind
: AstFragmentKind
) -> AstFragment
{
1095 self.collect(kind
, InvocationKind
::Bang { mac: mac, ident: None, span: span }
)
1098 fn collect_attr(&mut self,
1099 attr
: Option
<ast
::Attribute
>,
1102 kind
: AstFragmentKind
,
1105 self.collect(kind
, InvocationKind
::Attr { attr, traits, item, after_derive }
)
1108 fn find_attr_invoc(&self, attrs
: &mut Vec
<ast
::Attribute
>, after_derive
: &mut bool
)
1109 -> Option
<ast
::Attribute
> {
1110 let attr
= attrs
.iter()
1112 if a
.path
== "derive" {
1113 *after_derive
= true;
1115 !attr
::is_known(a
) && !is_builtin_attr(a
)
1117 .map(|i
| attrs
.remove(i
));
1118 if let Some(attr
) = &attr
{
1119 if !self.cx
.ecfg
.enable_custom_inner_attributes() &&
1120 attr
.style
== ast
::AttrStyle
::Inner
&& attr
.path
!= "test" {
1121 emit_feature_err(&self.cx
.parse_sess
, "custom_inner_attributes",
1122 attr
.span
, GateIssue
::Language
,
1123 "non-builtin inner attributes are unstable");
1129 /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
1130 fn classify_item
<T
>(&mut self, item
: &mut T
)
1131 -> (Option
<ast
::Attribute
>, Vec
<Path
>, /* after_derive */ bool
)
1134 let (mut attr
, mut traits
, mut after_derive
) = (None
, Vec
::new(), false);
1136 item
.visit_attrs(|mut attrs
| {
1137 attr
= self.find_attr_invoc(&mut attrs
, &mut after_derive
);
1138 traits
= collect_derives(&mut self.cx
, &mut attrs
);
1141 (attr
, traits
, after_derive
)
1144 /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
1145 /// to the unused-attributes lint (making it an error on statements and expressions
1146 /// is a breaking change)
1147 fn classify_nonitem
<T
: HasAttrs
>(&mut self, nonitem
: &mut T
)
1148 -> (Option
<ast
::Attribute
>, /* after_derive */ bool
) {
1149 let (mut attr
, mut after_derive
) = (None
, false);
1151 nonitem
.visit_attrs(|mut attrs
| {
1152 attr
= self.find_attr_invoc(&mut attrs
, &mut after_derive
);
1155 (attr
, after_derive
)
1158 fn configure
<T
: HasAttrs
>(&mut self, node
: T
) -> Option
<T
> {
1159 self.cfg
.configure(node
)
1162 // Detect use of feature-gated or invalid attributes on macro invocations
1163 // since they will not be detected after macro expansion.
1164 fn check_attributes(&mut self, attrs
: &[ast
::Attribute
]) {
1165 let features
= self.cx
.ecfg
.features
.unwrap();
1166 for attr
in attrs
.iter() {
1167 self.check_attribute_inner(attr
, features
);
1169 // macros are expanded before any lint passes so this warning has to be hardcoded
1170 if attr
.path
== "derive" {
1171 self.cx
.struct_span_warn(attr
.span
, "`#[derive]` does nothing on macro invocations")
1172 .note("this may become a hard error in a future release")
1178 fn check_attribute(&mut self, at
: &ast
::Attribute
) {
1179 let features
= self.cx
.ecfg
.features
.unwrap();
1180 self.check_attribute_inner(at
, features
);
1183 fn check_attribute_inner(&mut self, at
: &ast
::Attribute
, features
: &Features
) {
1184 feature_gate
::check_attribute(at
, self.cx
.parse_sess
, features
);
1188 impl<'a
, 'b
> MutVisitor
for InvocationCollector
<'a
, 'b
> {
1189 fn visit_expr(&mut self, expr
: &mut P
<ast
::Expr
>) {
1190 self.cfg
.configure_expr(expr
);
1191 visit_clobber(expr
.deref_mut(), |mut expr
| {
1192 self.cfg
.configure_expr_kind(&mut expr
.node
);
1194 // ignore derives so they remain unused
1195 let (attr
, after_derive
) = self.classify_nonitem(&mut expr
);
1198 // Collect the invoc regardless of whether or not attributes are permitted here
1199 // expansion will eat the attribute so it won't error later.
1200 attr
.as_ref().map(|a
| self.cfg
.maybe_emit_expr_attr_err(a
));
1202 // AstFragmentKind::Expr requires the macro to emit an expression.
1203 return self.collect_attr(attr
, vec
![], Annotatable
::Expr(P(expr
)),
1204 AstFragmentKind
::Expr
, after_derive
)
1209 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
1210 self.check_attributes(&expr
.attrs
);
1211 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::Expr
)
1215 noop_visit_expr(&mut expr
, self);
1221 fn filter_map_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
1222 let expr
= configure
!(self, expr
);
1223 expr
.filter_map(|mut expr
| {
1224 self.cfg
.configure_expr_kind(&mut expr
.node
);
1226 // Ignore derives so they remain unused.
1227 let (attr
, after_derive
) = self.classify_nonitem(&mut expr
);
1230 attr
.as_ref().map(|a
| self.cfg
.maybe_emit_expr_attr_err(a
));
1232 return self.collect_attr(attr
, vec
![], Annotatable
::Expr(P(expr
)),
1233 AstFragmentKind
::OptExpr
, after_derive
)
1235 .map(|expr
| expr
.into_inner())
1238 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
1239 self.check_attributes(&expr
.attrs
);
1240 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::OptExpr
)
1242 .map(|expr
| expr
.into_inner())
1244 Some({ noop_visit_expr(&mut expr, self); expr }
)
1249 fn visit_pat(&mut self, pat
: &mut P
<ast
::Pat
>) {
1250 self.cfg
.configure_pat(pat
);
1252 PatKind
::Mac(_
) => {}
1253 _
=> return noop_visit_pat(pat
, self),
1256 visit_clobber(pat
, |mut pat
| {
1257 match mem
::replace(&mut pat
.node
, PatKind
::Wild
) {
1258 PatKind
::Mac(mac
) =>
1259 self.collect_bang(mac
, pat
.span
, AstFragmentKind
::Pat
).make_pat(),
1260 _
=> unreachable
!(),
1265 fn flat_map_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVec
<[ast
::Stmt
; 1]> {
1266 let mut stmt
= configure
!(self, stmt
);
1268 // we'll expand attributes on expressions separately
1269 if !stmt
.is_expr() {
1270 let (attr
, derives
, after_derive
) = if stmt
.is_item() {
1271 self.classify_item(&mut stmt
)
1273 // ignore derives on non-item statements so it falls through
1274 // to the unused-attributes lint
1275 let (attr
, after_derive
) = self.classify_nonitem(&mut stmt
);
1276 (attr
, vec
![], after_derive
)
1279 if attr
.is_some() || !derives
.is_empty() {
1280 return self.collect_attr(attr
, derives
, Annotatable
::Stmt(P(stmt
)),
1281 AstFragmentKind
::Stmts
, after_derive
).make_stmts();
1285 if let StmtKind
::Mac(mac
) = stmt
.node
{
1286 let (mac
, style
, attrs
) = mac
.into_inner();
1287 self.check_attributes(&attrs
);
1288 let mut placeholder
= self.collect_bang(mac
, stmt
.span
, AstFragmentKind
::Stmts
)
1291 // If this is a macro invocation with a semicolon, then apply that
1292 // semicolon to the final statement produced by expansion.
1293 if style
== MacStmtStyle
::Semicolon
{
1294 if let Some(stmt
) = placeholder
.pop() {
1295 placeholder
.push(stmt
.add_trailing_semicolon());
1302 // The placeholder expander gives ids to statements, so we avoid folding the id here.
1303 let ast
::Stmt { id, node, span }
= stmt
;
1304 noop_flat_map_stmt_kind(node
, self).into_iter().map(|node
| {
1305 ast
::Stmt { id, node, span }
1310 fn visit_block(&mut self, block
: &mut P
<Block
>) {
1311 let old_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
1312 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::UnownedViaBlock
;
1313 noop_visit_block(block
, self);
1314 self.cx
.current_expansion
.directory_ownership
= old_directory_ownership
;
1317 fn flat_map_item(&mut self, item
: P
<ast
::Item
>) -> SmallVec
<[P
<ast
::Item
>; 1]> {
1318 let mut item
= configure
!(self, item
);
1320 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1321 if attr
.is_some() || !traits
.is_empty() {
1322 return self.collect_attr(attr
, traits
, Annotatable
::Item(item
),
1323 AstFragmentKind
::Items
, after_derive
).make_items();
1327 ast
::ItemKind
::Mac(..) => {
1328 self.check_attributes(&item
.attrs
);
1329 item
.and_then(|item
| match item
.node
{
1330 ItemKind
::Mac(mac
) => {
1331 self.collect(AstFragmentKind
::Items
, InvocationKind
::Bang
{
1333 ident
: Some(item
.ident
),
1337 _
=> unreachable
!(),
1340 ast
::ItemKind
::Mod(ast
::Mod { inner, .. }
) => {
1341 if item
.ident
== keywords
::Invalid
.ident() {
1342 return noop_flat_map_item(item
, self);
1345 let orig_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
1346 let mut module
= (*self.cx
.current_expansion
.module
).clone();
1347 module
.mod_path
.push(item
.ident
);
1349 // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
1350 // In the non-inline case, `inner` is never the dummy span (cf. `parse_item_mod`).
1351 // Thus, if `inner` is the dummy span, we know the module is inline.
1352 let inline_module
= item
.span
.contains(inner
) || inner
.is_dummy();
1355 if let Some(path
) = attr
::first_attr_value_str_by_name(&item
.attrs
, "path") {
1356 self.cx
.current_expansion
.directory_ownership
=
1357 DirectoryOwnership
::Owned { relative: None }
;
1358 module
.directory
.push(&*path
.as_str());
1360 module
.directory
.push(&*item
.ident
.as_str());
1363 let path
= self.cx
.parse_sess
.source_map().span_to_unmapped_path(inner
);
1364 let mut path
= match path
{
1365 FileName
::Real(path
) => path
,
1366 other
=> PathBuf
::from(other
.to_string()),
1368 let directory_ownership
= match path
.file_name().unwrap().to_str() {
1369 Some("mod.rs") => DirectoryOwnership
::Owned { relative: None }
,
1370 Some(_
) => DirectoryOwnership
::Owned
{
1371 relative
: Some(item
.ident
),
1373 None
=> DirectoryOwnership
::UnownedViaMod(false),
1376 module
.directory
= path
;
1377 self.cx
.current_expansion
.directory_ownership
= directory_ownership
;
1381 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
1382 let result
= noop_flat_map_item(item
, self);
1383 self.cx
.current_expansion
.module
= orig_module
;
1384 self.cx
.current_expansion
.directory_ownership
= orig_directory_ownership
;
1388 _
=> noop_flat_map_item(item
, self),
1392 fn flat_map_trait_item(&mut self, item
: ast
::TraitItem
) -> SmallVec
<[ast
::TraitItem
; 1]> {
1393 let mut item
= configure
!(self, item
);
1395 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1396 if attr
.is_some() || !traits
.is_empty() {
1397 return self.collect_attr(attr
, traits
, Annotatable
::TraitItem(P(item
)),
1398 AstFragmentKind
::TraitItems
, after_derive
).make_trait_items()
1402 ast
::TraitItemKind
::Macro(mac
) => {
1403 let ast
::TraitItem { attrs, span, .. }
= item
;
1404 self.check_attributes(&attrs
);
1405 self.collect_bang(mac
, span
, AstFragmentKind
::TraitItems
).make_trait_items()
1407 _
=> noop_flat_map_trait_item(item
, self),
1411 fn flat_map_impl_item(&mut self, item
: ast
::ImplItem
) -> SmallVec
<[ast
::ImplItem
; 1]> {
1412 let mut item
= configure
!(self, item
);
1414 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1415 if attr
.is_some() || !traits
.is_empty() {
1416 return self.collect_attr(attr
, traits
, Annotatable
::ImplItem(P(item
)),
1417 AstFragmentKind
::ImplItems
, after_derive
).make_impl_items();
1421 ast
::ImplItemKind
::Macro(mac
) => {
1422 let ast
::ImplItem { attrs, span, .. }
= item
;
1423 self.check_attributes(&attrs
);
1424 self.collect_bang(mac
, span
, AstFragmentKind
::ImplItems
).make_impl_items()
1426 _
=> noop_flat_map_impl_item(item
, self),
1430 fn visit_ty(&mut self, ty
: &mut P
<ast
::Ty
>) {
1432 ast
::TyKind
::Mac(_
) => {}
1433 _
=> return noop_visit_ty(ty
, self),
1436 visit_clobber(ty
, |mut ty
| {
1437 match mem
::replace(&mut ty
.node
, ast
::TyKind
::Err
) {
1438 ast
::TyKind
::Mac(mac
) =>
1439 self.collect_bang(mac
, ty
.span
, AstFragmentKind
::Ty
).make_ty(),
1440 _
=> unreachable
!(),
1445 fn visit_foreign_mod(&mut self, foreign_mod
: &mut ast
::ForeignMod
) {
1446 self.cfg
.configure_foreign_mod(foreign_mod
);
1447 noop_visit_foreign_mod(foreign_mod
, self);
1450 fn flat_map_foreign_item(&mut self, mut foreign_item
: ast
::ForeignItem
)
1451 -> SmallVec
<[ast
::ForeignItem
; 1]>
1453 let (attr
, traits
, after_derive
) = self.classify_item(&mut foreign_item
);
1455 if attr
.is_some() || !traits
.is_empty() {
1456 return self.collect_attr(attr
, traits
, Annotatable
::ForeignItem(P(foreign_item
)),
1457 AstFragmentKind
::ForeignItems
, after_derive
)
1458 .make_foreign_items();
1461 if let ast
::ForeignItemKind
::Macro(mac
) = foreign_item
.node
{
1462 self.check_attributes(&foreign_item
.attrs
);
1463 return self.collect_bang(mac
, foreign_item
.span
, AstFragmentKind
::ForeignItems
)
1464 .make_foreign_items();
1467 noop_flat_map_foreign_item(foreign_item
, self)
1470 fn visit_item_kind(&mut self, item
: &mut ast
::ItemKind
) {
1472 ast
::ItemKind
::MacroDef(..) => {}
1474 self.cfg
.configure_item_kind(item
);
1475 noop_visit_item_kind(item
, self);
1480 fn visit_generic_param(&mut self, param
: &mut ast
::GenericParam
) {
1481 self.cfg
.disallow_cfg_on_generic_param(¶m
);
1482 noop_visit_generic_param(param
, self)
1485 fn visit_attribute(&mut self, at
: &mut ast
::Attribute
) {
1486 // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
1487 // contents="file contents")]` attributes
1488 if !at
.check_name("doc") {
1489 return noop_visit_attribute(at
, self);
1492 if let Some(list
) = at
.meta_item_list() {
1493 if !list
.iter().any(|it
| it
.check_name("include")) {
1494 return noop_visit_attribute(at
, self);
1497 let mut items
= vec
![];
1499 for mut it
in list
{
1500 if !it
.check_name("include") {
1501 items
.push({ noop_visit_meta_list_item(&mut it, self); it }
);
1505 if let Some(file
) = it
.value_str() {
1506 let err_count
= self.cx
.parse_sess
.span_diagnostic
.err_count();
1507 self.check_attribute(&at
);
1508 if self.cx
.parse_sess
.span_diagnostic
.err_count() > err_count
{
1509 // avoid loading the file if they haven't enabled the feature
1510 return noop_visit_attribute(at
, self);
1513 let filename
= self.cx
.root_path
.join(file
.to_string());
1514 match fs
::read_to_string(&filename
) {
1516 let src_interned
= Symbol
::intern(&src
);
1518 // Add this input file to the code map to make it available as
1519 // dependency information
1520 self.cx
.source_map().new_source_file(filename
.into(), src
);
1522 let include_info
= vec
![
1523 dummy_spanned(ast
::NestedMetaItemKind
::MetaItem(
1524 attr
::mk_name_value_item_str(
1525 Ident
::from_str("file"),
1526 dummy_spanned(file
),
1529 dummy_spanned(ast
::NestedMetaItemKind
::MetaItem(
1530 attr
::mk_name_value_item_str(
1531 Ident
::from_str("contents"),
1532 dummy_spanned(src_interned
),
1537 let include_ident
= Ident
::from_str("include");
1538 let item
= attr
::mk_list_item(DUMMY_SP
, include_ident
, include_info
);
1539 items
.push(dummy_spanned(ast
::NestedMetaItemKind
::MetaItem(item
)));
1544 .and_then(|item
| item
.name_value_literal())
1547 if e
.kind() == ErrorKind
::InvalidData
{
1551 &format
!("{} wasn't a utf-8 file", filename
.display()),
1553 .span_label(lit
.span
, "contains invalid utf-8")
1556 let mut err
= self.cx
.struct_span_err(
1558 &format
!("couldn't read {}: {}", filename
.display(), e
),
1560 err
.span_label(lit
.span
, "couldn't read file");
1562 if e
.kind() == ErrorKind
::NotFound
{
1563 err
.help("external doc paths are relative to the crate root");
1571 let mut err
= self.cx
.struct_span_err(
1573 &format
!("expected path to external documentation"),
1576 // Check if the user erroneously used `doc(include(...))` syntax.
1577 let literal
= it
.meta_item_list().and_then(|list
| {
1578 if list
.len() == 1 {
1579 list
[0].literal().map(|literal
| &literal
.node
)
1585 let (path
, applicability
) = match &literal
{
1586 Some(LitKind
::Str(path
, ..)) => {
1587 (path
.to_string(), Applicability
::MachineApplicable
)
1589 _
=> (String
::from("<path>"), Applicability
::HasPlaceholders
),
1592 err
.span_suggestion(
1594 "provide a file path with `=`",
1595 format
!("include = \"{}\"", path
),
1603 let meta
= attr
::mk_list_item(DUMMY_SP
, Ident
::from_str("doc"), items
);
1605 ast
::AttrStyle
::Inner
=> *at
= attr
::mk_spanned_attr_inner(at
.span
, at
.id
, meta
),
1606 ast
::AttrStyle
::Outer
=> *at
= attr
::mk_spanned_attr_outer(at
.span
, at
.id
, meta
),
1609 noop_visit_attribute(at
, self)
1613 fn visit_id(&mut self, id
: &mut ast
::NodeId
) {
1615 debug_assert_eq
!(*id
, ast
::DUMMY_NODE_ID
);
1616 *id
= self.cx
.resolver
.next_node_id()
1621 pub struct ExpansionConfig
<'feat
> {
1622 pub crate_name
: String
,
1623 pub features
: Option
<&'feat Features
>,
1624 pub recursion_limit
: usize,
1625 pub trace_mac
: bool
,
1626 pub should_test
: bool
, // If false, strip `#[test]` nodes
1627 pub single_step
: bool
,
1628 pub keep_macs
: bool
,
1631 macro_rules
! feature_tests
{
1632 ($
( fn $getter
:ident
= $field
:ident
, )*) => {
1634 pub fn $
getter(&self) -> bool
{
1635 match self.features
{
1636 Some(&Features { $field: true, .. }
) => true,
1644 impl<'feat
> ExpansionConfig
<'feat
> {
1645 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1649 recursion_limit
: 1024,
1658 fn enable_asm
= asm
,
1659 fn enable_custom_test_frameworks
= custom_test_frameworks
,
1660 fn enable_global_asm
= global_asm
,
1661 fn enable_log_syntax
= log_syntax
,
1662 fn enable_concat_idents
= concat_idents
,
1663 fn enable_trace_macros
= trace_macros
,
1664 fn enable_allow_internal_unstable
= allow_internal_unstable
,
1665 fn enable_format_args_nl
= format_args_nl
,
1666 fn macros_in_extern_enabled
= macros_in_extern
,
1667 fn proc_macro_hygiene
= proc_macro_hygiene
,
1670 fn enable_custom_inner_attributes(&self) -> bool
{
1671 self.features
.map_or(false, |features
| {
1672 features
.custom_inner_attributes
|| features
.custom_attribute
|| features
.rustc_attrs
1677 // A Marker adds the given mark to the syntax context.
1679 pub struct Marker(pub Mark
);
1681 impl MutVisitor
for Marker
{
1682 fn visit_span(&mut self, span
: &mut Span
) {
1683 *span
= span
.apply_mark(self.0)
1686 fn visit_mac(&mut self, mac
: &mut ast
::Mac
) {
1687 noop_visit_mac(mac
, self)