]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
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. | |
10 | ||
cc61c64b XL |
11 | use ast::{self, Block, Ident, NodeId, PatKind, Path}; |
12 | use ast::{MacStmtStyle, StmtKind, ItemKind}; | |
5bcae85e | 13 | use attr::{self, HasAttrs}; |
9e0c209e | 14 | use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; |
c30ab7b3 | 15 | use config::{is_test_or_bench, StripUnconfigured}; |
cc61c64b | 16 | use errors::FatalError; |
223e47cc | 17 | use ext::base::*; |
8bb4bdeb | 18 | use ext::derive::{add_derived_markers, collect_derives}; |
041b39d2 | 19 | use ext::hygiene::{Mark, SyntaxContext}; |
8bb4bdeb XL |
20 | use ext::placeholders::{placeholder, PlaceholderExpander}; |
21 | use feature_gate::{self, Features, is_builtin_attr}; | |
1a4d82fc | 22 | use fold; |
223e47cc | 23 | use fold::*; |
041b39d2 XL |
24 | use parse::{DirectoryOwnership, PResult}; |
25 | use parse::token::{self, Token}; | |
9e0c209e | 26 | use parse::parser::Parser; |
1a4d82fc | 27 | use ptr::P; |
c30ab7b3 | 28 | use std_inject; |
8bb4bdeb | 29 | use symbol::Symbol; |
476ff2be | 30 | use symbol::keywords; |
cc61c64b | 31 | use syntax_pos::{Span, DUMMY_SP}; |
abe05a73 | 32 | use syntax_pos::hygiene::ExpnFormat; |
041b39d2 | 33 | use tokenstream::{TokenStream, TokenTree}; |
1a4d82fc | 34 | use util::small_vector::SmallVector; |
970d7e83 | 35 | use visit::Visitor; |
223e47cc | 36 | |
8bb4bdeb | 37 | use std::collections::HashMap; |
9e0c209e | 38 | use std::mem; |
9e0c209e SL |
39 | use std::rc::Rc; |
40 | ||
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), )* } | |
48 | ||
49 | impl ExpansionKind { | |
50 | pub fn name(self) -> &'static str { | |
51 | match self { | |
52 | ExpansionKind::OptExpr => "expression", | |
53 | $( ExpansionKind::$kind => $kind_name, )* | |
54 | } | |
55 | } | |
92a42be0 | 56 | |
9e0c209e SL |
57 | fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<Expansion> { |
58 | match self { | |
59 | ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr), | |
60 | $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )* | |
61 | } | |
62 | } | |
63 | } | |
1a4d82fc | 64 | |
9e0c209e SL |
65 | impl Expansion { |
66 | pub fn make_opt_expr(self) -> Option<P<ast::Expr>> { | |
67 | match self { | |
68 | Expansion::OptExpr(expr) => expr, | |
69 | _ => panic!("Expansion::make_* called on the wrong kind of expansion"), | |
70 | } | |
71 | } | |
72 | $( pub fn $make(self) -> $ty { | |
73 | match self { | |
74 | Expansion::$kind(ast) => ast, | |
75 | _ => panic!("Expansion::make_* called on the wrong kind of expansion"), | |
76 | } | |
77 | } )* | |
78 | ||
79 | pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self { | |
80 | use self::Expansion::*; | |
81 | match self { | |
82 | OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))), | |
83 | $($( $kind(ast) => $kind(folder.$fold(ast)), )*)* | |
84 | $($( $kind(ast) => { | |
85 | $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect()) | |
86 | }, )*)* | |
87 | } | |
88 | } | |
1a4d82fc | 89 | |
476ff2be | 90 | pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { |
9e0c209e SL |
91 | match *self { |
92 | Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), | |
93 | Expansion::OptExpr(None) => {} | |
94 | $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* | |
476ff2be | 95 | $($( Expansion::$kind(ref ast) => for ast in &ast[..] { |
9e0c209e SL |
96 | visitor.$visit_elt(ast); |
97 | }, )*)* | |
98 | } | |
3157f602 | 99 | } |
9e0c209e SL |
100 | } |
101 | ||
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() | |
3157f602 | 105 | } |
9e0c209e SL |
106 | $($(fn $fold(&mut self, node: $ty) -> $ty { |
107 | self.expand(Expansion::$kind(node)).$make() | |
108 | })*)* | |
109 | $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty { | |
110 | self.expand(Expansion::$kind(SmallVector::one(node))).$make() | |
111 | })*)* | |
112 | } | |
113 | ||
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()) | |
117 | })* | |
1a4d82fc | 118 | } |
9e0c209e | 119 | } |
3157f602 | 120 | } |
1a4d82fc | 121 | |
9e0c209e SL |
122 | expansions! { |
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], | |
3157f602 | 131 | "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; |
9e0c209e | 132 | ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem], |
3157f602 XL |
133 | "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; |
134 | } | |
c1a9b12d | 135 | |
9e0c209e SL |
136 | impl ExpansionKind { |
137 | fn dummy(self, span: Span) -> Expansion { | |
138 | self.make_from(DummyResult::any(span)).unwrap() | |
139 | } | |
140 | ||
141 | fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) -> Expansion { | |
142 | let items = items.into_iter(); | |
143 | match self { | |
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()), | |
150 | _ => unreachable!(), | |
151 | } | |
3157f602 XL |
152 | } |
153 | } | |
154 | ||
abe05a73 XL |
155 | fn macro_bang_format(path: &ast::Path) -> ExpnFormat { |
156 | // We don't want to format a path using pretty-printing, | |
157 | // `format!("{}", path)`, because that tries to insert | |
158 | // line-breaks and is slow. | |
159 | let mut path_str = String::with_capacity(64); | |
160 | for (i, segment) in path.segments.iter().enumerate() { | |
161 | if i != 0 { | |
162 | path_str.push_str("::"); | |
163 | } | |
164 | ||
165 | if segment.identifier.name != keywords::CrateRoot.name() && | |
166 | segment.identifier.name != keywords::DollarCrate.name() | |
167 | { | |
168 | path_str.push_str(&segment.identifier.name.as_str()) | |
169 | } | |
170 | } | |
171 | ||
172 | MacroBang(Symbol::intern(&path_str)) | |
173 | } | |
174 | ||
9e0c209e SL |
175 | pub struct Invocation { |
176 | pub kind: InvocationKind, | |
177 | expansion_kind: ExpansionKind, | |
8bb4bdeb | 178 | pub expansion_data: ExpansionData, |
9e0c209e SL |
179 | } |
180 | ||
181 | pub enum InvocationKind { | |
182 | Bang { | |
9e0c209e SL |
183 | mac: ast::Mac, |
184 | ident: Option<Ident>, | |
185 | span: Span, | |
186 | }, | |
187 | Attr { | |
8bb4bdeb | 188 | attr: Option<ast::Attribute>, |
cc61c64b | 189 | traits: Vec<Path>, |
8bb4bdeb XL |
190 | item: Annotatable, |
191 | }, | |
192 | Derive { | |
cc61c64b | 193 | path: Path, |
9e0c209e SL |
194 | item: Annotatable, |
195 | }, | |
196 | } | |
197 | ||
198 | impl Invocation { | |
199 | fn span(&self) -> Span { | |
200 | match self.kind { | |
201 | InvocationKind::Bang { span, .. } => span, | |
8bb4bdeb | 202 | InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, |
cc61c64b XL |
203 | InvocationKind::Attr { attr: None, .. } => DUMMY_SP, |
204 | InvocationKind::Derive { ref path, .. } => path.span, | |
c1a9b12d | 205 | } |
5bcae85e SL |
206 | } |
207 | } | |
c1a9b12d | 208 | |
9e0c209e SL |
209 | pub struct MacroExpander<'a, 'b:'a> { |
210 | pub cx: &'a mut ExtCtxt<'b>, | |
211 | monotonic: bool, // c.f. `cx.monotonic_expander()` | |
212 | } | |
213 | ||
214 | impl<'a, 'b> MacroExpander<'a, 'b> { | |
215 | pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { | |
216 | MacroExpander { cx: cx, monotonic: monotonic } | |
217 | } | |
218 | ||
c30ab7b3 SL |
219 | pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { |
220 | self.cx.crate_root = std_inject::injected_crate_name(&krate); | |
221 | let mut module = ModuleData { | |
476ff2be | 222 | mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], |
ea8adc8c | 223 | directory: self.cx.codemap().span_to_unmapped_path(krate.span), |
c30ab7b3 SL |
224 | }; |
225 | module.directory.pop(); | |
226 | self.cx.current_expansion.module = Rc::new(module); | |
9e0c209e | 227 | |
cc61c64b XL |
228 | let orig_mod_span = krate.module.inner; |
229 | ||
9e0c209e SL |
230 | let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { |
231 | attrs: krate.attrs, | |
232 | span: krate.span, | |
233 | node: ast::ItemKind::Mod(krate.module), | |
5bcae85e | 234 | ident: keywords::Invalid.ident(), |
5bcae85e | 235 | id: ast::DUMMY_NODE_ID, |
9e0c209e | 236 | vis: ast::Visibility::Public, |
3b2f2976 | 237 | tokens: None, |
9e0c209e SL |
238 | }))); |
239 | ||
cc61c64b XL |
240 | match self.expand(krate_item).make_items().pop().map(P::unwrap) { |
241 | Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => { | |
9e0c209e SL |
242 | krate.attrs = attrs; |
243 | krate.module = module; | |
244 | }, | |
cc61c64b XL |
245 | None => { |
246 | // Resolution failed so we return an empty expansion | |
247 | krate.attrs = vec![]; | |
248 | krate.module = ast::Mod { | |
249 | inner: orig_mod_span, | |
250 | items: vec![], | |
251 | }; | |
252 | }, | |
9e0c209e SL |
253 | _ => unreachable!(), |
254 | }; | |
7cac9316 | 255 | self.cx.trace_macros_diag(); |
9e0c209e | 256 | krate |
5bcae85e | 257 | } |
1a4d82fc | 258 | |
9e0c209e SL |
259 | // Fully expand all the invocations in `expansion`. |
260 | fn expand(&mut self, expansion: Expansion) -> Expansion { | |
261 | let orig_expansion_data = self.cx.current_expansion.clone(); | |
262 | self.cx.current_expansion.depth = 0; | |
263 | ||
8bb4bdeb | 264 | let (expansion, mut invocations) = self.collect_invocations(expansion, &[]); |
476ff2be | 265 | self.resolve_imports(); |
9e0c209e SL |
266 | invocations.reverse(); |
267 | ||
c30ab7b3 | 268 | let mut expansions = Vec::new(); |
8bb4bdeb | 269 | let mut derives = HashMap::new(); |
c30ab7b3 SL |
270 | let mut undetermined_invocations = Vec::new(); |
271 | let (mut progress, mut force) = (false, !self.monotonic); | |
272 | loop { | |
8bb4bdeb | 273 | let mut invoc = if let Some(invoc) = invocations.pop() { |
c30ab7b3 | 274 | invoc |
c30ab7b3 | 275 | } else { |
476ff2be SL |
276 | self.resolve_imports(); |
277 | if undetermined_invocations.is_empty() { break } | |
c30ab7b3 SL |
278 | invocations = mem::replace(&mut undetermined_invocations, Vec::new()); |
279 | force = !mem::replace(&mut progress, false); | |
280 | continue | |
281 | }; | |
282 | ||
283 | let scope = | |
284 | if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; | |
8bb4bdeb | 285 | let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { |
c30ab7b3 SL |
286 | Ok(ext) => Some(ext), |
287 | Err(Determinacy::Determined) => None, | |
288 | Err(Determinacy::Undetermined) => { | |
289 | undetermined_invocations.push(invoc); | |
290 | continue | |
291 | } | |
292 | }; | |
293 | ||
294 | progress = true; | |
9e0c209e SL |
295 | let ExpansionData { depth, mark, .. } = invoc.expansion_data; |
296 | self.cx.current_expansion = invoc.expansion_data.clone(); | |
297 | ||
9e0c209e | 298 | self.cx.current_expansion.mark = scope; |
8bb4bdeb XL |
299 | // FIXME(jseyfried): Refactor out the following logic |
300 | let (expansion, new_invocations) = if let Some(ext) = ext { | |
301 | if let Some(ext) = ext { | |
302 | let expansion = self.expand_invoc(invoc, ext); | |
303 | self.collect_invocations(expansion, &[]) | |
304 | } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { | |
ea8adc8c XL |
305 | let derive_allowed = match item { |
306 | Annotatable::Item(ref item) => match item.node { | |
307 | ast::ItemKind::Struct(..) | | |
308 | ast::ItemKind::Enum(..) | | |
309 | ast::ItemKind::Union(..) => true, | |
310 | _ => false, | |
311 | }, | |
312 | _ => false, | |
313 | }; | |
314 | if !derive_allowed { | |
315 | let attr = item.attrs().iter() | |
316 | .find(|attr| attr.check_name("derive")) | |
317 | .expect("`derive` attribute should exist"); | |
318 | let span = attr.span; | |
319 | let mut err = self.cx.mut_span_err(span, | |
320 | "`derive` may only be applied to \ | |
321 | structs, enums and unions"); | |
322 | if let ast::AttrStyle::Inner = attr.style { | |
323 | let trait_list = traits.iter() | |
324 | .map(|t| format!("{}", t)).collect::<Vec<_>>(); | |
325 | let suggestion = format!("#[derive({})]", trait_list.join(", ")); | |
326 | err.span_suggestion(span, "try an outer attribute", suggestion); | |
327 | } | |
328 | err.emit(); | |
329 | } | |
330 | ||
331 | let item = self.fully_configure(item) | |
cc61c64b | 332 | .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); |
8bb4bdeb | 333 | let item_with_markers = |
cc61c64b | 334 | add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); |
8bb4bdeb XL |
335 | let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); |
336 | ||
cc61c64b | 337 | for path in &traits { |
7cac9316 | 338 | let mark = Mark::fresh(self.cx.current_expansion.mark); |
8bb4bdeb | 339 | derives.push(mark); |
8bb4bdeb | 340 | let item = match self.cx.resolver.resolve_macro( |
cc61c64b | 341 | Mark::root(), path, MacroKind::Derive, false) { |
8bb4bdeb | 342 | Ok(ext) => match *ext { |
3b2f2976 | 343 | BuiltinDerive(..) => item_with_markers.clone(), |
8bb4bdeb XL |
344 | _ => item.clone(), |
345 | }, | |
346 | _ => item.clone(), | |
347 | }; | |
348 | invocations.push(Invocation { | |
cc61c64b | 349 | kind: InvocationKind::Derive { path: path.clone(), item: item }, |
8bb4bdeb XL |
350 | expansion_kind: invoc.expansion_kind, |
351 | expansion_data: ExpansionData { | |
3b2f2976 | 352 | mark, |
8bb4bdeb XL |
353 | ..invoc.expansion_data.clone() |
354 | }, | |
355 | }); | |
356 | } | |
357 | let expansion = invoc.expansion_kind | |
358 | .expect_from_annotatables(::std::iter::once(item_with_markers)); | |
359 | self.collect_invocations(expansion, derives) | |
360 | } else { | |
361 | unreachable!() | |
362 | } | |
363 | } else { | |
364 | self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()), &[]) | |
9e0c209e SL |
365 | }; |
366 | ||
c30ab7b3 | 367 | if expansions.len() < depth { |
9e0c209e SL |
368 | expansions.push(Vec::new()); |
369 | } | |
32a655c1 | 370 | expansions[depth - 1].push((mark, expansion)); |
9e0c209e SL |
371 | if !self.cx.ecfg.single_step { |
372 | invocations.extend(new_invocations.into_iter().rev()); | |
373 | } | |
374 | } | |
375 | ||
376 | self.cx.current_expansion = orig_expansion_data; | |
377 | ||
378 | let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); | |
379 | while let Some(expansions) = expansions.pop() { | |
380 | for (mark, expansion) in expansions.into_iter().rev() { | |
8bb4bdeb | 381 | let derives = derives.remove(&mark).unwrap_or_else(Vec::new); |
cc61c64b | 382 | placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives); |
9e0c209e SL |
383 | } |
384 | } | |
385 | ||
c30ab7b3 | 386 | expansion.fold_with(&mut placeholder_expander) |
9e0c209e SL |
387 | } |
388 | ||
476ff2be SL |
389 | fn resolve_imports(&mut self) { |
390 | if self.monotonic { | |
391 | let err_count = self.cx.parse_sess.span_diagnostic.err_count(); | |
392 | self.cx.resolver.resolve_imports(); | |
393 | self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; | |
394 | } | |
395 | } | |
396 | ||
8bb4bdeb XL |
397 | fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark]) |
398 | -> (Expansion, Vec<Invocation>) { | |
9e0c209e SL |
399 | let result = { |
400 | let mut collector = InvocationCollector { | |
401 | cfg: StripUnconfigured { | |
9e0c209e SL |
402 | should_test: self.cx.ecfg.should_test, |
403 | sess: self.cx.parse_sess, | |
404 | features: self.cx.ecfg.features, | |
405 | }, | |
406 | cx: self.cx, | |
407 | invocations: Vec::new(), | |
408 | monotonic: self.monotonic, | |
409 | }; | |
410 | (expansion.fold_with(&mut collector), collector.invocations) | |
411 | }; | |
9e0c209e SL |
412 | |
413 | if self.monotonic { | |
c30ab7b3 | 414 | let err_count = self.cx.parse_sess.span_diagnostic.err_count(); |
9e0c209e | 415 | let mark = self.cx.current_expansion.mark; |
8bb4bdeb | 416 | self.cx.resolver.visit_expansion(mark, &result.0, derives); |
c30ab7b3 | 417 | self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; |
9e0c209e SL |
418 | } |
419 | ||
420 | result | |
421 | } | |
422 | ||
ea8adc8c XL |
423 | fn fully_configure(&mut self, item: Annotatable) -> Annotatable { |
424 | let mut cfg = StripUnconfigured { | |
425 | should_test: self.cx.ecfg.should_test, | |
426 | sess: self.cx.parse_sess, | |
427 | features: self.cx.ecfg.features, | |
428 | }; | |
429 | // Since the item itself has already been configured by the InvocationCollector, | |
430 | // we know that fold result vector will contain exactly one element | |
431 | match item { | |
432 | Annotatable::Item(item) => { | |
433 | Annotatable::Item(cfg.fold_item(item).pop().unwrap()) | |
434 | } | |
435 | Annotatable::TraitItem(item) => { | |
436 | Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap())) | |
437 | } | |
438 | Annotatable::ImplItem(item) => { | |
439 | Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap())) | |
440 | } | |
441 | } | |
442 | } | |
443 | ||
9e0c209e | 444 | fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { |
cc61c64b | 445 | let result = match invoc.kind { |
9e0c209e SL |
446 | InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), |
447 | InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), | |
8bb4bdeb | 448 | InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), |
cc61c64b XL |
449 | }; |
450 | ||
451 | if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { | |
452 | let info = self.cx.current_expansion.mark.expn_info().unwrap(); | |
453 | let suggested_limit = self.cx.ecfg.recursion_limit * 2; | |
ea8adc8c | 454 | let mut err = self.cx.struct_span_err(info.call_site, |
cc61c64b XL |
455 | &format!("recursion limit reached while expanding the macro `{}`", |
456 | info.callee.name())); | |
457 | err.help(&format!( | |
458 | "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", | |
459 | suggested_limit)); | |
460 | err.emit(); | |
ea8adc8c | 461 | self.cx.trace_macros_diag(); |
cc61c64b | 462 | panic!(FatalError); |
9e0c209e | 463 | } |
cc61c64b XL |
464 | |
465 | result | |
9e0c209e SL |
466 | } |
467 | ||
468 | fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { | |
469 | let Invocation { expansion_kind: kind, .. } = invoc; | |
470 | let (attr, item) = match invoc.kind { | |
8bb4bdeb | 471 | InvocationKind::Attr { attr, item, .. } => (attr.unwrap(), item), |
9e0c209e SL |
472 | _ => unreachable!(), |
473 | }; | |
474 | ||
475 | attr::mark_used(&attr); | |
cc61c64b | 476 | invoc.expansion_data.mark.set_expn_info(ExpnInfo { |
9e0c209e SL |
477 | call_site: attr.span, |
478 | callee: NameAndSpan { | |
cc61c64b XL |
479 | format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), |
480 | span: None, | |
9e0c209e | 481 | allow_internal_unstable: false, |
3b2f2976 | 482 | allow_internal_unsafe: false, |
9e0c209e SL |
483 | } |
484 | }); | |
485 | ||
486 | match *ext { | |
487 | MultiModifier(ref mac) => { | |
7cac9316 | 488 | let meta = panictry!(attr.parse_meta(self.cx.parse_sess)); |
cc61c64b | 489 | let item = mac.expand(self.cx, attr.span, &meta, item); |
9e0c209e SL |
490 | kind.expect_from_annotatables(item) |
491 | } | |
492 | MultiDecorator(ref mac) => { | |
493 | let mut items = Vec::new(); | |
7cac9316 | 494 | let meta = panictry!(attr.parse_meta(self.cx.parse_sess)); |
cc61c64b | 495 | mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); |
9e0c209e SL |
496 | items.push(item); |
497 | kind.expect_from_annotatables(items) | |
498 | } | |
3b2f2976 | 499 | AttrProcMacro(ref mac) => { |
041b39d2 XL |
500 | let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item { |
501 | Annotatable::Item(item) => token::NtItem(item), | |
502 | Annotatable::TraitItem(item) => token::NtTraitItem(item.unwrap()), | |
503 | Annotatable::ImplItem(item) => token::NtImplItem(item.unwrap()), | |
504 | })).into(); | |
505 | let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok); | |
506 | self.parse_expansion(tok_result, kind, &attr.path, attr.span) | |
9e0c209e | 507 | } |
3b2f2976 | 508 | ProcMacroDerive(..) | BuiltinDerive(..) => { |
cc61c64b | 509 | self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); |
ea8adc8c | 510 | self.cx.trace_macros_diag(); |
c30ab7b3 SL |
511 | kind.dummy(attr.span) |
512 | } | |
513 | _ => { | |
cc61c64b | 514 | let msg = &format!("macro `{}` may not be used in attributes", attr.path); |
7cac9316 | 515 | self.cx.span_err(attr.span, msg); |
ea8adc8c | 516 | self.cx.trace_macros_diag(); |
c30ab7b3 SL |
517 | kind.dummy(attr.span) |
518 | } | |
9e0c209e SL |
519 | } |
520 | } | |
521 | ||
522 | /// Expand a macro invocation. Returns the result of expansion. | |
523 | fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { | |
524 | let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind); | |
32a655c1 SL |
525 | let (mac, ident, span) = match invoc.kind { |
526 | InvocationKind::Bang { mac, ident, span } => (mac, ident, span), | |
9e0c209e SL |
527 | _ => unreachable!(), |
528 | }; | |
8bb4bdeb | 529 | let path = &mac.node.path; |
9e0c209e | 530 | |
7cac9316 | 531 | let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); |
3b2f2976 XL |
532 | let validate_and_set_expn_info = |def_site_span, |
533 | allow_internal_unstable, | |
534 | allow_internal_unsafe| { | |
7cac9316 XL |
535 | if ident.name != keywords::Invalid.name() { |
536 | return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident)); | |
537 | } | |
538 | mark.set_expn_info(ExpnInfo { | |
539 | call_site: span, | |
540 | callee: NameAndSpan { | |
abe05a73 | 541 | format: macro_bang_format(path), |
7cac9316 | 542 | span: def_site_span, |
3b2f2976 XL |
543 | allow_internal_unstable, |
544 | allow_internal_unsafe, | |
7cac9316 XL |
545 | }, |
546 | }); | |
547 | Ok(()) | |
548 | }; | |
549 | ||
9e0c209e | 550 | let opt_expanded = match *ext { |
3b2f2976 | 551 | DeclMacro(ref expand, def_span) => { |
7cac9316 | 552 | if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s), |
3b2f2976 | 553 | false, false) { |
9e0c209e | 554 | self.cx.span_err(path.span, &msg); |
ea8adc8c | 555 | self.cx.trace_macros_diag(); |
9e0c209e | 556 | return kind.dummy(span); |
3157f602 | 557 | } |
041b39d2 | 558 | kind.make_from(expand.expand(self.cx, span, mac.node.stream())) |
7cac9316 | 559 | } |
3157f602 | 560 | |
3b2f2976 XL |
561 | NormalTT { |
562 | ref expander, | |
563 | def_info, | |
564 | allow_internal_unstable, | |
565 | allow_internal_unsafe | |
566 | } => { | |
7cac9316 | 567 | if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s), |
3b2f2976 XL |
568 | allow_internal_unstable, |
569 | allow_internal_unsafe) { | |
7cac9316 | 570 | self.cx.span_err(path.span, &msg); |
ea8adc8c | 571 | self.cx.trace_macros_diag(); |
7cac9316 XL |
572 | return kind.dummy(span); |
573 | } | |
3b2f2976 | 574 | kind.make_from(expander.expand(self.cx, span, mac.node.stream())) |
3157f602 XL |
575 | } |
576 | ||
577 | IdentTT(ref expander, tt_span, allow_internal_unstable) => { | |
578 | if ident.name == keywords::Invalid.name() { | |
9e0c209e | 579 | self.cx.span_err(path.span, |
cc61c64b | 580 | &format!("macro {}! expects an ident argument", path)); |
ea8adc8c | 581 | self.cx.trace_macros_diag(); |
9e0c209e | 582 | return kind.dummy(span); |
b039eaaf | 583 | }; |
3157f602 | 584 | |
cc61c64b | 585 | invoc.expansion_data.mark.set_expn_info(ExpnInfo { |
9e0c209e | 586 | call_site: span, |
3157f602 | 587 | callee: NameAndSpan { |
abe05a73 | 588 | format: macro_bang_format(path), |
3157f602 | 589 | span: tt_span, |
3b2f2976 XL |
590 | allow_internal_unstable, |
591 | allow_internal_unsafe: false, | |
223e47cc | 592 | } |
3157f602 XL |
593 | }); |
594 | ||
041b39d2 | 595 | let input: Vec<_> = mac.node.stream().into_trees().collect(); |
8bb4bdeb | 596 | kind.make_from(expander.expand(self.cx, span, ident, input)) |
3157f602 XL |
597 | } |
598 | ||
3b2f2976 | 599 | MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => { |
9e0c209e | 600 | self.cx.span_err(path.span, |
cc61c64b | 601 | &format!("`{}` can only be used in attributes", path)); |
ea8adc8c | 602 | self.cx.trace_macros_diag(); |
9e0c209e SL |
603 | return kind.dummy(span); |
604 | } | |
3157f602 | 605 | |
3b2f2976 | 606 | ProcMacroDerive(..) | BuiltinDerive(..) => { |
cc61c64b | 607 | self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); |
ea8adc8c | 608 | self.cx.trace_macros_diag(); |
c30ab7b3 SL |
609 | return kind.dummy(span); |
610 | } | |
611 | ||
3b2f2976 | 612 | ProcMacro(ref expandfun) => { |
9e0c209e SL |
613 | if ident.name != keywords::Invalid.name() { |
614 | let msg = | |
cc61c64b | 615 | format!("macro {}! expects no ident argument, given '{}'", path, ident); |
9e0c209e | 616 | self.cx.span_err(path.span, &msg); |
ea8adc8c | 617 | self.cx.trace_macros_diag(); |
9e0c209e SL |
618 | return kind.dummy(span); |
619 | } | |
620 | ||
cc61c64b | 621 | invoc.expansion_data.mark.set_expn_info(ExpnInfo { |
9e0c209e | 622 | call_site: span, |
3157f602 | 623 | callee: NameAndSpan { |
abe05a73 | 624 | format: macro_bang_format(path), |
9e0c209e SL |
625 | // FIXME procedural macros do not have proper span info |
626 | // yet, when they do, we should use it here. | |
3157f602 | 627 | span: None, |
9e0c209e | 628 | // FIXME probably want to follow macro_rules macros here. |
3157f602 | 629 | allow_internal_unstable: false, |
3b2f2976 | 630 | allow_internal_unsafe: false, |
9e0c209e | 631 | }, |
3157f602 XL |
632 | }); |
633 | ||
041b39d2 | 634 | let tok_result = expandfun.expand(self.cx, span, mac.node.stream()); |
cc61c64b | 635 | Some(self.parse_expansion(tok_result, kind, path, span)) |
b039eaaf | 636 | } |
9e0c209e | 637 | }; |
3157f602 | 638 | |
041b39d2 | 639 | unwrap_or!(opt_expanded, { |
9e0c209e SL |
640 | let msg = format!("non-{kind} macro in {kind} position: {name}", |
641 | name = path.segments[0].identifier.name, kind = kind.name()); | |
642 | self.cx.span_err(path.span, &msg); | |
ea8adc8c | 643 | self.cx.trace_macros_diag(); |
041b39d2 XL |
644 | kind.dummy(span) |
645 | }) | |
9e0c209e | 646 | } |
1a4d82fc | 647 | |
8bb4bdeb XL |
648 | /// Expand a derive invocation. Returns the result of expansion. |
649 | fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { | |
650 | let Invocation { expansion_kind: kind, .. } = invoc; | |
cc61c64b XL |
651 | let (path, item) = match invoc.kind { |
652 | InvocationKind::Derive { path, item } => (path, item), | |
8bb4bdeb XL |
653 | _ => unreachable!(), |
654 | }; | |
655 | ||
cc61c64b XL |
656 | let pretty_name = Symbol::intern(&format!("derive({})", path)); |
657 | let span = path.span; | |
658 | let attr = ast::Attribute { | |
3b2f2976 XL |
659 | path, span, |
660 | tokens: TokenStream::empty(), | |
cc61c64b XL |
661 | // irrelevant: |
662 | id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, | |
663 | }; | |
8bb4bdeb | 664 | |
cc61c64b | 665 | let mut expn_info = ExpnInfo { |
8bb4bdeb XL |
666 | call_site: span, |
667 | callee: NameAndSpan { | |
668 | format: MacroAttribute(pretty_name), | |
cc61c64b | 669 | span: None, |
8bb4bdeb | 670 | allow_internal_unstable: false, |
3b2f2976 | 671 | allow_internal_unsafe: false, |
8bb4bdeb | 672 | } |
cc61c64b | 673 | }; |
8bb4bdeb XL |
674 | |
675 | match *ext { | |
3b2f2976 | 676 | ProcMacroDerive(ref ext, _) => { |
cc61c64b | 677 | invoc.expansion_data.mark.set_expn_info(expn_info); |
ea8adc8c | 678 | let span = span.with_ctxt(self.cx.backtrace()); |
cc61c64b XL |
679 | let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this |
680 | name: keywords::Invalid.name(), | |
681 | span: DUMMY_SP, | |
682 | node: ast::MetaItemKind::Word, | |
8bb4bdeb | 683 | }; |
cc61c64b | 684 | kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)) |
8bb4bdeb | 685 | } |
3b2f2976 | 686 | BuiltinDerive(func) => { |
cc61c64b XL |
687 | expn_info.callee.allow_internal_unstable = true; |
688 | invoc.expansion_data.mark.set_expn_info(expn_info); | |
ea8adc8c | 689 | let span = span.with_ctxt(self.cx.backtrace()); |
8bb4bdeb | 690 | let mut items = Vec::new(); |
cc61c64b XL |
691 | func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); |
692 | kind.expect_from_annotatables(items) | |
8bb4bdeb XL |
693 | } |
694 | _ => { | |
cc61c64b | 695 | let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); |
7cac9316 | 696 | self.cx.span_err(span, msg); |
ea8adc8c | 697 | self.cx.trace_macros_diag(); |
8bb4bdeb XL |
698 | kind.dummy(span) |
699 | } | |
700 | } | |
701 | } | |
702 | ||
cc61c64b | 703 | fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span) |
9e0c209e | 704 | -> Expansion { |
8bb4bdeb | 705 | let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>()); |
9e0c209e SL |
706 | let expansion = match parser.parse_expansion(kind, false) { |
707 | Ok(expansion) => expansion, | |
708 | Err(mut err) => { | |
9cc50fc6 | 709 | err.emit(); |
ea8adc8c | 710 | self.cx.trace_macros_diag(); |
9e0c209e | 711 | return kind.dummy(span); |
1a4d82fc JJ |
712 | } |
713 | }; | |
cc61c64b | 714 | parser.ensure_complete_parse(path, kind.name(), span); |
041b39d2 | 715 | expansion |
9e0c209e SL |
716 | } |
717 | } | |
970d7e83 | 718 | |
9e0c209e SL |
719 | impl<'a> Parser<'a> { |
720 | pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool) | |
721 | -> PResult<'a, Expansion> { | |
722 | Ok(match kind { | |
723 | ExpansionKind::Items => { | |
476ff2be | 724 | let mut items = SmallVector::new(); |
9e0c209e SL |
725 | while let Some(item) = self.parse_item()? { |
726 | items.push(item); | |
727 | } | |
728 | Expansion::Items(items) | |
729 | } | |
730 | ExpansionKind::TraitItems => { | |
476ff2be | 731 | let mut items = SmallVector::new(); |
9e0c209e | 732 | while self.token != token::Eof { |
cc61c64b | 733 | items.push(self.parse_trait_item(&mut false)?); |
9e0c209e SL |
734 | } |
735 | Expansion::TraitItems(items) | |
736 | } | |
737 | ExpansionKind::ImplItems => { | |
476ff2be | 738 | let mut items = SmallVector::new(); |
9e0c209e | 739 | while self.token != token::Eof { |
cc61c64b | 740 | items.push(self.parse_impl_item(&mut false)?); |
9e0c209e SL |
741 | } |
742 | Expansion::ImplItems(items) | |
743 | } | |
744 | ExpansionKind::Stmts => { | |
476ff2be SL |
745 | let mut stmts = SmallVector::new(); |
746 | while self.token != token::Eof && | |
747 | // won't make progress on a `}` | |
748 | self.token != token::CloseDelim(token::Brace) { | |
9e0c209e SL |
749 | if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? { |
750 | stmts.push(stmt); | |
751 | } | |
752 | } | |
753 | Expansion::Stmts(stmts) | |
223e47cc | 754 | } |
9e0c209e SL |
755 | ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), |
756 | ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)), | |
cc61c64b | 757 | ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), |
9e0c209e SL |
758 | ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), |
759 | }) | |
760 | } | |
761 | ||
cc61c64b | 762 | pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) { |
9e0c209e SL |
763 | if self.token != token::Eof { |
764 | let msg = format!("macro expansion ignores token `{}` and any following", | |
765 | self.this_token_to_string()); | |
ea8adc8c XL |
766 | // Avoid emitting backtrace info twice. |
767 | let def_site_span = self.span.with_ctxt(SyntaxContext::empty()); | |
041b39d2 | 768 | let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); |
9e0c209e SL |
769 | let msg = format!("caused by the macro expansion here; the usage \ |
770 | of `{}!` is likely invalid in {} context", | |
cc61c64b | 771 | macro_path, kind_name); |
9e0c209e | 772 | err.span_note(span, &msg).emit(); |
1a4d82fc JJ |
773 | } |
774 | } | |
1a4d82fc JJ |
775 | } |
776 | ||
9e0c209e SL |
777 | struct InvocationCollector<'a, 'b: 'a> { |
778 | cx: &'a mut ExtCtxt<'b>, | |
779 | cfg: StripUnconfigured<'a>, | |
780 | invocations: Vec<Invocation>, | |
781 | monotonic: bool, | |
782 | } | |
223e47cc | 783 | |
9e0c209e SL |
784 | impl<'a, 'b> InvocationCollector<'a, 'b> { |
785 | fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { | |
7cac9316 | 786 | let mark = Mark::fresh(self.cx.current_expansion.mark); |
9e0c209e | 787 | self.invocations.push(Invocation { |
3b2f2976 XL |
788 | kind, |
789 | expansion_kind, | |
c30ab7b3 | 790 | expansion_data: ExpansionData { |
3b2f2976 | 791 | mark, |
c30ab7b3 SL |
792 | depth: self.cx.current_expansion.depth + 1, |
793 | ..self.cx.current_expansion.clone() | |
794 | }, | |
9e0c209e | 795 | }); |
cc61c64b | 796 | placeholder(expansion_kind, NodeId::placeholder_from_mark(mark)) |
1a4d82fc | 797 | } |
223e47cc | 798 | |
32a655c1 SL |
799 | fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { |
800 | self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span }) | |
9e0c209e | 801 | } |
85aaf69f | 802 | |
8bb4bdeb XL |
803 | fn collect_attr(&mut self, |
804 | attr: Option<ast::Attribute>, | |
cc61c64b | 805 | traits: Vec<Path>, |
8bb4bdeb XL |
806 | item: Annotatable, |
807 | kind: ExpansionKind) | |
9e0c209e | 808 | -> Expansion { |
3b2f2976 | 809 | self.collect(kind, InvocationKind::Attr { attr, traits, item }) |
9e0c209e | 810 | } |
3157f602 | 811 | |
9e0c209e | 812 | // If `item` is an attr invocation, remove and return the macro attribute. |
cc61c64b | 813 | fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T) |
8bb4bdeb XL |
814 | where T: HasAttrs, |
815 | { | |
816 | let (mut attr, mut traits) = (None, Vec::new()); | |
817 | ||
9e0c209e | 818 | item = item.map_attrs(|mut attrs| { |
8bb4bdeb XL |
819 | if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs) { |
820 | attr = Some(legacy_attr_invoc); | |
821 | return attrs; | |
822 | } | |
823 | ||
824 | if self.cx.ecfg.proc_macro_enabled() { | |
825 | attr = find_attr_invoc(&mut attrs); | |
826 | } | |
827 | traits = collect_derives(&mut self.cx, &mut attrs); | |
9e0c209e SL |
828 | attrs |
829 | }); | |
8bb4bdeb XL |
830 | |
831 | (attr, traits, item) | |
9e0c209e | 832 | } |
c34b1796 | 833 | |
9e0c209e SL |
834 | fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> { |
835 | self.cfg.configure(node) | |
d9579d0f | 836 | } |
32a655c1 SL |
837 | |
838 | // Detect use of feature-gated or invalid attributes on macro invocations | |
839 | // since they will not be detected after macro expansion. | |
840 | fn check_attributes(&mut self, attrs: &[ast::Attribute]) { | |
32a655c1 SL |
841 | let features = self.cx.ecfg.features.unwrap(); |
842 | for attr in attrs.iter() { | |
7cac9316 | 843 | feature_gate::check_attribute(attr, self.cx.parse_sess, features); |
32a655c1 SL |
844 | } |
845 | } | |
85aaf69f SL |
846 | } |
847 | ||
8bb4bdeb | 848 | pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> { |
7cac9316 XL |
849 | attrs.iter() |
850 | .position(|a| !attr::is_known(a) && !is_builtin_attr(a)) | |
851 | .map(|i| attrs.remove(i)) | |
8bb4bdeb XL |
852 | } |
853 | ||
9e0c209e SL |
854 | impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { |
855 | fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> { | |
856 | let mut expr = self.cfg.configure_expr(expr).unwrap(); | |
857 | expr.node = self.cfg.configure_expr_kind(expr.node); | |
858 | ||
859 | if let ast::ExprKind::Mac(mac) = expr.node { | |
32a655c1 SL |
860 | self.check_attributes(&expr.attrs); |
861 | self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr() | |
9e0c209e SL |
862 | } else { |
863 | P(noop_fold_expr(expr, self)) | |
223e47cc | 864 | } |
c34b1796 | 865 | } |
223e47cc | 866 | |
9e0c209e SL |
867 | fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { |
868 | let mut expr = configure!(self, expr).unwrap(); | |
869 | expr.node = self.cfg.configure_expr_kind(expr.node); | |
870 | ||
871 | if let ast::ExprKind::Mac(mac) = expr.node { | |
32a655c1 SL |
872 | self.check_attributes(&expr.attrs); |
873 | self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr() | |
9e0c209e SL |
874 | } else { |
875 | Some(P(noop_fold_expr(expr, self))) | |
3157f602 | 876 | } |
3157f602 | 877 | } |
3157f602 | 878 | |
9e0c209e | 879 | fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> { |
32a655c1 | 880 | let pat = self.cfg.configure_pat(pat); |
9e0c209e SL |
881 | match pat.node { |
882 | PatKind::Mac(_) => {} | |
883 | _ => return noop_fold_pat(pat, self), | |
e9174d1e | 884 | } |
e9174d1e | 885 | |
9e0c209e | 886 | pat.and_then(|pat| match pat.node { |
32a655c1 | 887 | PatKind::Mac(mac) => self.collect_bang(mac, pat.span, ExpansionKind::Pat).make_pat(), |
9e0c209e SL |
888 | _ => unreachable!(), |
889 | }) | |
890 | } | |
e9174d1e | 891 | |
9e0c209e SL |
892 | fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> { |
893 | let stmt = match self.cfg.configure_stmt(stmt) { | |
894 | Some(stmt) => stmt, | |
476ff2be | 895 | None => return SmallVector::new(), |
9e0c209e | 896 | }; |
1a4d82fc | 897 | |
9e0c209e SL |
898 | let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node { |
899 | mac.unwrap() | |
900 | } else { | |
901 | // The placeholder expander gives ids to statements, so we avoid folding the id here. | |
902 | let ast::Stmt { id, node, span } = stmt; | |
903 | return noop_fold_stmt_kind(node, self).into_iter().map(|node| { | |
904 | ast::Stmt { id: id, node: node, span: span } | |
905 | }).collect() | |
906 | }; | |
907 | ||
32a655c1 SL |
908 | self.check_attributes(&attrs); |
909 | let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts).make_stmts(); | |
9e0c209e SL |
910 | |
911 | // If this is a macro invocation with a semicolon, then apply that | |
912 | // semicolon to the final statement produced by expansion. | |
913 | if style == MacStmtStyle::Semicolon { | |
914 | if let Some(stmt) = placeholder.pop() { | |
915 | placeholder.push(stmt.add_trailing_semicolon()); | |
916 | } | |
5bcae85e | 917 | } |
9e0c209e SL |
918 | |
919 | placeholder | |
1a4d82fc | 920 | } |
3157f602 | 921 | |
9e0c209e | 922 | fn fold_block(&mut self, block: P<Block>) -> P<Block> { |
476ff2be SL |
923 | let old_directory_ownership = self.cx.current_expansion.directory_ownership; |
924 | self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock; | |
9e0c209e | 925 | let result = noop_fold_block(block, self); |
476ff2be | 926 | self.cx.current_expansion.directory_ownership = old_directory_ownership; |
9e0c209e | 927 | result |
3157f602 XL |
928 | } |
929 | ||
9e0c209e SL |
930 | fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> { |
931 | let item = configure!(self, item); | |
932 | ||
8bb4bdeb XL |
933 | let (attr, traits, mut item) = self.classify_item(item); |
934 | if attr.is_some() || !traits.is_empty() { | |
ea8adc8c | 935 | let item = Annotatable::Item(item); |
8bb4bdeb | 936 | return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items(); |
3157f602 XL |
937 | } |
938 | ||
9e0c209e SL |
939 | match item.node { |
940 | ast::ItemKind::Mac(..) => { | |
32a655c1 | 941 | self.check_attributes(&item.attrs); |
8bb4bdeb | 942 | item.and_then(|item| match item.node { |
9e0c209e SL |
943 | ItemKind::Mac(mac) => { |
944 | self.collect(ExpansionKind::Items, InvocationKind::Bang { | |
3b2f2976 | 945 | mac, |
9e0c209e SL |
946 | ident: Some(item.ident), |
947 | span: item.span, | |
948 | }).make_items() | |
949 | } | |
950 | _ => unreachable!(), | |
951 | }) | |
3157f602 | 952 | } |
9e0c209e SL |
953 | ast::ItemKind::Mod(ast::Mod { inner, .. }) => { |
954 | if item.ident == keywords::Invalid.ident() { | |
955 | return noop_fold_item(item, self); | |
956 | } | |
3157f602 | 957 | |
476ff2be | 958 | let orig_directory_ownership = self.cx.current_expansion.directory_ownership; |
9e0c209e SL |
959 | let mut module = (*self.cx.current_expansion.module).clone(); |
960 | module.mod_path.push(item.ident); | |
1a4d82fc | 961 | |
9e0c209e SL |
962 | // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). |
963 | // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). | |
964 | // Thus, if `inner` is the dummy span, we know the module is inline. | |
cc61c64b | 965 | let inline_module = item.span.contains(inner) || inner == DUMMY_SP; |
54a0048b | 966 | |
9e0c209e | 967 | if inline_module { |
c30ab7b3 | 968 | if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { |
476ff2be SL |
969 | self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned; |
970 | module.directory.push(&*path.as_str()); | |
c30ab7b3 SL |
971 | } else { |
972 | module.directory.push(&*item.ident.name.as_str()); | |
973 | } | |
9e0c209e | 974 | } else { |
ea8adc8c | 975 | let mut path = self.cx.parse_sess.codemap().span_to_unmapped_path(inner); |
476ff2be SL |
976 | let directory_ownership = match path.file_name().unwrap().to_str() { |
977 | Some("mod.rs") => DirectoryOwnership::Owned, | |
978 | _ => DirectoryOwnership::UnownedViaMod(false), | |
979 | }; | |
980 | path.pop(); | |
981 | module.directory = path; | |
982 | self.cx.current_expansion.directory_ownership = directory_ownership; | |
9e0c209e | 983 | } |
3157f602 | 984 | |
9e0c209e SL |
985 | let orig_module = |
986 | mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); | |
987 | let result = noop_fold_item(item, self); | |
988 | self.cx.current_expansion.module = orig_module; | |
476ff2be | 989 | self.cx.current_expansion.directory_ownership = orig_directory_ownership; |
7cac9316 | 990 | result |
9e0c209e | 991 | } |
c30ab7b3 SL |
992 | // Ensure that test functions are accessible from the test harness. |
993 | ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => { | |
994 | if item.attrs.iter().any(|attr| is_test_or_bench(attr)) { | |
995 | item = item.map(|mut item| { item.vis = ast::Visibility::Public; item }); | |
996 | } | |
997 | noop_fold_item(item, self) | |
998 | } | |
9e0c209e SL |
999 | _ => noop_fold_item(item, self), |
1000 | } | |
1a4d82fc JJ |
1001 | } |
1002 | ||
9e0c209e SL |
1003 | fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> { |
1004 | let item = configure!(self, item); | |
1a4d82fc | 1005 | |
8bb4bdeb XL |
1006 | let (attr, traits, item) = self.classify_item(item); |
1007 | if attr.is_some() || !traits.is_empty() { | |
ea8adc8c | 1008 | let item = Annotatable::TraitItem(P(item)); |
8bb4bdeb XL |
1009 | return self.collect_attr(attr, traits, item, ExpansionKind::TraitItems) |
1010 | .make_trait_items() | |
9e0c209e SL |
1011 | } |
1012 | ||
1013 | match item.node { | |
1014 | ast::TraitItemKind::Macro(mac) => { | |
1015 | let ast::TraitItem { attrs, span, .. } = item; | |
32a655c1 SL |
1016 | self.check_attributes(&attrs); |
1017 | self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items() | |
54a0048b | 1018 | } |
9e0c209e | 1019 | _ => fold::noop_fold_trait_item(item, self), |
54a0048b | 1020 | } |
1a4d82fc JJ |
1021 | } |
1022 | ||
9e0c209e SL |
1023 | fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> { |
1024 | let item = configure!(self, item); | |
1a4d82fc | 1025 | |
8bb4bdeb XL |
1026 | let (attr, traits, item) = self.classify_item(item); |
1027 | if attr.is_some() || !traits.is_empty() { | |
ea8adc8c | 1028 | let item = Annotatable::ImplItem(P(item)); |
8bb4bdeb XL |
1029 | return self.collect_attr(attr, traits, item, ExpansionKind::ImplItems) |
1030 | .make_impl_items(); | |
9e0c209e | 1031 | } |
1a4d82fc | 1032 | |
9e0c209e SL |
1033 | match item.node { |
1034 | ast::ImplItemKind::Macro(mac) => { | |
1035 | let ast::ImplItem { attrs, span, .. } = item; | |
32a655c1 SL |
1036 | self.check_attributes(&attrs); |
1037 | self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items() | |
9e0c209e SL |
1038 | } |
1039 | _ => fold::noop_fold_impl_item(item, self), | |
1040 | } | |
85aaf69f SL |
1041 | } |
1042 | ||
9e0c209e SL |
1043 | fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> { |
1044 | let ty = match ty.node { | |
1045 | ast::TyKind::Mac(_) => ty.unwrap(), | |
1046 | _ => return fold::noop_fold_ty(ty, self), | |
1047 | }; | |
1048 | ||
1049 | match ty.node { | |
32a655c1 | 1050 | ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, ExpansionKind::Ty).make_ty(), |
9e0c209e SL |
1051 | _ => unreachable!(), |
1052 | } | |
1a4d82fc JJ |
1053 | } |
1054 | ||
9e0c209e SL |
1055 | fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { |
1056 | noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self) | |
e9174d1e | 1057 | } |
970d7e83 | 1058 | |
9e0c209e | 1059 | fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { |
8bb4bdeb XL |
1060 | match item { |
1061 | ast::ItemKind::MacroDef(..) => item, | |
1062 | _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self), | |
1063 | } | |
54a0048b SL |
1064 | } |
1065 | ||
9e0c209e SL |
1066 | fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { |
1067 | if self.monotonic { | |
1068 | assert_eq!(id, ast::DUMMY_NODE_ID); | |
1069 | self.cx.resolver.next_node_id() | |
1070 | } else { | |
1071 | id | |
1072 | } | |
54a0048b SL |
1073 | } |
1074 | } | |
1075 | ||
85aaf69f | 1076 | pub struct ExpansionConfig<'feat> { |
1a4d82fc | 1077 | pub crate_name: String, |
85aaf69f SL |
1078 | pub features: Option<&'feat Features>, |
1079 | pub recursion_limit: usize, | |
d9579d0f | 1080 | pub trace_mac: bool, |
3157f602 | 1081 | pub should_test: bool, // If false, strip `#[test]` nodes |
9e0c209e SL |
1082 | pub single_step: bool, |
1083 | pub keep_macs: bool, | |
1a4d82fc JJ |
1084 | } |
1085 | ||
c34b1796 AL |
1086 | macro_rules! feature_tests { |
1087 | ($( fn $getter:ident = $field:ident, )*) => { | |
1088 | $( | |
1089 | pub fn $getter(&self) -> bool { | |
1090 | match self.features { | |
1091 | Some(&Features { $field: true, .. }) => true, | |
1092 | _ => false, | |
1093 | } | |
1094 | } | |
1095 | )* | |
1096 | } | |
1097 | } | |
1098 | ||
85aaf69f SL |
1099 | impl<'feat> ExpansionConfig<'feat> { |
1100 | pub fn default(crate_name: String) -> ExpansionConfig<'static> { | |
1a4d82fc | 1101 | ExpansionConfig { |
3b2f2976 | 1102 | crate_name, |
85aaf69f | 1103 | features: None, |
7cac9316 | 1104 | recursion_limit: 1024, |
d9579d0f | 1105 | trace_mac: false, |
3157f602 | 1106 | should_test: false, |
9e0c209e SL |
1107 | single_step: false, |
1108 | keep_macs: false, | |
1a4d82fc | 1109 | } |
970d7e83 | 1110 | } |
85aaf69f | 1111 | |
c34b1796 | 1112 | feature_tests! { |
a7813a04 XL |
1113 | fn enable_quotes = quote, |
1114 | fn enable_asm = asm, | |
cc61c64b | 1115 | fn enable_global_asm = global_asm, |
a7813a04 XL |
1116 | fn enable_log_syntax = log_syntax, |
1117 | fn enable_concat_idents = concat_idents, | |
1118 | fn enable_trace_macros = trace_macros, | |
c34b1796 | 1119 | fn enable_allow_internal_unstable = allow_internal_unstable, |
a7813a04 | 1120 | fn enable_custom_derive = custom_derive, |
8bb4bdeb | 1121 | fn proc_macro_enabled = proc_macro, |
85aaf69f | 1122 | } |
970d7e83 LB |
1123 | } |
1124 | ||
cc61c64b | 1125 | // A Marker adds the given mark to the syntax context. |
3b2f2976 | 1126 | #[derive(Debug)] |
041b39d2 | 1127 | pub struct Marker(pub Mark); |
1a4d82fc JJ |
1128 | |
1129 | impl Folder for Marker { | |
5bcae85e | 1130 | fn fold_ident(&mut self, mut ident: Ident) -> Ident { |
cc61c64b | 1131 | ident.ctxt = ident.ctxt.apply_mark(self.0); |
5bcae85e | 1132 | ident |
1a4d82fc | 1133 | } |
1a4d82fc | 1134 | |
ea8adc8c XL |
1135 | fn new_span(&mut self, span: Span) -> Span { |
1136 | span.with_ctxt(span.ctxt().apply_mark(self.0)) | |
3157f602 | 1137 | } |
cc61c64b XL |
1138 | |
1139 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { | |
1140 | noop_fold_mac(mac, self) | |
1141 | } | |
1a4d82fc | 1142 | } |