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, SyntaxContext}
;
20 use ext
::placeholders
::{placeholder, PlaceholderExpander}
;
21 use feature_gate
::{self, Features, is_builtin_attr}
;
24 use parse
::{DirectoryOwnership, PResult}
;
25 use parse
::token
::{self, Token}
;
26 use parse
::parser
::Parser
;
31 use syntax_pos
::{Span, DUMMY_SP}
;
32 use tokenstream
::{TokenStream, TokenTree}
;
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
,
234 self.cx
.trace_macros_diag();
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(self.cx
.current_expansion
.mark
);
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_tok
= TokenTree
::Token(DUMMY_SP
, Token
::interpolated(match item
{
431 Annotatable
::Item(item
) => token
::NtItem(item
),
432 Annotatable
::TraitItem(item
) => token
::NtTraitItem(item
.unwrap()),
433 Annotatable
::ImplItem(item
) => token
::NtImplItem(item
.unwrap()),
435 let tok_result
= mac
.expand(self.cx
, attr
.span
, attr
.tokens
, item_tok
);
436 self.parse_expansion(tok_result
, kind
, &attr
.path
, attr
.span
)
438 SyntaxExtension
::ProcMacroDerive(..) | SyntaxExtension
::BuiltinDerive(..) => {
439 self.cx
.span_err(attr
.span
, &format
!("`{}` is a derive mode", attr
.path
));
440 kind
.dummy(attr
.span
)
443 let msg
= &format
!("macro `{}` may not be used in attributes", attr
.path
);
444 self.cx
.span_err(attr
.span
, msg
);
445 kind
.dummy(attr
.span
)
450 /// Expand a macro invocation. Returns the result of expansion.
451 fn expand_bang_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
452 let (mark
, kind
) = (invoc
.expansion_data
.mark
, invoc
.expansion_kind
);
453 let (mac
, ident
, span
) = match invoc
.kind
{
454 InvocationKind
::Bang { mac, ident, span }
=> (mac
, ident
, span
),
457 let path
= &mac
.node
.path
;
459 let ident
= ident
.unwrap_or_else(|| keywords
::Invalid
.ident());
460 let validate_and_set_expn_info
= |def_site_span
, allow_internal_unstable
| {
461 if ident
.name
!= keywords
::Invalid
.name() {
462 return Err(format
!("macro {}! expects no ident argument, given '{}'", path
, ident
));
464 mark
.set_expn_info(ExpnInfo
{
466 callee
: NameAndSpan
{
467 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
469 allow_internal_unstable
: allow_internal_unstable
,
475 let opt_expanded
= match *ext
{
476 SyntaxExtension
::DeclMacro(ref expand
, def_span
) => {
477 if let Err(msg
) = validate_and_set_expn_info(def_span
.map(|(_
, s
)| s
),
479 self.cx
.span_err(path
.span
, &msg
);
480 return kind
.dummy(span
);
482 kind
.make_from(expand
.expand(self.cx
, span
, mac
.node
.stream()))
485 NormalTT(ref expandfun
, def_info
, allow_internal_unstable
) => {
486 if let Err(msg
) = validate_and_set_expn_info(def_info
.map(|(_
, s
)| s
),
487 allow_internal_unstable
) {
488 self.cx
.span_err(path
.span
, &msg
);
489 return kind
.dummy(span
);
491 kind
.make_from(expandfun
.expand(self.cx
, span
, mac
.node
.stream()))
494 IdentTT(ref expander
, tt_span
, allow_internal_unstable
) => {
495 if ident
.name
== keywords
::Invalid
.name() {
496 self.cx
.span_err(path
.span
,
497 &format
!("macro {}! expects an ident argument", path
));
498 return kind
.dummy(span
);
501 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
503 callee
: NameAndSpan
{
504 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
506 allow_internal_unstable
: allow_internal_unstable
,
510 let input
: Vec
<_
> = mac
.node
.stream().into_trees().collect();
511 kind
.make_from(expander
.expand(self.cx
, span
, ident
, input
))
514 MultiDecorator(..) | MultiModifier(..) | SyntaxExtension
::AttrProcMacro(..) => {
515 self.cx
.span_err(path
.span
,
516 &format
!("`{}` can only be used in attributes", path
));
517 return kind
.dummy(span
);
520 SyntaxExtension
::ProcMacroDerive(..) | SyntaxExtension
::BuiltinDerive(..) => {
521 self.cx
.span_err(path
.span
, &format
!("`{}` is a derive mode", path
));
522 return kind
.dummy(span
);
525 SyntaxExtension
::ProcMacro(ref expandfun
) => {
526 if ident
.name
!= keywords
::Invalid
.name() {
528 format
!("macro {}! expects no ident argument, given '{}'", path
, ident
);
529 self.cx
.span_err(path
.span
, &msg
);
530 return kind
.dummy(span
);
533 invoc
.expansion_data
.mark
.set_expn_info(ExpnInfo
{
535 callee
: NameAndSpan
{
536 format
: MacroBang(Symbol
::intern(&format
!("{}", path
))),
537 // FIXME procedural macros do not have proper span info
538 // yet, when they do, we should use it here.
540 // FIXME probably want to follow macro_rules macros here.
541 allow_internal_unstable
: false,
545 let tok_result
= expandfun
.expand(self.cx
, span
, mac
.node
.stream());
546 Some(self.parse_expansion(tok_result
, kind
, path
, span
))
550 unwrap_or
!(opt_expanded
, {
551 let msg
= format
!("non-{kind} macro in {kind} position: {name}",
552 name
= path
.segments
[0].identifier
.name
, kind
= kind
.name());
553 self.cx
.span_err(path
.span
, &msg
);
558 /// Expand a derive invocation. Returns the result of expansion.
559 fn expand_derive_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
560 let Invocation { expansion_kind: kind, .. }
= invoc
;
561 let (path
, item
) = match invoc
.kind
{
562 InvocationKind
::Derive { path, item }
=> (path
, item
),
566 let pretty_name
= Symbol
::intern(&format
!("derive({})", path
));
567 let span
= path
.span
;
568 let attr
= ast
::Attribute
{
569 path
: path
, tokens
: TokenStream
::empty(), span
: span
,
571 id
: ast
::AttrId(0), style
: ast
::AttrStyle
::Outer
, is_sugared_doc
: false,
574 let mut expn_info
= ExpnInfo
{
576 callee
: NameAndSpan
{
577 format
: MacroAttribute(pretty_name
),
579 allow_internal_unstable
: false,
584 SyntaxExtension
::ProcMacroDerive(ref ext
, _
) => {
585 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
586 let span
= Span { ctxt: self.cx.backtrace(), ..span }
;
587 let dummy
= ast
::MetaItem
{ // FIXME(jseyfried) avoid this
588 name
: keywords
::Invalid
.name(),
590 node
: ast
::MetaItemKind
::Word
,
592 kind
.expect_from_annotatables(ext
.expand(self.cx
, span
, &dummy
, item
))
594 SyntaxExtension
::BuiltinDerive(func
) => {
595 expn_info
.callee
.allow_internal_unstable
= true;
596 invoc
.expansion_data
.mark
.set_expn_info(expn_info
);
597 let span
= Span { ctxt: self.cx.backtrace(), ..span }
;
598 let mut items
= Vec
::new();
599 func(self.cx
, span
, &attr
.meta().unwrap(), &item
, &mut |a
| items
.push(a
));
600 kind
.expect_from_annotatables(items
)
603 let msg
= &format
!("macro `{}` may not be used for derive attributes", attr
.path
);
604 self.cx
.span_err(span
, msg
);
610 fn parse_expansion(&mut self, toks
: TokenStream
, kind
: ExpansionKind
, path
: &Path
, span
: Span
)
612 let mut parser
= self.cx
.new_parser_from_tts(&toks
.into_trees().collect
::<Vec
<_
>>());
613 let expansion
= match parser
.parse_expansion(kind
, false) {
614 Ok(expansion
) => expansion
,
617 return kind
.dummy(span
);
620 parser
.ensure_complete_parse(path
, kind
.name(), span
);
625 impl<'a
> Parser
<'a
> {
626 pub fn parse_expansion(&mut self, kind
: ExpansionKind
, macro_legacy_warnings
: bool
)
627 -> PResult
<'a
, Expansion
> {
629 ExpansionKind
::Items
=> {
630 let mut items
= SmallVector
::new();
631 while let Some(item
) = self.parse_item()?
{
634 Expansion
::Items(items
)
636 ExpansionKind
::TraitItems
=> {
637 let mut items
= SmallVector
::new();
638 while self.token
!= token
::Eof
{
639 items
.push(self.parse_trait_item(&mut false)?
);
641 Expansion
::TraitItems(items
)
643 ExpansionKind
::ImplItems
=> {
644 let mut items
= SmallVector
::new();
645 while self.token
!= token
::Eof
{
646 items
.push(self.parse_impl_item(&mut false)?
);
648 Expansion
::ImplItems(items
)
650 ExpansionKind
::Stmts
=> {
651 let mut stmts
= SmallVector
::new();
652 while self.token
!= token
::Eof
&&
653 // won't make progress on a `}`
654 self.token
!= token
::CloseDelim(token
::Brace
) {
655 if let Some(stmt
) = self.parse_full_stmt(macro_legacy_warnings
)?
{
659 Expansion
::Stmts(stmts
)
661 ExpansionKind
::Expr
=> Expansion
::Expr(self.parse_expr()?
),
662 ExpansionKind
::OptExpr
=> Expansion
::OptExpr(Some(self.parse_expr()?
)),
663 ExpansionKind
::Ty
=> Expansion
::Ty(self.parse_ty()?
),
664 ExpansionKind
::Pat
=> Expansion
::Pat(self.parse_pat()?
),
668 pub fn ensure_complete_parse(&mut self, macro_path
: &Path
, kind_name
: &str, span
: Span
) {
669 if self.token
!= token
::Eof
{
670 let msg
= format
!("macro expansion ignores token `{}` and any following",
671 self.this_token_to_string());
672 let mut def_site_span
= self.span
;
673 def_site_span
.ctxt
= SyntaxContext
::empty(); // Avoid emitting backtrace info twice.
674 let mut err
= self.diagnostic().struct_span_err(def_site_span
, &msg
);
675 let msg
= format
!("caused by the macro expansion here; the usage \
676 of `{}!` is likely invalid in {} context",
677 macro_path
, kind_name
);
678 err
.span_note(span
, &msg
).emit();
683 struct InvocationCollector
<'a
, 'b
: 'a
> {
684 cx
: &'a
mut ExtCtxt
<'b
>,
685 cfg
: StripUnconfigured
<'a
>,
686 invocations
: Vec
<Invocation
>,
690 macro_rules
! fully_configure
{
691 ($this
:ident
, $node
:ident
, $noop_fold
:ident
) => {
692 match $
noop_fold($node
, &mut $this
.cfg
).pop() {
694 None
=> return SmallVector
::new(),
699 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
700 fn collect(&mut self, expansion_kind
: ExpansionKind
, kind
: InvocationKind
) -> Expansion
{
701 let mark
= Mark
::fresh(self.cx
.current_expansion
.mark
);
702 self.invocations
.push(Invocation
{
704 expansion_kind
: expansion_kind
,
705 expansion_data
: ExpansionData
{
707 depth
: self.cx
.current_expansion
.depth
+ 1,
708 ..self.cx
.current_expansion
.clone()
711 placeholder(expansion_kind
, NodeId
::placeholder_from_mark(mark
))
714 fn collect_bang(&mut self, mac
: ast
::Mac
, span
: Span
, kind
: ExpansionKind
) -> Expansion
{
715 self.collect(kind
, InvocationKind
::Bang { mac: mac, ident: None, span: span }
)
718 fn collect_attr(&mut self,
719 attr
: Option
<ast
::Attribute
>,
724 if !traits
.is_empty() &&
725 (kind
== ExpansionKind
::TraitItems
|| kind
== ExpansionKind
::ImplItems
) {
726 self.cx
.span_err(traits
[0].span
, "`derive` can be only be applied to items");
727 return kind
.expect_from_annotatables(::std
::iter
::once(item
));
729 self.collect(kind
, InvocationKind
::Attr { attr: attr, traits: traits, item: item }
)
732 // If `item` is an attr invocation, remove and return the macro attribute.
733 fn classify_item
<T
>(&mut self, mut item
: T
) -> (Option
<ast
::Attribute
>, Vec
<Path
>, T
)
736 let (mut attr
, mut traits
) = (None
, Vec
::new());
738 item
= item
.map_attrs(|mut attrs
| {
739 if let Some(legacy_attr_invoc
) = self.cx
.resolver
.find_legacy_attr_invoc(&mut attrs
) {
740 attr
= Some(legacy_attr_invoc
);
744 if self.cx
.ecfg
.proc_macro_enabled() {
745 attr
= find_attr_invoc(&mut attrs
);
747 traits
= collect_derives(&mut self.cx
, &mut attrs
);
754 fn configure
<T
: HasAttrs
>(&mut self, node
: T
) -> Option
<T
> {
755 self.cfg
.configure(node
)
758 // Detect use of feature-gated or invalid attributes on macro invocations
759 // since they will not be detected after macro expansion.
760 fn check_attributes(&mut self, attrs
: &[ast
::Attribute
]) {
761 let features
= self.cx
.ecfg
.features
.unwrap();
762 for attr
in attrs
.iter() {
763 feature_gate
::check_attribute(attr
, self.cx
.parse_sess
, features
);
768 pub fn find_attr_invoc(attrs
: &mut Vec
<ast
::Attribute
>) -> Option
<ast
::Attribute
> {
770 .position(|a
| !attr
::is_known(a
) && !is_builtin_attr(a
))
771 .map(|i
| attrs
.remove(i
))
774 impl<'a
, 'b
> Folder
for InvocationCollector
<'a
, 'b
> {
775 fn fold_expr(&mut self, expr
: P
<ast
::Expr
>) -> P
<ast
::Expr
> {
776 let mut expr
= self.cfg
.configure_expr(expr
).unwrap();
777 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
779 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
780 self.check_attributes(&expr
.attrs
);
781 self.collect_bang(mac
, expr
.span
, ExpansionKind
::Expr
).make_expr()
783 P(noop_fold_expr(expr
, self))
787 fn fold_opt_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
788 let mut expr
= configure
!(self, expr
).unwrap();
789 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
791 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
792 self.check_attributes(&expr
.attrs
);
793 self.collect_bang(mac
, expr
.span
, ExpansionKind
::OptExpr
).make_opt_expr()
795 Some(P(noop_fold_expr(expr
, self)))
799 fn fold_pat(&mut self, pat
: P
<ast
::Pat
>) -> P
<ast
::Pat
> {
800 let pat
= self.cfg
.configure_pat(pat
);
802 PatKind
::Mac(_
) => {}
803 _
=> return noop_fold_pat(pat
, self),
806 pat
.and_then(|pat
| match pat
.node
{
807 PatKind
::Mac(mac
) => self.collect_bang(mac
, pat
.span
, ExpansionKind
::Pat
).make_pat(),
812 fn fold_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVector
<ast
::Stmt
> {
813 let stmt
= match self.cfg
.configure_stmt(stmt
) {
815 None
=> return SmallVector
::new(),
818 let (mac
, style
, attrs
) = if let StmtKind
::Mac(mac
) = stmt
.node
{
821 // The placeholder expander gives ids to statements, so we avoid folding the id here.
822 let ast
::Stmt { id, node, span }
= stmt
;
823 return noop_fold_stmt_kind(node
, self).into_iter().map(|node
| {
824 ast
::Stmt { id: id, node: node, span: span }
828 self.check_attributes(&attrs
);
829 let mut placeholder
= self.collect_bang(mac
, stmt
.span
, ExpansionKind
::Stmts
).make_stmts();
831 // If this is a macro invocation with a semicolon, then apply that
832 // semicolon to the final statement produced by expansion.
833 if style
== MacStmtStyle
::Semicolon
{
834 if let Some(stmt
) = placeholder
.pop() {
835 placeholder
.push(stmt
.add_trailing_semicolon());
842 fn fold_block(&mut self, block
: P
<Block
>) -> P
<Block
> {
843 let old_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
844 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::UnownedViaBlock
;
845 let result
= noop_fold_block(block
, self);
846 self.cx
.current_expansion
.directory_ownership
= old_directory_ownership
;
850 fn fold_item(&mut self, item
: P
<ast
::Item
>) -> SmallVector
<P
<ast
::Item
>> {
851 let item
= configure
!(self, item
);
853 let (attr
, traits
, mut item
) = self.classify_item(item
);
854 if attr
.is_some() || !traits
.is_empty() {
855 let item
= Annotatable
::Item(fully_configure
!(self, item
, noop_fold_item
));
856 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::Items
).make_items();
860 ast
::ItemKind
::Mac(..) => {
861 self.check_attributes(&item
.attrs
);
862 item
.and_then(|item
| match item
.node
{
863 ItemKind
::Mac(mac
) => {
864 self.collect(ExpansionKind
::Items
, InvocationKind
::Bang
{
866 ident
: Some(item
.ident
),
873 ast
::ItemKind
::Mod(ast
::Mod { inner, .. }
) => {
874 if item
.ident
== keywords
::Invalid
.ident() {
875 return noop_fold_item(item
, self);
878 let orig_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
879 let mut module
= (*self.cx
.current_expansion
.module
).clone();
880 module
.mod_path
.push(item
.ident
);
882 // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
883 // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
884 // Thus, if `inner` is the dummy span, we know the module is inline.
885 let inline_module
= item
.span
.contains(inner
) || inner
== DUMMY_SP
;
888 if let Some(path
) = attr
::first_attr_value_str_by_name(&item
.attrs
, "path") {
889 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::Owned
;
890 module
.directory
.push(&*path
.as_str());
892 module
.directory
.push(&*item
.ident
.name
.as_str());
896 PathBuf
::from(self.cx
.parse_sess
.codemap().span_to_filename(inner
));
897 let directory_ownership
= match path
.file_name().unwrap().to_str() {
898 Some("mod.rs") => DirectoryOwnership
::Owned
,
899 _
=> DirectoryOwnership
::UnownedViaMod(false),
902 module
.directory
= path
;
903 self.cx
.current_expansion
.directory_ownership
= directory_ownership
;
907 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
908 let result
= noop_fold_item(item
, self);
909 self.cx
.current_expansion
.module
= orig_module
;
910 self.cx
.current_expansion
.directory_ownership
= orig_directory_ownership
;
913 // Ensure that test functions are accessible from the test harness.
914 ast
::ItemKind
::Fn(..) if self.cx
.ecfg
.should_test
=> {
915 if item
.attrs
.iter().any(|attr
| is_test_or_bench(attr
)) {
916 item
= item
.map(|mut item
| { item.vis = ast::Visibility::Public; item }
);
918 noop_fold_item(item
, self)
920 _
=> noop_fold_item(item
, self),
924 fn fold_trait_item(&mut self, item
: ast
::TraitItem
) -> SmallVector
<ast
::TraitItem
> {
925 let item
= configure
!(self, item
);
927 let (attr
, traits
, item
) = self.classify_item(item
);
928 if attr
.is_some() || !traits
.is_empty() {
930 Annotatable
::TraitItem(P(fully_configure
!(self, item
, noop_fold_trait_item
)));
931 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::TraitItems
)
936 ast
::TraitItemKind
::Macro(mac
) => {
937 let ast
::TraitItem { attrs, span, .. }
= item
;
938 self.check_attributes(&attrs
);
939 self.collect_bang(mac
, span
, ExpansionKind
::TraitItems
).make_trait_items()
941 _
=> fold
::noop_fold_trait_item(item
, self),
945 fn fold_impl_item(&mut self, item
: ast
::ImplItem
) -> SmallVector
<ast
::ImplItem
> {
946 let item
= configure
!(self, item
);
948 let (attr
, traits
, item
) = self.classify_item(item
);
949 if attr
.is_some() || !traits
.is_empty() {
950 let item
= Annotatable
::ImplItem(P(fully_configure
!(self, item
, noop_fold_impl_item
)));
951 return self.collect_attr(attr
, traits
, item
, ExpansionKind
::ImplItems
)
956 ast
::ImplItemKind
::Macro(mac
) => {
957 let ast
::ImplItem { attrs, span, .. }
= item
;
958 self.check_attributes(&attrs
);
959 self.collect_bang(mac
, span
, ExpansionKind
::ImplItems
).make_impl_items()
961 _
=> fold
::noop_fold_impl_item(item
, self),
965 fn fold_ty(&mut self, ty
: P
<ast
::Ty
>) -> P
<ast
::Ty
> {
966 let ty
= match ty
.node
{
967 ast
::TyKind
::Mac(_
) => ty
.unwrap(),
968 _
=> return fold
::noop_fold_ty(ty
, self),
972 ast
::TyKind
::Mac(mac
) => self.collect_bang(mac
, ty
.span
, ExpansionKind
::Ty
).make_ty(),
977 fn fold_foreign_mod(&mut self, foreign_mod
: ast
::ForeignMod
) -> ast
::ForeignMod
{
978 noop_fold_foreign_mod(self.cfg
.configure_foreign_mod(foreign_mod
), self)
981 fn fold_item_kind(&mut self, item
: ast
::ItemKind
) -> ast
::ItemKind
{
983 ast
::ItemKind
::MacroDef(..) => item
,
984 _
=> noop_fold_item_kind(self.cfg
.configure_item_kind(item
), self),
988 fn new_id(&mut self, id
: ast
::NodeId
) -> ast
::NodeId
{
990 assert_eq
!(id
, ast
::DUMMY_NODE_ID
);
991 self.cx
.resolver
.next_node_id()
998 pub struct ExpansionConfig
<'feat
> {
999 pub crate_name
: String
,
1000 pub features
: Option
<&'feat Features
>,
1001 pub recursion_limit
: usize,
1002 pub trace_mac
: bool
,
1003 pub should_test
: bool
, // If false, strip `#[test]` nodes
1004 pub single_step
: bool
,
1005 pub keep_macs
: bool
,
1008 macro_rules
! feature_tests
{
1009 ($
( fn $getter
:ident
= $field
:ident
, )*) => {
1011 pub fn $
getter(&self) -> bool
{
1012 match self.features
{
1013 Some(&Features { $field: true, .. }
) => true,
1021 impl<'feat
> ExpansionConfig
<'feat
> {
1022 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1024 crate_name
: crate_name
,
1026 recursion_limit
: 1024,
1035 fn enable_quotes
= quote
,
1036 fn enable_asm
= asm
,
1037 fn enable_global_asm
= global_asm
,
1038 fn enable_log_syntax
= log_syntax
,
1039 fn enable_concat_idents
= concat_idents
,
1040 fn enable_trace_macros
= trace_macros
,
1041 fn enable_allow_internal_unstable
= allow_internal_unstable
,
1042 fn enable_custom_derive
= custom_derive
,
1043 fn proc_macro_enabled
= proc_macro
,
1047 // A Marker adds the given mark to the syntax context.
1048 pub struct Marker(pub Mark
);
1050 impl Folder
for Marker
{
1051 fn fold_ident(&mut self, mut ident
: Ident
) -> Ident
{
1052 ident
.ctxt
= ident
.ctxt
.apply_mark(self.0);
1056 fn new_span(&mut self, mut span
: Span
) -> Span
{
1057 span
.ctxt
= span
.ctxt
.apply_mark(self.0);
1061 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
1062 noop_fold_mac(mac
, self)