expand.rs 53.5 KB
Newer Older
S
Steven Fackler 已提交
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use ast::{self, Block, Ident, NodeId, PatKind, Path};
J
Jeffrey Seyfried 已提交
12
use ast::{MacStmtStyle, StmtKind, ItemKind};
13
use attr::{self, HasAttrs};
14
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan};
15
use config::{is_test_or_bench, StripUnconfigured};
16
use errors::FatalError;
P
Patrick Walton 已提交
17
use ext::base::*;
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, GateIssue, is_builtin_attr, emit_feature_err};
J
John Clements 已提交
22
use fold;
23
use fold::*;
J
Jeffrey Seyfried 已提交
24 25
use parse::{DirectoryOwnership, PResult};
use parse::token::{self, Token};
N
Nick Cameron 已提交
26
use parse::parser::Parser;
27
use ptr::P;
28
use symbol::Symbol;
29
use symbol::keywords;
30
use syntax_pos::{Span, DUMMY_SP, FileName};
31
use syntax_pos::hygiene::ExpnFormat;
J
Jeffrey Seyfried 已提交
32
use tokenstream::{TokenStream, TokenTree};
33
use util::small_vector::SmallVector;
34
use visit::Visitor;
35

36
use std::collections::HashMap;
37 38
use std::fs::File;
use std::io::Read;
39
use std::mem;
J
Jeffrey Seyfried 已提交
40
use std::rc::Rc;
41
use std::path::PathBuf;
42

43
macro_rules! expansions {
44
    ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
45 46
            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
            $(.$visit:ident)*  $(lift .$visit_elt:ident)*;)*) => {
47
        #[derive(Copy, Clone, PartialEq, Eq)]
48 49
        pub enum ExpansionKind { OptExpr, $( $kind, )*  }
        pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
50 51

        impl ExpansionKind {
52
            pub fn name(self) -> &'static str {
53 54 55 56 57
                match self {
                    ExpansionKind::OptExpr => "expression",
                    $( ExpansionKind::$kind => $kind_name, )*
                }
            }
J
Jeffrey Seyfried 已提交
58

59 60 61 62 63 64 65
            fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<Expansion> {
                match self {
                    ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr),
                    $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )*
                }
            }
        }
66

67
        impl Expansion {
68
            pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
69 70 71 72 73
                match self {
                    Expansion::OptExpr(expr) => expr,
                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                }
            }
74
            $( pub fn $make(self) -> $ty {
75 76 77 78 79
                match self {
                    Expansion::$kind(ast) => ast,
                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                }
            } )*
80

81
            pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
82 83 84 85 86 87 88 89
                use self::Expansion::*;
                match self {
                    OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
                    $($( $kind(ast) => $kind(folder.$fold(ast)), )*)*
                    $($( $kind(ast) => {
                        $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect())
                    }, )*)*
                }
90
            }
91

92
            pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
93 94 95 96
                match *self {
                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
                    Expansion::OptExpr(None) => {}
                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
97
                    $($( Expansion::$kind(ref ast) => for ast in &ast[..] {
98 99 100 101
                        visitor.$visit_elt(ast);
                    }, )*)*
                }
            }
102
        }
103 104 105 106 107 108 109 110 111 112 113 114

        impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
            fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
                self.expand(Expansion::OptExpr(Some(expr))).make_opt_expr()
            }
            $($(fn $fold(&mut self, node: $ty) -> $ty {
                self.expand(Expansion::$kind(node)).$make()
            })*)*
            $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty {
                self.expand(Expansion::$kind(SmallVector::one(node))).$make()
            })*)*
        }
115 116 117 118 119 120

        impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> {
            $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> {
                Some(self.make(ExpansionKind::$kind).$make())
            })*
        }
121
    }
122 123
}

124
expansions! {
125 126 127
    Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr;
    Pat: P<ast::Pat>   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
    Ty: P<ast::Ty>     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
128
    Stmts: SmallVector<ast::Stmt> [SmallVector, ast::Stmt],
129
        "statement",  .make_stmts,       lift .fold_stmt, lift .visit_stmt;
130
    Items: SmallVector<P<ast::Item>> [SmallVector, P<ast::Item>],
131
        "item",       .make_items,       lift .fold_item, lift .visit_item;
132
    TraitItems: SmallVector<ast::TraitItem> [SmallVector, ast::TraitItem],
133
        "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
134
    ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
135
        "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
136 137
}

138
impl ExpansionKind {
139 140
    fn dummy(self, span: Span) -> Option<Expansion> {
        self.make_from(DummyResult::any(span))
141
    }
142 143 144 145 146 147 148 149 150 151 152 153 154

    fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) -> Expansion {
        let items = items.into_iter();
        match self {
            ExpansionKind::Items =>
                Expansion::Items(items.map(Annotatable::expect_item).collect()),
            ExpansionKind::ImplItems =>
                Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
            ExpansionKind::TraitItems =>
                Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
            _ => unreachable!(),
        }
    }
155
}
156

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
    // We don't want to format a path using pretty-printing,
    // `format!("{}", path)`, because that tries to insert
    // line-breaks and is slow.
    let mut path_str = String::with_capacity(64);
    for (i, segment) in path.segments.iter().enumerate() {
        if i != 0 {
            path_str.push_str("::");
        }

        if segment.identifier.name != keywords::CrateRoot.name() &&
            segment.identifier.name != keywords::DollarCrate.name()
        {
            path_str.push_str(&segment.identifier.name.as_str())
        }
    }

    MacroBang(Symbol::intern(&path_str))
}

177
pub struct Invocation {
178
    pub kind: InvocationKind,
179
    expansion_kind: ExpansionKind,
180
    pub expansion_data: ExpansionData,
181 182
}

