1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use ast
::{self, Block, Ident, NodeId, PatKind, Path}
;
12 use ast
::{MacStmtStyle, StmtKind, ItemKind}
;
13 use attr
::{self, HasAttrs}
;
14 use codemap
::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}
;
15 use config
::{is_test_or_bench, StripUnconfigured}
;
16 use errors
::FatalError
;
18 use ext
::derive
::{add_derived_markers, collect_derives}
;
19 use ext
::hygiene
::Mark
;
20 use ext
::placeholders
::{placeholder, PlaceholderExpander}
;
21 use feature_gate
::{self, Features, is_builtin_attr}
;
24 use parse
::{filemap_to_stream, ParseSess, DirectoryOwnership, PResult, token}
;
25 use parse
::parser
::Parser
;
31 use syntax_pos
::{Span, DUMMY_SP}
;
32 use tokenstream
::TokenStream
;
33 use util
::small_vector
::SmallVector
;
36 use std
::collections
::HashMap
;
38 use std
::path
::PathBuf
;
41 macro_rules
! expansions
{
42 ($
($kind
:ident
: $ty
:ty
[$
($vec
:ident
, $ty_elt
:ty
)*], $kind_name
:expr
, .$make
:ident
,
43 $
(.$fold
:ident
)* $
(lift
.$fold_elt
:ident
)*,
44 $
(.$visit
:ident
)* $
(lift
.$visit_elt
:ident
)*;)*) => {
45 #[derive(Copy, Clone, PartialEq, Eq)]
46 pub enum ExpansionKind { OptExpr, $( $kind, )* }
47 pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
50 pub fn name(self) -> &'
static str {
52 ExpansionKind
::OptExpr
=> "expression",
53 $
( ExpansionKind
::$kind
=> $kind_name
, )*
57 fn make_from
<'a
>(self, result
: Box
<MacResult
+ 'a
>) -> Option
<Expansion
> {
59 ExpansionKind
::OptExpr
=> result
.make_expr().map(Some
).map(Expansion
::OptExpr
),
60 $
( ExpansionKind
::$kind
=> result
.$
make().map(Expansion
::$kind
), )*
66 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
68 Expansion
::OptExpr(expr
) => expr
,
69 _
=> panic
!("Expansion::make_* called on the wrong kind of expansion"),
72 $
( pub fn $
make(self) -> $ty
{
74 Expansion
::$
kind(ast
) => ast
,
75 _
=> panic
!("Expansion::make_* called on the wrong kind of expansion"),
79 pub fn fold_with
<F
: Folder
>(self, folder
: &mut F
) -> Self {
80 use self::Expansion
::*;
82 OptExpr(expr
) => OptExpr(expr
.and_then(|expr
| folder
.fold_opt_expr(expr
))),
83 $
($
( $
kind(ast
) => $
kind(folder
.$
fold(ast
)), )*)*
85 $
kind(ast
.into_iter().flat_map(|ast
| folder
.$
fold_elt(ast
)).collect())
90 pub fn visit_with
<'a
, V
: Visitor
<'a
>>(&'a
self, visitor
: &mut V
) {
92 Expansion
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
93 Expansion
::OptExpr(None
) => {}
94 $
($
( Expansion
::$
kind(ref ast
) => visitor
.$
visit(ast
), )*)*
95 $
($
( Expansion
::$
kind(ref ast
) => for ast
in &ast
[..] {
96 visitor
.$
visit_elt(ast
);
102 impl<'a
, 'b
> Folder
for MacroExpander
<'a
, 'b
> {
103 fn fold_opt_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
104 self.expand(Expansion
::OptExpr(Some(expr
))).make_opt_expr()
106 $
($
(fn $
fold(&mut self, node
: $ty
) -> $ty
{
107 self.expand(Expansion
::$
kind(node
)).$
make()
109 $
($
(fn $
fold_elt(&mut self, node
: $ty_elt
) -> $ty
{
110 self.expand(Expansion
::$
kind(SmallVector
::one(node
))).$
make()
114 impl<'a
> MacResult
for ::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
> {
115 $
(fn $
make(self: Box
<::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
>>) -> Option
<$ty
> {
116 Some(self.make(ExpansionKind
::$kind
).$
make())
123 Expr
: P
<ast
::Expr
> [], "expression", .make_expr
, .fold_expr
, .visit_expr
;
124 Pat
: P
<ast
::Pat
> [], "pattern", .make_pat
, .fold_pat
, .visit_pat
;
125 Ty
: P
<ast
::Ty
> [], "type", .make_ty
, .fold_ty
, .visit_ty
;
126 Stmts
: SmallVector
<ast
::Stmt
> [SmallVector
, ast
::Stmt
],
127 "statement", .make_stmts
, lift
.fold_stmt
, lift
.visit_stmt
;
128 Items
: SmallVector
<P
<ast
::Item
>> [SmallVector
, P
<ast
::Item
>],
129 "item", .make_items
, lift
.fold_item
, lift
.visit_item
;
130 TraitItems
: SmallVector
<ast
::TraitItem
> [SmallVector
, ast
::TraitItem
],
131 "trait item", .make_trait_items
, lift
.fold_trait_item
, lift
.visit_trait_item
;
132 ImplItems
: SmallVector
<ast
::ImplItem
> [SmallVector
, ast
::ImplItem
],
133 "impl item", .make_impl_items
, lift
.fold_impl_item
, lift
.visit_impl_item
;
137 fn dummy(self, span
: Span
) -> Expansion
{
138 self.make_from(DummyResult
::any(span
)).unwrap()
141 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(self, items
: I
) -> Expansion
{
142 let items
= items
.into_iter();
144 ExpansionKind
::Items
=>
145 Expansion
::Items(items
.map(Annotatable
::expect_item
).collect()),
146 ExpansionKind
::ImplItems
=>
147 Expansion
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect()),
148 ExpansionKind
::TraitItems
=>
149 Expansion
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect()),
155 pub struct Invocation
{
156 pub kind
: InvocationKind
,
157 expansion_kind
: ExpansionKind
,
158 pub expansion_data
: ExpansionData
,
161 pub enum InvocationKind
{
164 ident
: Option
<Ident
>,
168 attr
: Option
<ast
::Attribute
>,
179 fn span(&self) -> Span
{
181 InvocationKind
::Bang { span, .. }
=> span
,
182 InvocationKind
::Attr { attr: Some(ref attr), .. }
=> attr
.span
,
183 InvocationKind
::Attr { attr: None, .. }
=> DUMMY_SP
,
184 InvocationKind
::Derive { ref path, .. }
=> path
.span
,
189 pub struct MacroExpander
<'a
, 'b
:'a
> {
190 pub cx
: &'a
mut ExtCtxt
<'b
>,
191 monotonic
: bool
, // c.f. `cx.monotonic_expander()`
194 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
195 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
196 MacroExpander { cx: cx, monotonic: monotonic }
199 pub fn expand_crate(&mut self, mut krate
: ast
::Crate
) -> ast
::Crate
{
200 self.cx
.crate_root
= std_inject
::injected_crate_name(&krate
);
201 let mut module
= ModuleData
{
202 mod_path
: vec
![Ident
::from_str(&self.cx
.ecfg
.crate_name
)],
203 directory
: PathBuf
::from(self.cx
.codemap().span_to_filename(krate
.span
)),
205 module
.directory
.pop();
206 self.cx
.current_expansion
.module
= Rc
::new(module
);
208 let orig_mod_span
= krate
.module
.inner
;
210 let krate_item
= Expansion
::Items(SmallVector
::one(P(ast
::Item
{
213 node
: ast
::ItemKind
::Mod(krate
.module
),
214 ident
: keywords
::Invalid
.ident(),
215 id
: ast
::DUMMY_NODE_ID
,
216 vis
: ast
::Visibility
::Public
,
219 match self.expand(krate_item
).make_items().pop().map(P
::unwrap
) {
220 Some(ast
::Item { attrs, node: ast::ItemKind::Mod(module), .. }
) => {
222 krate
.module
= module
;
225 // Resolution failed so we return an empty expansion
226 krate
.attrs
= vec
![];
227 krate
.module
= ast
::Mod
{
228 inner
: orig_mod_span
,
238 // Fully expand all the invocations in `expansion`.
239 fn expand(&mut self, expansion
: Expansion
) -> Expansion
{
240 let orig_expansion_data
= self.cx
.current_expansion
.clone();
241 self.cx
.current_expansion
.depth
= 0;
243 let (expansion
, mut invocations
) = self.collect_invocations(expansion
, &[]);
244 self.resolve_imports();
245 invocations
.reverse();
247 let mut expansions
= Vec
::new();
248 let mut derives
= HashMap
::new();
249 let mut undetermined_invocations
= Vec
::new();
250 let (mut progress
, mut force
) = (false, !self.monotonic
);
252 let mut invoc
= if let Some(invoc
) = invocations
.pop() {
255 self.resolve_imports();
256 if undetermined_invocations
.is_empty() { break }
257 invocations
= mem
::replace(&mut undetermined_invocations
, Vec
::new());
258 force
= !mem
::replace(&mut progress
, false);
263 if self.monotonic { invoc.expansion_data.mark }
else { orig_expansion_data.mark }
;
264 let ext
= match self.cx
.resolver
.resolve_invoc(&mut invoc
, scope
, force
) {
265 Ok(ext
) => Some(ext
),
266 Err(Determinacy
::Determined
) => None
,
267 Err(Determinacy
::Undetermined
) => {
268 undetermined_invocations
.push(invoc
);
274 let ExpansionData { depth, mark, .. }
= invoc
.expansion_data
;
275 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
277 self.cx
.current_expansion
.mark
= scope
;
278 // FIXME(jseyfried): Refactor out the following logic
279 let (expansion
, new_invocations
) = if let Some(ext
) = ext
{
280 if let Some(ext
) = ext
{
281 let expansion
= self.expand_invoc(invoc
, ext
);
282 self.collect_invocations(expansion
, &[])
283 } else if let InvocationKind
::Attr { attr: None, traits, item }
= invoc
.kind
{
285 .map_attrs(|mut attrs
| { attrs.retain(|a| a.path != "derive"); attrs }
);
286 let item_with_markers
=
287 add_derived_markers(&mut self.cx
, item
.span(), &traits
, item
.clone());
288 let derives
= derives
.entry(invoc
.expansion_data
.mark
).or_insert_with(Vec
::new
);
290 for path
in &traits
{
291 let mark
= Mark
::fresh();
293 let item
= match self.cx
.resolver
.resolve_macro(
294 Mark
::root(), path
, MacroKind
::Derive
, false) {
295 Ok(ext
) => match *ext
{
296 SyntaxExtension
::BuiltinDerive(..) => item_with_markers
.clone(),
301 invocations
.push(Invocation
{
302 kind
: InvocationKind
::Derive { path: path.clone(), item: item }
,
303 expansion_kind
: invoc
.expansion_kind
,
304 expansion_data
: ExpansionData
{
306 ..invoc
.expansion_data
.clone()
310 let expansion
= invoc
.expansion_kind
311 .expect_from_annotatables(::std
::iter
::once(item_with_markers
));
312 self.collect_invocations(expansion
, derives
)
317 self.collect_invocations(invoc
.expansion_kind
.dummy(invoc
.span()), &[])
320 if expansions
.len() < depth
{
321 expansions
.push(Vec
::new());
323 expansions
[depth
- 1].push((mark
, expansion
));
324 if !self.cx
.ecfg
.single_step
{
325 invocations
.extend(new_invocations
.into_iter().rev());
329 self.cx
.current_expansion
= orig_expansion_data
;
331 let mut placeholder_expander
= PlaceholderExpander
::new(self.cx
, self.monotonic
);
332 while let Some(expansions
) = expansions
.pop() {
333 for (mark
, expansion
) in expansions
.into_iter().rev() {
334 let derives
= derives
.remove(&mark
).unwrap_or_else(Vec
::new
);
335 placeholder_expander
.add(NodeId
::placeholder_from_mark(mark
), expansion
, derives
);
339 expansion
.fold_with(&mut placeholder_expander
)
342 fn resolve_imports(&mut self) {
344 let err_count
= self.cx
.parse_sess
.span_diagnostic
.err_count();
345 self.cx
.resolver
.resolve_imports();
346 self.cx
.resolve_err_count
+= self.cx
.parse_sess
.span_diagnostic
.err_count() - err_count
;
350 fn collect_invocations(&mut self, expansion
: Expansion
, derives
: &[Mark
])
351 -> (Expansion
, Vec
<Invocation
>) {
353 let mut collector
= InvocationCollector
{
354 cfg
: StripUnconfigured
{
355 should_test
: self.cx
.ecfg
.should_test
,
356 sess
: self.cx
.parse_sess
,
357 features
: self.cx
.ecfg
.features
,
360 invocations
: Vec
::new(),
361 monotonic
: self.monotonic
,
363 (expansion
.fold_with(&mut collector
), collector
.invocations
)
367 let err_count
= self.cx
.parse_sess
.span_diagnostic
.err_count();
368 let mark
= self.cx
.current_expansion
.mark
;
369 self.cx
.resolver
.visit_expansion(mark
, &result
.0, derives
);
370 self.cx
.resolve_err_count
+= self.cx
.parse_sess
.span_diagnostic
.err_count() - err_count
;
376 fn expand_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
377 let result
= match invoc
.kind
{
378 InvocationKind
::Bang { .. }
=> self.expand_bang_invoc(invoc
, ext
),
379 InvocationKind
::Attr { .. }
=> self.expand_attr_invoc(invoc
, ext
),
380 InvocationKind
::Derive { .. }
=> self.expand_derive_invoc(invoc
, ext
),
383 if self.cx
.current_expansion
.depth
> self.cx
.ecfg
.recursion_limit
{
384 let info
= self.cx
.current_expansion
.mark
.expn_info().unwrap();
385 let suggested_limit
= self.cx
.ecfg
.recursion_limit
* 2;
386 let mut err
= self.cx
.struct_span_fatal(info
.call_site
,
387 &format
!("recursion limit reached while expanding the macro `{}`",
388 info
.callee
.name()));
390 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
399 fn expand_attr_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
400 let Invocation { expansion_kind: kind, .. }
= invoc
;
401 let (attr
, item
) = match invoc
.kind
{
402 InvocationKind
::Attr { attr, item, .. }
=> (attr
.unwrap(), item
),
406 attr
::mark_used(&attr
);
407 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
408 call_site
: attr
.span
,
409 callee
: NameAndSpan
{
410 format
: MacroAttribute(Symbol
::intern(&format
!("{}", attr
.path
))),
412 allow_internal_unstable
: false,
417 MultiModifier(ref mac
) => {
418 let meta
= panictry
!(attr
.parse_meta(&self.cx
.parse_sess
));
419 let item
= mac
.expand(self.cx
, attr
.span
, &meta
, item
);
420 kind
.expect_from_annotatables(item
)
422 MultiDecorator(ref mac
) => {
423 let mut items
= Vec
::new();
424 let meta
= panictry
!(attr
.parse_meta(&self.cx
.parse_sess
));
425 mac
.expand(self.cx
, attr
.span
, &meta
, &item
, &mut |item
| items
.push(item
));
427 kind
.expect_from_annotatables(items
)
429 SyntaxExtension
::AttrProcMacro(ref mac
) => {
430 let item_toks
= stream_for_item(&item
, &self.cx
.parse_sess
);
432 let span
= Span { ctxt: self.cx.backtrace(), ..attr.span }
;
433 let tok_result
= mac
.expand(self.cx
, attr
.span
, attr
.tokens
, item_toks
);
434 self.parse_expansion(tok_result
, kind
, &attr
.path
, span
)
436 SyntaxExtension
::ProcMacroDerive(..) | SyntaxExtension
::BuiltinDerive(..) => {
437 self.cx
.span_err(attr
.span
, &format
!("`{}` is a derive mode", attr
.path
));
438 kind
.dummy(attr
.span
)
441 let msg
= &format
!("macro `{}` may not be used in attributes", attr
.path
);
442 self.cx
.span_err(attr
.span
, &msg
);
443 kind
.dummy(attr
.span
)
448 /// Expand a macro invocation. Returns the result of expansion.
449 fn expand_bang_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
450 let (mark
, kind
) = (invoc
.expansion_data
.mark
, invoc
.expansion_kind
);
451 let (mac
, ident
, span
) = match invoc
.kind
{
452 InvocationKind
::Bang { mac, ident, span }
=> (mac
, ident
, span
),
455 let path
= &mac
.node
.path
;
457 let ident
= ident
.unwrap_or(keywords
::Invalid
.ident());
458 let marked_tts
= noop_fold_tts(mac
.node
.stream(), &mut Marker(mark
));
459 let opt_expanded
= match *ext
{
460 NormalTT(ref expandfun
, exp_span
, allow_internal_unstable
) => {
461 if ident
.name
!= keywords
::Invalid
.name() {
463 format
!("macro {}! expects no ident argument, given '{}'", path
, ident
);
464 self.cx
.span_err(path
.span
, &msg
);
465 return kind
.dummy(span
);
468 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
470 callee
: NameAndSpan
{
471 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
473 allow_internal_unstable
: allow_internal_unstable
,
477 kind
.make_from(expandfun
.expand(self.cx
, span
, marked_tts
))
480 IdentTT(ref expander
, tt_span
, allow_internal_unstable
) => {
481 if ident
.name
== keywords
::Invalid
.name() {
482 self.cx
.span_err(path
.span
,
483 &format
!("macro {}! expects an ident argument", path
));
484 return kind
.dummy(span
);
487 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
489 callee
: NameAndSpan
{
490 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
492 allow_internal_unstable
: allow_internal_unstable
,
496 let input
: Vec
<_
> = marked_tts
.into_trees().collect();
497 kind
.make_from(expander
.expand(self.cx
, span
, ident
, input
))
500 MultiDecorator(..) | MultiModifier(..) | SyntaxExtension
::AttrProcMacro(..) => {
501 self.cx
.span_err(path
.span
,
502 &format
!("`{}` can only be used in attributes", path
));
503 return kind
.dummy(span
);
506 SyntaxExtension
::ProcMacroDerive(..) | SyntaxExtension
::BuiltinDerive(..) => {
507 self.cx
.span_err(path
.span
, &format
!("`{}` is a derive mode", path
));
508 return kind
.dummy(span
);
511 SyntaxExtension
::ProcMacro(ref expandfun
) => {
512 if ident
.name
!= keywords
::Invalid
.name() {
514 format
!("macro {}! expects no ident argument, given '{}'", path
, ident
);
515 self.cx
.span_err(path
.span
, &msg
);
516 return kind
.dummy(span
);
519 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
521 callee
: NameAndSpan
{
522 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
523 // FIXME procedural macros do not have proper span info
524 // yet, when they do, we should use it here.
526 // FIXME probably want to follow macro_rules macros here.
527 allow_internal_unstable
: false,
531 let tok_result
= expandfun
.expand(self.cx
, span
, marked_tts
);
532 Some(self.parse_expansion(tok_result
, kind
, path
, span
))
536 let expanded
= if let Some(expanded
) = opt_expanded
{
539 let msg
= format
!("non-{kind} macro in {kind} position: {name}",
540 name
= path
.segments
[0].identifier
.name
, kind
= kind
.name());
541 self.cx
.span_err(path
.span
, &msg
);
542 return kind
.dummy(span
);
545 expanded
.fold_with(&mut Marker(mark
))
548 /// Expand a derive invocation. Returns the result of expansion.
549 fn expand_derive_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
550 let Invocation { expansion_kind: kind, .. }
= invoc
;
551 let (path
, item
) = match invoc
.kind
{
552 InvocationKind
::Derive { path, item }
=> (path
, item
),
556 let pretty_name
= Symbol
::intern(&format
!("derive({})", path
));
557 let span
= path
.span
;
558 let attr
= ast
::Attribute
{
559 path
: path
, tokens
: TokenStream
::empty(), span
: span
,
561 id
: ast
::AttrId(0), style
: ast
::AttrStyle
::Outer
, is_sugared_doc
: false,
564 let mut expn_info
= ExpnInfo
{
566 callee
: NameAndSpan
{
567 format
: MacroAttribute(pretty_name
),
569 allow_internal_unstable
: false,
574 SyntaxExtension
::ProcMacroDerive(ref ext
, _
) => {
575 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
576 let span
= Span { ctxt: self.cx.backtrace(), ..span }
;
577 let dummy
= ast
::MetaItem
{ // FIXME(jseyfried) avoid this
578 name
: keywords
::Invalid
.name(),
580 node
: ast
::MetaItemKind
::Word
,
582 kind
.expect_from_annotatables(ext
.expand(self.cx
, span
, &dummy
, item
))
584 SyntaxExtension
::BuiltinDerive(func
) => {
585 expn_info
.callee
.allow_internal_unstable
= true;
586 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
587 let span
= Span { ctxt: self.cx.backtrace(), ..span }
;
588 let mut items
= Vec
::new();
589 func(self.cx
, span
, &attr
.meta().unwrap(), &item
, &mut |a
| items
.push(a
));
590 kind
.expect_from_annotatables(items
)
593 let msg
= &format
!("macro `{}` may not be used for derive attributes", attr
.path
);
594 self.cx
.span_err(span
, &msg
);
600 fn parse_expansion(&mut self, toks
: TokenStream
, kind
: ExpansionKind
, path
: &Path
, span
: Span
)
602 let mut parser
= self.cx
.new_parser_from_tts(&toks
.into_trees().collect
::<Vec
<_
>>());
603 let expansion
= match parser
.parse_expansion(kind
, false) {
604 Ok(expansion
) => expansion
,
607 return kind
.dummy(span
);
610 parser
.ensure_complete_parse(path
, kind
.name(), span
);
611 // FIXME better span info
612 expansion
.fold_with(&mut ChangeSpan { span: span }
)
616 impl<'a
> Parser
<'a
> {
617 pub fn parse_expansion(&mut self, kind
: ExpansionKind
, macro_legacy_warnings
: bool
)
618 -> PResult
<'a
, Expansion
> {
620 ExpansionKind
::Items
=> {
621 let mut items
= SmallVector
::new();
622 while let Some(item
) = self.parse_item()?
{
625 Expansion
::Items(items
)
627 ExpansionKind
::TraitItems
=> {
628 let mut items
= SmallVector
::new();
629 while self.token
!= token
::Eof
{
630 items
.push(self.parse_trait_item(&mut false)?
);
632 Expansion
::TraitItems(items
)
634 ExpansionKind
::ImplItems
=> {
635 let mut items
= SmallVector
::new();
636 while self.token
!= token
::Eof
{
637 items
.push(self.parse_impl_item(&mut false)?
);
639 Expansion
::ImplItems(items
)
641 ExpansionKind
::Stmts
=> {
642 let mut stmts
= SmallVector
::new();
643 while self.token
!= token
::Eof
&&
644 // won't make progress on a `}`
645 self.token
!= token
::CloseDelim(token
::Brace
) {
646 if let Some(stmt
) = self.parse_full_stmt(macro_legacy_warnings
)?
{
650 Expansion
::Stmts(stmts
)
652 ExpansionKind
::Expr
=> Expansion
::Expr(self.parse_expr()?
),
653 ExpansionKind
::OptExpr
=> Expansion
::OptExpr(Some(self.parse_expr()?
)),
654 ExpansionKind
::Ty
=> Expansion
::Ty(self.parse_ty()?
),
655 ExpansionKind
::Pat
=> Expansion
::Pat(self.parse_pat()?
),
659 pub fn ensure_complete_parse(&mut self, macro_path
: &Path
, kind_name
: &str, span
: Span
) {
660 if self.token
!= token
::Eof
{
661 let msg
= format
!("macro expansion ignores token `{}` and any following",
662 self.this_token_to_string());
663 let mut err
= self.diagnostic().struct_span_err(self.span
, &msg
);
664 let msg
= format
!("caused by the macro expansion here; the usage \
665 of `{}!` is likely invalid in {} context",
666 macro_path
, kind_name
);
667 err
.span_note(span
, &msg
).emit();
672 struct InvocationCollector
<'a
, 'b
: 'a
> {
673 cx
: &'a
mut ExtCtxt
<'b
>,
674 cfg
: StripUnconfigured
<'a
>,
675 invocations
: Vec
<Invocation
>,
679 macro_rules
! fully_configure
{
680 ($this
:ident
, $node
:ident
, $noop_fold
:ident
) => {
681 match $
noop_fold($node
, &mut $this
.cfg
).pop() {
683 None
=> return SmallVector
::new(),
688 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
689 fn collect(&mut self, expansion_kind
: ExpansionKind
, kind
: InvocationKind
) -> Expansion
{
690 let mark
= Mark
::fresh();
691 self.invocations
.push(Invocation
{
693 expansion_kind
: expansion_kind
,
694 expansion_data
: ExpansionData
{
696 depth
: self.cx
.current_expansion
.depth
+ 1,
697 ..self.cx
.current_expansion
.clone()
700 placeholder(expansion_kind
, NodeId
::placeholder_from_mark(mark
))
703 fn collect_bang(&mut self, mac
: ast
::Mac
, span
: Span
, kind
: ExpansionKind
) -> Expansion
{
704 self.collect(kind
, InvocationKind
::Bang { mac: mac, ident: None, span: span }
)
707 fn collect_attr(&mut self,
708 attr
: Option
<ast
::Attribute
>,
713 if !traits
.is_empty() &&
714 (kind
== ExpansionKind
::TraitItems
|| kind
== ExpansionKind
::ImplItems
) {
715 self.cx
.span_err(traits
[0].span
, "`derive` can be only be applied to items");
716 return kind
.expect_from_annotatables(::std
::iter
::once(item
));
718 self.collect(kind
, InvocationKind
::Attr { attr: attr, traits: traits, item: item }
)
721 // If `item` is an attr invocation, remove and return the macro attribute.
722 fn classify_item
<T
>(&mut self, mut item
: T
) -> (Option
<ast
::Attribute
>, Vec
<Path
>, T
)
725 let (mut attr
, mut traits
) = (None
, Vec
::new());
727 item
= item
.map_attrs(|mut attrs
| {
728 if let Some(legacy_attr_invoc
) = self.cx
.resolver
.find_legacy_attr_invoc(&mut attrs
) {
729 attr
= Some(legacy_attr_invoc
);
733 if self.cx
.ecfg
.proc_macro_enabled() {
734 attr
= find_attr_invoc(&mut attrs
);
736 traits
= collect_derives(&mut self.cx
, &mut attrs
);
743 fn configure
<T
: HasAttrs
>(&mut self, node
: T
) -> Option
<T
> {
744 self.cfg
.configure(node
)
747 // Detect use of feature-gated or invalid attributes on macro invocations
748 // since they will not be detected after macro expansion.
749 fn check_attributes(&mut self, attrs
: &[ast
::Attribute
]) {
750 let features
= self.cx
.ecfg
.features
.unwrap();
751 for attr
in attrs
.iter() {
752 feature_gate
::check_attribute(&attr
, &self.cx
.parse_sess
, features
);
757 pub fn find_attr_invoc(attrs
: &mut Vec
<ast
::Attribute
>) -> Option
<ast
::Attribute
> {
758 for i
in 0 .. attrs
.len() {
759 if !attr
::is_known(&attrs
[i
]) && !is_builtin_attr(&attrs
[i
]) {
760 return Some(attrs
.remove(i
));
767 // These are pretty nasty. Ideally, we would keep the tokens around, linked from
768 // the AST. However, we don't so we need to create new ones. Since the item might
769 // have come from a macro expansion (possibly only in part), we can't use the
772 // Therefore, we must use the pretty printer (yuck) to turn the AST node into a
773 // string, which we then re-tokenise (double yuck), but first we have to patch
774 // the pretty-printed string on to the end of the existing codemap (infinity-yuck).
775 fn stream_for_item(item
: &Annotatable
, parse_sess
: &ParseSess
) -> TokenStream
{
776 let text
= match *item
{
777 Annotatable
::Item(ref i
) => pprust
::item_to_string(i
),
778 Annotatable
::TraitItem(ref ti
) => pprust
::trait_item_to_string(ti
),
779 Annotatable
::ImplItem(ref ii
) => pprust
::impl_item_to_string(ii
),
781 string_to_stream(text
, parse_sess
)
784 fn string_to_stream(text
: String
, parse_sess
: &ParseSess
) -> TokenStream
{
785 let filename
= String
::from("<macro expansion>");
786 filemap_to_stream(parse_sess
, parse_sess
.codemap().new_filemap(filename
, None
, text
))
789 impl<'a
, 'b
> Folder
for InvocationCollector
<'a
, 'b
> {
790 fn fold_expr(&mut self, expr
: P
<ast
::Expr
>) -> P
<ast
::Expr
> {
791 let mut expr
= self.cfg
.configure_expr(expr
).unwrap();
792 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
794 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
795 self.check_attributes(&expr
.attrs
);
796 self.collect_bang(mac
, expr
.span
, ExpansionKind
::Expr
).make_expr()
798 P(noop_fold_expr(expr
, self))
802 fn fold_opt_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
803 let mut expr
= configure
!(self, expr
).unwrap();
804 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
806 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
807 self.check_attributes(&expr
.attrs
);
808 self.collect_bang(mac
, expr
.span
, ExpansionKind
::OptExpr
).make_opt_expr()
810 Some(P(noop_fold_expr(expr
, self)))
814 fn fold_pat(&mut self, pat
: P
<ast
::Pat
>) -> P
<ast
::Pat
> {
815 let pat
= self.cfg
.configure_pat(pat
);
817 PatKind
::Mac(_
) => {}
818 _
=> return noop_fold_pat(pat
, self),
821 pat
.and_then(|pat
| match pat
.node
{
822 PatKind
::Mac(mac
) => self.collect_bang(mac
, pat
.span
, ExpansionKind
::Pat
).make_pat(),
827 fn fold_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVector
<ast
::Stmt
> {
828 let stmt
= match self.cfg
.configure_stmt(stmt
) {
830 None
=> return SmallVector
::new(),
833 let (mac
, style
, attrs
) = if let StmtKind
::Mac(mac
) = stmt
.node
{
836 // The placeholder expander gives ids to statements, so we avoid folding the id here.
837 let ast
::Stmt { id, node, span }
= stmt
;
838 return noop_fold_stmt_kind(node
, self).into_iter().map(|node
| {
839 ast
::Stmt { id: id, node: node, span: span }
843 self.check_attributes(&attrs
);
844 let mut placeholder
= self.collect_bang(mac
, stmt
.span
, ExpansionKind
::Stmts
).make_stmts();
846 // If this is a macro invocation with a semicolon, then apply that
847 // semicolon to the final statement produced by expansion.
848 if style
== MacStmtStyle
::Semicolon
{
849 if let Some(stmt
) = placeholder
.pop() {
850 placeholder
.push(stmt
.add_trailing_semicolon());
857 fn fold_block(&mut self, block
: P
<Block
>) -> P
<Block
> {
858 let old_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
859 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::UnownedViaBlock
;
860 let result
= noop_fold_block(block
, self);
861 self.cx
.current_expansion
.directory_ownership
= old_directory_ownership
;
865 fn fold_item(&mut self, item
: P
<ast
::Item
>) -> SmallVector
<P
<ast
::Item
>> {
866 let item
= configure
!(self, item
);
868 let (attr
, traits
, mut item
) = self.classify_item(item
);
869 if attr
.is_some() || !traits
.is_empty() {
870 let item
= Annotatable
::Item(fully_configure
!(self, item
, noop_fold_item
));
871 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::Items
).make_items();
875 ast
::ItemKind
::Mac(..) => {
876 self.check_attributes(&item
.attrs
);
877 item
.and_then(|item
| match item
.node
{
878 ItemKind
::Mac(mac
) => {
879 self.collect(ExpansionKind
::Items
, InvocationKind
::Bang
{
881 ident
: Some(item
.ident
),
888 ast
::ItemKind
::Mod(ast
::Mod { inner, .. }
) => {
889 if item
.ident
== keywords
::Invalid
.ident() {
890 return noop_fold_item(item
, self);
893 let orig_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
894 let mut module
= (*self.cx
.current_expansion
.module
).clone();
895 module
.mod_path
.push(item
.ident
);
897 // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
898 // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
899 // Thus, if `inner` is the dummy span, we know the module is inline.
900 let inline_module
= item
.span
.contains(inner
) || inner
== DUMMY_SP
;
903 if let Some(path
) = attr
::first_attr_value_str_by_name(&item
.attrs
, "path") {
904 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::Owned
;
905 module
.directory
.push(&*path
.as_str());
907 module
.directory
.push(&*item
.ident
.name
.as_str());
911 PathBuf
::from(self.cx
.parse_sess
.codemap().span_to_filename(inner
));
912 let directory_ownership
= match path
.file_name().unwrap().to_str() {
913 Some("mod.rs") => DirectoryOwnership
::Owned
,
914 _
=> DirectoryOwnership
::UnownedViaMod(false),
917 module
.directory
= path
;
918 self.cx
.current_expansion
.directory_ownership
= directory_ownership
;
922 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
923 let result
= noop_fold_item(item
, self);
924 self.cx
.current_expansion
.module
= orig_module
;
925 self.cx
.current_expansion
.directory_ownership
= orig_directory_ownership
;
928 // Ensure that test functions are accessible from the test harness.
929 ast
::ItemKind
::Fn(..) if self.cx
.ecfg
.should_test
=> {
930 if item
.attrs
.iter().any(|attr
| is_test_or_bench(attr
)) {
931 item
= item
.map(|mut item
| { item.vis = ast::Visibility::Public; item }
);
933 noop_fold_item(item
, self)
935 _
=> noop_fold_item(item
, self),
939 fn fold_trait_item(&mut self, item
: ast
::TraitItem
) -> SmallVector
<ast
::TraitItem
> {
940 let item
= configure
!(self, item
);
942 let (attr
, traits
, item
) = self.classify_item(item
);
943 if attr
.is_some() || !traits
.is_empty() {
945 Annotatable
::TraitItem(P(fully_configure
!(self, item
, noop_fold_trait_item
)));
946 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::TraitItems
)
951 ast
::TraitItemKind
::Macro(mac
) => {
952 let ast
::TraitItem { attrs, span, .. }
= item
;
953 self.check_attributes(&attrs
);
954 self.collect_bang(mac
, span
, ExpansionKind
::TraitItems
).make_trait_items()
956 _
=> fold
::noop_fold_trait_item(item
, self),
960 fn fold_impl_item(&mut self, item
: ast
::ImplItem
) -> SmallVector
<ast
::ImplItem
> {
961 let item
= configure
!(self, item
);
963 let (attr
, traits
, item
) = self.classify_item(item
);
964 if attr
.is_some() || !traits
.is_empty() {
965 let item
= Annotatable
::ImplItem(P(fully_configure
!(self, item
, noop_fold_impl_item
)));
966 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::ImplItems
)
971 ast
::ImplItemKind
::Macro(mac
) => {
972 let ast
::ImplItem { attrs, span, .. }
= item
;
973 self.check_attributes(&attrs
);
974 self.collect_bang(mac
, span
, ExpansionKind
::ImplItems
).make_impl_items()
976 _
=> fold
::noop_fold_impl_item(item
, self),
980 fn fold_ty(&mut self, ty
: P
<ast
::Ty
>) -> P
<ast
::Ty
> {
981 let ty
= match ty
.node
{
982 ast
::TyKind
::Mac(_
) => ty
.unwrap(),
983 _
=> return fold
::noop_fold_ty(ty
, self),
987 ast
::TyKind
::Mac(mac
) => self.collect_bang(mac
, ty
.span
, ExpansionKind
::Ty
).make_ty(),
992 fn fold_foreign_mod(&mut self, foreign_mod
: ast
::ForeignMod
) -> ast
::ForeignMod
{
993 noop_fold_foreign_mod(self.cfg
.configure_foreign_mod(foreign_mod
), self)
996 fn fold_item_kind(&mut self, item
: ast
::ItemKind
) -> ast
::ItemKind
{
998 ast
::ItemKind
::MacroDef(..) => item
,
999 _
=> noop_fold_item_kind(self.cfg
.configure_item_kind(item
), self),
1003 fn new_id(&mut self, id
: ast
::NodeId
) -> ast
::NodeId
{
1005 assert_eq
!(id
, ast
::DUMMY_NODE_ID
);
1006 self.cx
.resolver
.next_node_id()
1013 pub struct ExpansionConfig
<'feat
> {
1014 pub crate_name
: String
,
1015 pub features
: Option
<&'feat Features
>,
1016 pub recursion_limit
: usize,
1017 pub trace_mac
: bool
,
1018 pub should_test
: bool
, // If false, strip `#[test]` nodes
1019 pub single_step
: bool
,
1020 pub keep_macs
: bool
,
1023 macro_rules
! feature_tests
{
1024 ($
( fn $getter
:ident
= $field
:ident
, )*) => {
1026 pub fn $
getter(&self) -> bool
{
1027 match self.features
{
1028 Some(&Features { $field: true, .. }
) => true,
1036 impl<'feat
> ExpansionConfig
<'feat
> {
1037 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1039 crate_name
: crate_name
,
1041 recursion_limit
: 64,
1050 fn enable_quotes
= quote
,
1051 fn enable_asm
= asm
,
1052 fn enable_global_asm
= global_asm
,
1053 fn enable_log_syntax
= log_syntax
,
1054 fn enable_concat_idents
= concat_idents
,
1055 fn enable_trace_macros
= trace_macros
,
1056 fn enable_allow_internal_unstable
= allow_internal_unstable
,
1057 fn enable_custom_derive
= custom_derive
,
1058 fn proc_macro_enabled
= proc_macro
,
1062 // A Marker adds the given mark to the syntax context.
1063 struct Marker(Mark
);
1065 impl Folder
for Marker
{
1066 fn fold_ident(&mut self, mut ident
: Ident
) -> Ident
{
1067 ident
.ctxt
= ident
.ctxt
.apply_mark(self.0);
1071 fn new_span(&mut self, mut span
: Span
) -> Span
{
1072 span
.ctxt
= span
.ctxt
.apply_mark(self.0);
1076 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
1077 noop_fold_mac(mac
, self)