183
pub enum InvocationKind {
184 185 186 187 188 189
    Bang {
        mac: ast::Mac,
        ident: Option<Ident>,
        span: Span,
    },
    Attr {
190
        attr: Option<ast::Attribute>,
J
Jeffrey Seyfried 已提交
191
        traits: Vec<Path>,
192 193
        item: Annotatable,
    },
194
    Derive {
J
Jeffrey Seyfried 已提交
195
        path: Path,
196 197
        item: Annotatable,
    },
198
}
199

200 201 202 203
impl Invocation {
    fn span(&self) -> Span {
        match self.kind {
            InvocationKind::Bang { span, .. } => span,
204
            InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
J
Jeffrey Seyfried 已提交
205 206
            InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
            InvocationKind::Derive { ref path, .. } => path.span,
207 208 209 210
        }
    }
}

211
pub struct MacroExpander<'a, 'b:'a> {
212
    pub cx: &'a mut ExtCtxt<'b>,
213
    monotonic: bool, // c.f. `cx.monotonic_expander()`
N
Nick Cameron 已提交
214 215 216
}

impl<'a, 'b> MacroExpander<'a, 'b> {
217
    pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
218
        MacroExpander { cx: cx, monotonic: monotonic }
N
Nick Cameron 已提交
219
    }
220

221 222
    pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
        let mut module = ModuleData {
223
            mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
224 225 226 227
            directory: match self.cx.codemap().span_to_unmapped_path(krate.span) {
                FileName::Real(path) => path,
                other => PathBuf::from(other.to_string()),
            },
228 229
        };
        module.directory.pop();
230
        self.cx.root_path = module.directory.clone();
231
        self.cx.current_expansion.module = Rc::new(module);
232
        self.cx.current_expansion.crate_span = Some(krate.span);
233

234 235
        let orig_mod_span = krate.module.inner;

236 237 238 239 240 241
        let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
            attrs: krate.attrs,
            span: krate.span,
            node: ast::ItemKind::Mod(krate.module),
            ident: keywords::Invalid.ident(),
            id: ast::DUMMY_NODE_ID,
242
            vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public),
243
            tokens: None,
244 245
        })));

246
        match self.expand(krate_item).make_items().pop().map(P::into_inner) {
247
            Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => {
248 249 250
                krate.attrs = attrs;
                krate.module = module;
            },
251 252 253 254 255 256 257 258
            None => {
                // Resolution failed so we return an empty expansion
                krate.attrs = vec![];
                krate.module = ast::Mod {
                    inner: orig_mod_span,
                    items: vec![],
                };
            },
259 260
            _ => unreachable!(),
        };
261
        self.cx.trace_macros_diag();
262 263 264 265 266
        krate
    }

    // Fully expand all the invocations in `expansion`.
    fn expand(&mut self, expansion: Expansion) -> Expansion {
267 268 269
        let orig_expansion_data = self.cx.current_expansion.clone();
        self.cx.current_expansion.depth = 0;

270
        let (expansion, mut invocations) = self.collect_invocations(expansion, &[]);
271
        self.resolve_imports();
272 273
        invocations.reverse();

J
Jeffrey Seyfried 已提交
274
        let mut expansions = Vec::new();
275
        let mut derives = HashMap::new();
276 277 278
        let mut undetermined_invocations = Vec::new();
        let (mut progress, mut force) = (false, !self.monotonic);
        loop {
279
            let mut invoc = if let Some(invoc) = invocations.pop() {
280 281
                invoc
            } else {
282 283
                self.resolve_imports();
                if undetermined_invocations.is_empty() { break }
284 285 286 287 288 289 290
                invocations = mem::replace(&mut undetermined_invocations, Vec::new());
                force = !mem::replace(&mut progress, false);
                continue
            };

            let scope =
                if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
291
            let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) {
292 293 294 295 296 297 298 299 300
                Ok(ext) => Some(ext),
                Err(Determinacy::Determined) => None,
                Err(Determinacy::Undetermined) => {
                    undetermined_invocations.push(invoc);
                    continue
                }
            };

            progress = true;
301 302
            let ExpansionData { depth, mark, .. } = invoc.expansion_data;
            self.cx.current_expansion = invoc.expansion_data.clone();
303

304
            self.cx.current_expansion.mark = scope;
305 306 307
            // FIXME(jseyfried): Refactor out the following logic
            let (expansion, new_invocations) = if let Some(ext) = ext {
                if let Some(ext) = ext {
308
                    let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap();
309
                    let expansion = self.expand_invoc(invoc, &*ext).unwrap_or(dummy);
310 311
                    self.collect_invocations(expansion, &[])
                } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind {
312 313
                    if !item.derive_allowed() {
                        let attr = attr::find_by_name(item.attrs(), "derive")
314 315 316 317 318 319 320 321 322 323 324 325
                            .expect("`derive` attribute should exist");
                        let span = attr.span;
                        let mut err = self.cx.mut_span_err(span,
                                                           "`derive` may only be applied to \
                                                            structs, enums and unions");
                        if let ast::AttrStyle::Inner = attr.style {
                            let trait_list = traits.iter()
                                .map(|t| format!("{}", t)).collect::<Vec<_>>();
                            let suggestion = format!("#[derive({})]", trait_list.join(", "));
                            err.span_suggestion(span, "try an outer attribute", suggestion);
                        }
                        err.emit();
326 327
                    }

328
                    let item = self.fully_configure(item)
329
                        .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
330
                    let item_with_markers =
331
                        add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
332 333
                    let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);

J
Jeffrey Seyfried 已提交
334
                    for path in &traits {
J
Jeffrey Seyfried 已提交
335
                        let mark = Mark::fresh(self.cx.current_expansion.mark);
336
                        derives.push(mark);
337
                        let item = match self.cx.resolver.resolve_macro(
J
Jeffrey Seyfried 已提交
338
                                Mark::root(), path, MacroKind::Derive, false) {
339
                            Ok(ext) => match *ext {
340
                                BuiltinDerive(..) => item_with_markers.clone(),
341 342 343 344 345
                                _ => item.clone(),
                            },
                            _ => item.clone(),
                        };
                        invocations.push(Invocation {
J
Jeffrey Seyfried 已提交
346
                            kind: InvocationKind::Derive { path: path.clone(), item: item },
347 348
                            expansion_kind: invoc.expansion_kind,
                            expansion_data: ExpansionData {
349
                                mark,
350 351 352 353 354 355 356 357 358 359 360
                                ..invoc.expansion_data.clone()
                            },
                        });
                    }
                    let expansion = invoc.expansion_kind
                        .expect_from_annotatables(::std::iter::once(item_with_markers));
                    self.collect_invocations(expansion, derives)
                } else {
                    unreachable!()
                }
            } else {
361
                self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[])
362
            };
363

J
Jeffrey Seyfried 已提交
364
            if expansions.len() < depth {
365 366
                expansions.push(Vec::new());
            }
367
            expansions[depth - 1].push((mark, expansion));
368
            if !self.cx.ecfg.single_step {
369 370 371 372
                invocations.extend(new_invocations.into_iter().rev());
            }
        }

373 374
        self.cx.current_expansion = orig_expansion_data;

375
        let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
376 377
        while let Some(expansions) = expansions.pop() {
            for (mark, expansion) in expansions.into_iter().rev() {
378
                let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
379
                placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives);
380 381 382
            }
        }

J
Jeffrey Seyfried 已提交
383
        expansion.fold_with(&mut placeholder_expander)
384 385
    }

386 387 388 389 390 391 392 393
    fn resolve_imports(&mut self) {
        if self.monotonic {
            let err_count = self.cx.parse_sess.span_diagnostic.err_count();
            self.cx.resolver.resolve_imports();
            self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
        }
    }

394 395
    fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark])
                           -> (Expansion, Vec<Invocation>) {
396 397 398 399 400 401 402 403 404
        let result = {
            let mut collector = InvocationCollector {
                cfg: StripUnconfigured {
                    should_test: self.cx.ecfg.should_test,
                    sess: self.cx.parse_sess,
                    features: self.cx.ecfg.features,
                },
                cx: self.cx,
                invocations: Vec::new(),
405
                monotonic: self.monotonic,
406 407 408
            };
            (expansion.fold_with(&mut collector), collector.invocations)
        };
409

410
        if self.monotonic {
411
            let err_count = self.cx.parse_sess.span_diagnostic.err_count();
412
            let mark = self.cx.current_expansion.mark;
413
            self.cx.resolver.visit_expansion(mark, &result.0, derives);
414
            self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
415 416
        }

417
        result
418
    }
419

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
    fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
        let mut cfg = StripUnconfigured {
            should_test: self.cx.ecfg.should_test,
            sess: self.cx.parse_sess,
            features: self.cx.ecfg.features,
        };
        // Since the item itself has already been configured by the InvocationCollector,
        // we know that fold result vector will contain exactly one element
        match item {
            Annotatable::Item(item) => {
                Annotatable::Item(cfg.fold_item(item).pop().unwrap())
            }
            Annotatable::TraitItem(item) => {
                Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap()))
            }
            Annotatable::ImplItem(item) => {
                Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
            }
438 439 440 441 442 443
            Annotatable::Stmt(stmt) => {
                Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
            }
            Annotatable::Expr(expr) => {
                Annotatable::Expr(cfg.fold_expr(expr))
            }
444 445 446
        }
    }

447
    fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<Expansion> {
448
        let result = match invoc.kind {
449 450 451
            InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?,
            InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?,
            InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext)?,
452 453 454 455 456
        };

        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
            let info = self.cx.current_expansion.mark.expn_info().unwrap();
            let suggested_limit = self.cx.ecfg.recursion_limit * 2;
457
            let mut err = self.cx.struct_span_err(info.call_site,
458 459 460 461 462 463
                &format!("recursion limit reached while expanding the macro `{}`",
                         info.callee.name()));
            err.help(&format!(
                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
                suggested_limit));
            err.emit();
464
            self.cx.trace_macros_diag();
465
            FatalError.raise();
466
        }
467

468
        Some(result)
469 470
    }

471 472
    fn expand_attr_invoc(&mut self,
                         invoc: Invocation,
473
                         ext: &SyntaxExtension)
474
                         -> Option<Expansion> {
475 476
        let Invocation { expansion_kind: kind, .. } = invoc;
        let (attr, item) = match invoc.kind {
477
            InvocationKind::Attr { attr, item, .. } => (attr?, item),
478 479 480 481
            _ => unreachable!(),
        };

        attr::mark_used(&attr);
482
        invoc.expansion_data.mark.set_expn_info(ExpnInfo {
483 484
            call_site: attr.span,
            callee: NameAndSpan {
J
Jeffrey Seyfried 已提交
485
                format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
486
                span: None,
487
                allow_internal_unstable: false,
488
                allow_internal_unsafe: false,
489 490 491
            }
        });

492
        match *ext {
493
            MultiModifier(ref mac) => {
494 495
                let meta = attr.parse_meta(self.cx.parse_sess)
                               .map_err(|mut e| { e.emit(); }).ok()?;
496
                let item = mac.expand(self.cx, attr.span, &meta, item);
497
                Some(kind.expect_from_annotatables(item))
498 499 500
            }
            MultiDecorator(ref mac) => {
                let mut items = Vec::new();
501 502
                let meta = attr.parse_meta(self.cx.parse_sess)
                               .expect("derive meta should already have been parsed");
503
                mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item));
504
                items.push(item);
505
                Some(kind.expect_from_annotatables(items))
506
            }
507
            AttrProcMacro(ref mac) => {
J
Jeffrey Seyfried 已提交
508 509
                let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
                    Annotatable::Item(item) => token::NtItem(item),
510 511
                    Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
                    Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
512 513
                    Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
                    Annotatable::Expr(expr) => token::NtExpr(expr),
J
Jeffrey Seyfried 已提交
514 515 516
                })).into();
                let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
                self.parse_expansion(tok_result, kind, &attr.path, attr.span)
517
            }
518
            ProcMacroDerive(..) | BuiltinDerive(..) => {
J
Jeffrey Seyfried 已提交
519
                self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
520
                self.cx.trace_macros_diag();
521 522 523
                kind.dummy(attr.span)
            }
            _ => {
J
Jeffrey Seyfried 已提交
524
                let msg = &format!("macro `{}` may not be used in attributes", attr.path);
525
                self.cx.span_err(attr.span, msg);
526
                self.cx.trace_macros_diag();
527 528
                kind.dummy(attr.span)
            }
529
        }
530 531 532
    }

    /// Expand a macro invocation. Returns the result of expansion.
533 534
    fn expand_bang_invoc(&mut self,
                         invoc: Invocation,
535
                         ext: &SyntaxExtension)
536
                         -> Option<Expansion> {
537
        let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind);
538 539
        let (mac, ident, span) = match invoc.kind {
            InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
540 541
            _ => unreachable!(),
        };
J
Jeffrey Seyfried 已提交
542
        let path = &mac.node.path;
543

544
        let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
545 546
        let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture
                                          def_site_span: Option<Span>,
547
                                          allow_internal_unstable,
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
                                          allow_internal_unsafe,
                                          // can't infer this type
                                          unstable_feature: Option<(Symbol, u32)>| {

            // feature-gate the macro invocation
            if let Some((feature, issue)) = unstable_feature {
                let crate_span = this.cx.current_expansion.crate_span.unwrap();
                // don't stability-check macros in the same crate
                // (the only time this is null is for syntax extensions registered as macros)
                if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
                    && !span.allows_unstable() && this.cx.ecfg.features.map_or(true, |feats| {
                    // macro features will count as lib features
                    !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
                }) {
                    let explain = format!("macro {}! is unstable", path);
                    emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span,
                                     GateIssue::Library(Some(issue)), &explain);
                    this.cx.trace_macros_diag();
                    return Err(kind.dummy(span));
                }
            }

J
Jeffrey Seyfried 已提交
570
            if ident.name != keywords::Invalid.name() {
571 572 573 574
                let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident);
                this.cx.span_err(path.span, &msg);
                this.cx.trace_macros_diag();
                return Err(kind.dummy(span));
J
Jeffrey Seyfried 已提交
575 576 577 578
            }
            mark.set_expn_info(ExpnInfo {
                call_site: span,
                callee: NameAndSpan {
579
                    format: macro_bang_format(path),
J
Jeffrey Seyfried 已提交
580
                    span: def_site_span,
581 582
                    allow_internal_unstable,
                    allow_internal_unsafe,
J
Jeffrey Seyfried 已提交
583 584 585 586 587
                },
            });
            Ok(())
        };

588
        let opt_expanded = match *ext {
589
            DeclMacro(ref expand, def_span) => {
590 591 592
                if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
                                                                    false, false, None) {
                    dummy_span
593 594
                } else {
                    kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
595
                }
J
Jeffrey Seyfried 已提交
596
            }
597

598 599 600 601
            NormalTT {
                ref expander,
                def_info,
                allow_internal_unstable,
602 603
                allow_internal_unsafe,
                unstable_feature,
604
            } => {
605 606 607 608 609
                if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
                                                                    allow_internal_unstable,
                                                                    allow_internal_unsafe,
                                                                    unstable_feature) {
                    dummy_span
610 611
                } else {
                    kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
J
Jeffrey Seyfried 已提交
612
                }
613 614 615 616 617
            }

            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                if ident.name == keywords::Invalid.name() {
                    self.cx.span_err(path.span,
J
Jeffrey Seyfried 已提交
618
                                    &format!("macro {}! expects an ident argument", path));
619
                    self.cx.trace_macros_diag();
620 621 622 623 624 625 626 627 628 629 630
                    kind.dummy(span)
                } else {
                    invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
                            format: macro_bang_format(path),
                            span: tt_span,
                            allow_internal_unstable,
                            allow_internal_unsafe: false,
                        }
                    });
631

632 633 634
                    let input: Vec<_> = mac.node.stream().into_trees().collect();
                    kind.make_from(expander.expand(self.cx, span, ident, input))
                }
635 636
            }

637
            MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
638
                self.cx.span_err(path.span,
J
Jeffrey Seyfried 已提交
639
                                 &format!("`{}` can only be used in attributes", path));
640
                self.cx.trace_macros_diag();
641
                kind.dummy(span)
642
            }
643

644
            ProcMacroDerive(..) | BuiltinDerive(..) => {
J
Jeffrey Seyfried 已提交
645
                self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
646
                self.cx.trace_macros_diag();
647
                kind.dummy(span)
648 649
            }

650
            ProcMacro(ref expandfun) => {
651 652
                if ident.name != keywords::Invalid.name() {
                    let msg =
J
Jeffrey Seyfried 已提交
653
                        format!("macro {}! expects no ident argument, given '{}'", path, ident);
N
Nick Cameron 已提交
654
                    self.cx.span_err(path.span, &msg);
655
                    self.cx.trace_macros_diag();
656 657 658 659 660 661 662 663 664 665 666 667 668 669
                    kind.dummy(span)
                } else {
                    invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
                            format: macro_bang_format(path),
                            // FIXME procedural macros do not have proper span info
                            // yet, when they do, we should use it here.
                            span: None,
                            // FIXME probably want to follow macro_rules macros here.
                            allow_internal_unstable: false,
                            allow_internal_unsafe: false,
                        },
                    });
670

671 672 673
                    let tok_result = expandfun.expand(self.cx, span, mac.node.stream());
                    self.parse_expansion(tok_result, kind, path, span)
                }
674
            }
675 676
        };

677 678 679
        if opt_expanded.is_some() {
            opt_expanded
        } else {
680 681 682
            let msg = format!("non-{kind} macro in {kind} position: {name}",
                              name = path.segments[0].identifier.name, kind = kind.name());
            self.cx.span_err(path.span, &msg);
683
            self.cx.trace_macros_diag();
684
            kind.dummy(span)
685
        }
686
    }
J
Jeffrey Seyfried 已提交
687

688
    /// Expand a derive invocation. Returns the result of expansion.
689 690
    fn expand_derive_invoc(&mut self,
                           invoc: Invocation,
691
                           ext: &SyntaxExtension)
692
                           -> Option<Expansion> {
693
        let Invocation { expansion_kind: kind, .. } = invoc;
J
Jeffrey Seyfried 已提交
694 695
        let (path, item) = match invoc.kind {
            InvocationKind::Derive { path, item } => (path, item),
696 697
            _ => unreachable!(),
        };
698 699 700
        if !item.derive_allowed() {
            return None;
        }
701

J
Jeffrey Seyfried 已提交
702 703 704
        let pretty_name = Symbol::intern(&format!("derive({})", path));
        let span = path.span;
        let attr = ast::Attribute {
705 706
            path, span,
            tokens: TokenStream::empty(),
J
Jeffrey Seyfried 已提交
707 708 709
            // irrelevant:
            id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
        };
710

711
        let mut expn_info = ExpnInfo {
712
            call_site: span,
713
            callee: NameAndSpan {
714
                format: MacroAttribute(pretty_name),
J
Jeffrey Seyfried 已提交
715
                span: None,
716
                allow_internal_unstable: false,
717
                allow_internal_unsafe: false,
718
            }
719
        };
720 721

        match *ext {
722
            ProcMacroDerive(ref ext, _) => {
723
                invoc.expansion_data.mark.set_expn_info(expn_info);
724
                let span = span.with_ctxt(self.cx.backtrace());
J
Jeffrey Seyfried 已提交
725 726 727 728 729
                let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
                    name: keywords::Invalid.name(),
                    span: DUMMY_SP,
                    node: ast::MetaItemKind::Word,
                };
730
                Some(kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)))
731
            }
732
            BuiltinDerive(func) => {
733 734
                expn_info.callee.allow_internal_unstable = true;
                invoc.expansion_data.mark.set_expn_info(expn_info);
735
                let span = span.with_ctxt(self.cx.backtrace());
736
                let mut items = Vec::new();
737 738
                func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a));
                Some(kind.expect_from_annotatables(items))
739 740
            }
            _ => {
J
Jeffrey Seyfried 已提交
741
                let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
742
                self.cx.span_err(span, msg);
743
                self.cx.trace_macros_diag();
744
                kind.dummy(span)
745 746 747 748
            }
        }
    }

749 750 751 752 753 754
    fn parse_expansion(&mut self,
                       toks: TokenStream,
                       kind: ExpansionKind,
                       path: &Path,
                       span: Span)
                       -> Option<Expansion> {
755
        let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>());
756 757 758 759 760
        match parser.parse_expansion(kind, false) {
            Ok(expansion) => {
                parser.ensure_complete_parse(path, kind.name(), span);
                Some(expansion)
            }
J
Jeffrey Seyfried 已提交
761
            Err(mut err) => {
762
                err.set_span(span);
J
Jeffrey Seyfried 已提交
763
                err.emit();
764
                self.cx.trace_macros_diag();
765
                kind.dummy(span)
J
Jeffrey Seyfried 已提交
766
            }
767
        }
J
Jeffrey Seyfried 已提交
768
    }
769 770
}

771
impl<'a> Parser<'a> {
J
Jeffrey Seyfried 已提交
772 773
    pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool)
                           -> PResult<'a, Expansion> {
774 775
        Ok(match kind {
            ExpansionKind::Items => {
776
                let mut items = SmallVector::new();
777 778 779 780 781 782
                while let Some(item) = self.parse_item()? {
                    items.push(item);
                }
                Expansion::Items(items)
            }
            ExpansionKind::TraitItems => {
783
                let mut items = SmallVector::new();
784
                while self.token != token::Eof {
785
                    items.push(self.parse_trait_item(&mut false)?);
786 787 788 789
                }
                Expansion::TraitItems(items)
            }
            ExpansionKind::ImplItems => {
790
                let mut items = SmallVector::new();
791
                while self.token != token::Eof {
792
                    items.push(self.parse_impl_item(&mut false)?);
793 794 795 796
                }
                Expansion::ImplItems(items)
            }
            ExpansionKind::Stmts => {
797
                let mut stmts = SmallVector::new();
G
Geoffry Song 已提交
798 799 800
                while self.token != token::Eof &&
                      // won't make progress on a `}`
                      self.token != token::CloseDelim(token::Brace) {
J
Jeffrey Seyfried 已提交
801
                    if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? {
802 803 804 805 806 807
                        stmts.push(stmt);
                    }
                }
                Expansion::Stmts(stmts)
            }
            ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?),
808 809 810 811 812 813 814
            ExpansionKind::OptExpr => {
                if self.token != token::Eof {
                    Expansion::OptExpr(Some(self.parse_expr()?))
                } else {
                    Expansion::OptExpr(None)
                }
            },
815
            ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?),
816 817 818
            ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?),
        })
    }
819

J
Jeffrey Seyfried 已提交
820
    pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) {
821 822 823
        if self.token != token::Eof {
            let msg = format!("macro expansion ignores token `{}` and any following",
                              self.this_token_to_string());
824 825
            // Avoid emitting backtrace info twice.
            let def_site_span = self.span.with_ctxt(SyntaxContext::empty());
826
            let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
827 828
            let msg = format!("caused by the macro expansion here; the usage \
                               of `{}!` is likely invalid in {} context",
J
Jeffrey Seyfried 已提交
829
                               macro_path, kind_name);
830 831 832
            err.span_note(span, &msg).emit();
        }
    }
833 834 835 836
}

struct InvocationCollector<'a, 'b: 'a> {
    cx: &'a mut ExtCtxt<'b>,
837
    cfg: StripUnconfigured<'a>,
838
    invocations: Vec<Invocation>,
839
    monotonic: bool,
840 841 842 843
}

impl<'a, 'b> InvocationCollector<'a, 'b> {
    fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
J
Jeffrey Seyfried 已提交
844
        let mark = Mark::fresh(self.cx.current_expansion.mark);
845
        self.invocations.push(Invocation {
846 847
            kind,
            expansion_kind,
J
Jeffrey Seyfried 已提交
848
            expansion_data: ExpansionData {
849
                mark,
J
Jeffrey Seyfried 已提交
850 851 852
                depth: self.cx.current_expansion.depth + 1,
                ..self.cx.current_expansion.clone()
            },
853
        });
854
        placeholder(expansion_kind, NodeId::placeholder_from_mark(mark))
855
    }
856

857 858
    fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion {
        self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
859
    }
860

861 862
    fn collect_attr(&mut self,
                    attr: Option<ast::Attribute>,
J
Jeffrey Seyfried 已提交
863
                    traits: Vec<Path>,
864 865
                    item: Annotatable,
                    kind: ExpansionKind)
866
                    -> Expansion {
867
        self.collect(kind, InvocationKind::Attr { attr, traits, item })
868 869 870
    }

    // If `item` is an attr invocation, remove and return the macro attribute.
J
Jeffrey Seyfried 已提交
871
    fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T)
872 873 874
        where T: HasAttrs,
    {
        let (mut attr, mut traits) = (None, Vec::new());
875

876
        item = item.map_attrs(|mut attrs| {
877 878 879 880
            if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs) {
                attr = Some(legacy_attr_invoc);
                return attrs;
            }
881

882 883 884 885
            if self.cx.ecfg.proc_macro_enabled() {
                attr = find_attr_invoc(&mut attrs);
            }
            traits = collect_derives(&mut self.cx, &mut attrs);
886 887
            attrs
        });
888

889
        (attr, traits, item)
890 891
    }

892 893 894
    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
        self.cfg.configure(node)
    }
895 896 897 898 899 900

    // Detect use of feature-gated or invalid attributes on macro invocations
    // since they will not be detected after macro expansion.
    fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
        let features = self.cx.ecfg.features.unwrap();
        for attr in attrs.iter() {
901
            feature_gate::check_attribute(attr, self.cx.parse_sess, features);
902 903
        }
    }
904 905 906 907 908

    fn check_attribute(&mut self, at: &ast::Attribute) {
        let features = self.cx.ecfg.features.unwrap();
        feature_gate::check_attribute(at, self.cx.parse_sess, features);
    }
909 910
}

911
pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
912 913 914
    attrs.iter()
         .position(|a| !attr::is_known(a) && !is_builtin_attr(a))
         .map(|i| attrs.remove(i))
915 916
}

917
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
918
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
919
        let mut expr = self.cfg.configure_expr(expr).into_inner();
920 921
        expr.node = self.cfg.configure_expr_kind(expr.node);

922 923 924 925 926 927 928 929 930 931 932 933
        let (attr, derives, expr) = self.classify_item(expr);

        if attr.is_some() || !derives.is_empty() {
            // collect the invoc regardless of whether or not attributes are permitted here
            // expansion will eat the attribute so it won't error later
            attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));

            // ExpansionKind::Expr requires the macro to emit an expression
            return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)), ExpansionKind::Expr)
                .make_expr();
        }

934
        if let ast::ExprKind::Mac(mac) = expr.node {
935 936
            self.check_attributes(&expr.attrs);
            self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr()
937 938 939
        } else {
            P(noop_fold_expr(expr, self))
        }
940 941
    }

942
    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
943
        let mut expr = configure!(self, expr).into_inner();
944 945
        expr.node = self.cfg.configure_expr_kind(expr.node);

946 947 948 949 950 951 952 953 954 955
        let (attr, derives, expr) = self.classify_item(expr);

        if attr.is_some() || !derives.is_empty() {
            attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));

            return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)),
                                     ExpansionKind::OptExpr)
                .make_opt_expr();
        }

956
        if let ast::ExprKind::Mac(mac) = expr.node {
957 958
            self.check_attributes(&expr.attrs);
            self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr()
959 960 961
        } else {
            Some(P(noop_fold_expr(expr, self)))
        }
962 963
    }

964
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
965
        let pat = self.cfg.configure_pat(pat);
966 967
        match pat.node {
            PatKind::Mac(_) => {}
968
            _ => return noop_fold_pat(pat, self),
969
        }
K
Keegan McAllister 已提交
970

971
        pat.and_then(|pat| match pat.node {
972
            PatKind::Mac(mac) => self.collect_bang(mac, pat.span, ExpansionKind::Pat).make_pat(),
973 974
            _ => unreachable!(),
        })
975 976
    }

977
    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
978
        let mut stmt = match self.cfg.configure_stmt(stmt) {
979
            Some(stmt) => stmt,
980
            None => return SmallVector::new(),
981 982
        };

983 984 985 986 987 988 989 990 991
        // we'll expand attributes on expressions separately
        if !stmt.is_expr() {
            let (attr, derives, stmt_) = self.classify_item(stmt);

            if attr.is_some() || !derives.is_empty() {
                return self.collect_attr(attr, derives,
                                         Annotatable::Stmt(P(stmt_)), ExpansionKind::Stmts)
                    .make_stmts();
            }
992

993 994
            stmt = stmt_;
        }
995

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
        if let StmtKind::Mac(mac) = stmt.node {
            let (mac, style, attrs) = mac.into_inner();
            self.check_attributes(&attrs);
            let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts)
                                        .make_stmts();

            // If this is a macro invocation with a semicolon, then apply that
            // semicolon to the final statement produced by expansion.
            if style == MacStmtStyle::Semicolon {
                if let Some(stmt) = placeholder.pop() {
                    placeholder.push(stmt.add_trailing_semicolon());
                }
1008
            }
1009 1010

            return placeholder;
1011 1012
        }

1013 1014 1015 1016 1017 1018
        // The placeholder expander gives ids to statements, so we avoid folding the id here.
        let ast::Stmt { id, node, span } = stmt;
        noop_fold_stmt_kind(node, self).into_iter().map(|node| {
            ast::Stmt { id, node, span }
        }).collect()

1019 1020
    }

S
Steven Fackler 已提交
1021
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1022 1023
        let old_directory_ownership = self.cx.current_expansion.directory_ownership;
        self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock;
J
Jeffrey Seyfried 已提交
1024
        let result = noop_fold_block(block, self);
1025
        self.cx.current_expansion.directory_ownership = old_directory_ownership;
1026
        result
1027 1028
    }

1029
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1030 1031
        let item = configure!(self, item);

1032 1033
        let (attr, traits, mut item) = self.classify_item(item);
        if attr.is_some() || !traits.is_empty() {
1034
            let item = Annotatable::Item(item);
1035
            return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items();
1036 1037 1038 1039
        }

        match item.node {
            ast::ItemKind::Mac(..) => {
1040
                self.check_attributes(&item.attrs);
1041
                item.and_then(|item| match item.node {
1042
                    ItemKind::Mac(mac) => {
1043
                        self.collect(ExpansionKind::Items, InvocationKind::Bang {
1044
                            mac,
1045 1046
                            ident: Some(item.ident),
                            span: item.span,
1047
                        }).make_items()
1048 1049 1050 1051 1052
                    }
                    _ => unreachable!(),
                })
            }
            ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
1053 1054 1055 1056
                if item.ident == keywords::Invalid.ident() {
                    return noop_fold_item(item, self);
                }

1057
                let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
1058 1059
                let mut module = (*self.cx.current_expansion.module).clone();
                module.mod_path.push(item.ident);
1060 1061 1062 1063

                // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
                // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
                // Thus, if `inner` is the dummy span, we know the module is inline.
J
Jeffrey Seyfried 已提交
1064
                let inline_module = item.span.contains(inner) || inner == DUMMY_SP;
1065 1066

                if inline_module {
1067
                    if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
1068 1069
                        self.cx.current_expansion.directory_ownership =
                            DirectoryOwnership::Owned { relative: None };
1070
                        module.directory.push(&*path.as_str());
1071 1072 1073
                    } else {
                        module.directory.push(&*item.ident.name.as_str());
                    }
1074
                } else {
1075 1076 1077 1078 1079
                    let path = self.cx.parse_sess.codemap().span_to_unmapped_path(inner);
                    let mut path = match path {
                        FileName::Real(path) => path,
                        other => PathBuf::from(other.to_string()),
                    };
1080
                    let directory_ownership = match path.file_name().unwrap().to_str() {
1081 1082 1083 1084 1085
                        Some("mod.rs") => DirectoryOwnership::Owned { relative: None },
                        Some(_) => DirectoryOwnership::Owned {
                            relative: Some(item.ident),
                        },
                        None => DirectoryOwnership::UnownedViaMod(false),
1086 1087 1088 1089
                    };
                    path.pop();
                    module.directory = path;
                    self.cx.current_expansion.directory_ownership = directory_ownership;
1090 1091
                }

1092 1093
                let orig_module =
                    mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
J
Jeffrey Seyfried 已提交
1094
                let result = noop_fold_item(item, self);
1095
                self.cx.current_expansion.module = orig_module;
1096
                self.cx.current_expansion.directory_ownership = orig_directory_ownership;
1097
                result
1098
            }
1099 1100 1101
            // Ensure that test functions are accessible from the test harness.
            ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
                if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
1102 1103 1104 1105
                    item = item.map(|mut item| {
                        item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
                        item
                    });
1106 1107 1108
                }
                noop_fold_item(item, self)
            }
1109 1110
            _ => noop_fold_item(item, self),
        }
1111 1112
    }

1113
    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
1114 1115
        let item = configure!(self, item);

1116 1117
        let (attr, traits, item) = self.classify_item(item);
        if attr.is_some() || !traits.is_empty() {
1118
            let item = Annotatable::TraitItem(P(item));
1119 1120
            return self.collect_attr(attr, traits, item, ExpansionKind::TraitItems)
                .make_trait_items()
1121 1122 1123 1124 1125
        }

        match item.node {
            ast::TraitItemKind::Macro(mac) => {
                let ast::TraitItem { attrs, span, .. } = item;
1126 1127
                self.check_attributes(&attrs);
                self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items()
1128 1129 1130 1131 1132 1133
            }
            _ => fold::noop_fold_trait_item(item, self),
        }
    }

    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
1134 1135
        let item = configure!(self, item);

1136 1137
        let (attr, traits, item) = self.classify_item(item);
        if attr.is_some() || !traits.is_empty() {
1138
            let item = Annotatable::ImplItem(P(item));
1139 1140
            return self.collect_attr(attr, traits, item, ExpansionKind::ImplItems)
                .make_impl_items();
1141 1142 1143 1144 1145
        }

        match item.node {
            ast::ImplItemKind::Macro(mac) => {
                let ast::ImplItem { attrs, span, .. } = item;
1146 1147
                self.check_attributes(&attrs);
                self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items()
1148
            }
1149
            _ => fold::noop_fold_impl_item(item, self),
1150
        }
1151 1152
    }

1153
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
1154
        let ty = match ty.node {
1155
            ast::TyKind::Mac(_) => ty.into_inner(),
1156 1157 1158 1159
            _ => return fold::noop_fold_ty(ty, self),
        };

        match ty.node {
1160
            ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, ExpansionKind::Ty).make_ty(),
1161 1162
            _ => unreachable!(),
        }
1163
    }
1164 1165 1166 1167 1168 1169

    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
        noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self)
    }

    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
1170 1171 1172 1173
        match item {
            ast::ItemKind::MacroDef(..) => item,
            _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self),
        }
1174
    }
1175

1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
    fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> {
        // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
        // contents="file contents")]` attributes
        if !at.check_name("doc") {
            return noop_fold_attribute(at, self);
        }

        if let Some(list) = at.meta_item_list() {
            if !list.iter().any(|it| it.check_name("include")) {
                return noop_fold_attribute(at, self);
            }

            let mut items = vec![];

            for it in list {
                if !it.check_name("include") {
                    items.push(noop_fold_meta_list_item(it, self));
                    continue;
                }

                if let Some(file) = it.value_str() {
                    let err_count = self.cx.parse_sess.span_diagnostic.err_count();
                    self.check_attribute(&at);
                    if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
                        // avoid loading the file if they haven't enabled the feature
                        return noop_fold_attribute(at, self);
                    }

                    let mut buf = vec![];
                    let filename = self.cx.root_path.join(file.to_string());

                    match File::open(&filename).and_then(|mut f| f.read_to_end(&mut buf)) {
                        Ok(..) => {}
                        Err(e) => {
1210 1211 1212 1213
                            self.cx.span_err(at.span,
                                             &format!("couldn't read {}: {}",
                                                      filename.display(),
                                                      e));
1214 1215 1216 1217 1218
                        }
                    }

                    match String::from_utf8(buf) {
                        Ok(src) => {
1219 1220 1221 1222
                            // Add this input file to the code map to make it available as
                            // dependency information
                            self.cx.codemap().new_filemap_and_lines(&filename, &src);

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
                            let include_info = vec![
                                dummy_spanned(ast::NestedMetaItemKind::MetaItem(
                                        attr::mk_name_value_item_str("file".into(),
                                                                     file))),
                                dummy_spanned(ast::NestedMetaItemKind::MetaItem(
                                        attr::mk_name_value_item_str("contents".into(),
                                                                     (&*src).into()))),
                            ];

                            items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem(
                                        attr::mk_list_item("include".into(), include_info))));
                        }
                        Err(_) => {
1236 1237 1238
                            self.cx.span_err(at.span,
                                             &format!("{} wasn't a utf-8 file",
                                                      filename.display()));
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
                        }
                    }
                } else {
                    items.push(noop_fold_meta_list_item(it, self));
                }
            }

            let meta = attr::mk_list_item("doc".into(), items);
            match at.style {
                ast::AttrStyle::Inner =>
                    Some(attr::mk_spanned_attr_inner(at.span, at.id, meta)),
                ast::AttrStyle::Outer =>
                    Some(attr::mk_spanned_attr_outer(at.span, at.id, meta)),
            }
        } else {
            noop_fold_attribute(at, self)
        }
    }

1258
    fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
1259 1260 1261 1262 1263 1264
        if self.monotonic {
            assert_eq!(id, ast::DUMMY_NODE_ID);
            self.cx.resolver.next_node_id()
        } else {
            id
        }
1265
    }
1266 1267
}

1268
pub struct ExpansionConfig<'feat> {
1269
    pub crate_name: String,
1270
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1271
    pub recursion_limit: usize,
1272
    pub trace_mac: bool,
1273
    pub should_test: bool, // If false, strip `#[test]` nodes
1274 1275
    pub single_step: bool,
    pub keep_macs: bool,
1276 1277
}

1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1291 1292
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1293
        ExpansionConfig {
1294
            crate_name,
1295
            features: None,
1296
            recursion_limit: 1024,
1297
            trace_mac: false,
1298
            should_test: false,
1299 1300
            single_step: false,
            keep_macs: false,
1301 1302
        }
    }
1303

1304
    feature_tests! {
1305 1306
        fn enable_quotes = quote,
        fn enable_asm = asm,
1307
        fn enable_global_asm = global_asm,
1308 1309 1310
        fn enable_log_syntax = log_syntax,
        fn enable_concat_idents = concat_idents,
        fn enable_trace_macros = trace_macros,
1311
        fn enable_allow_internal_unstable = allow_internal_unstable,
1312
        fn enable_custom_derive = custom_derive,
1313
        fn proc_macro_enabled = proc_macro,
1314
    }
1315 1316
}

1317
// A Marker adds the given mark to the syntax context.
1318
#[derive(Debug)]
1319
pub struct Marker(pub Mark);
1320

E
Eduard Burtescu 已提交
1321
impl Folder for Marker {
1322
    fn fold_ident(&mut self, mut ident: Ident) -> Ident {
1323
        ident.ctxt = ident.ctxt.apply_mark(self.0);
1324 1325
        ident
    }
1326

1327 1328
    fn new_span(&mut self, span: Span) -> Span {
        span.with_ctxt(span.ctxt().apply_mark(self.0))
1329
    }
1330 1331 1332 1333

    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        noop_fold_mac(mac, self)
    }
1334
}