]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use crate::expand::{self, AstFragment, Invocation}; |
2 | ||
60c5eb7d | 3 | use rustc_parse::{self, parser, DirectoryOwnership, MACRO_ARGUMENTS}; |
e74abb32 XL |
4 | use syntax::ast::{self, NodeId, Attribute, Name, PatKind}; |
5 | use syntax::attr::{self, HasAttrs, Stability, Deprecation}; | |
6 | use syntax::source_map::SourceMap; | |
7 | use syntax::edition::Edition; | |
8 | use syntax::mut_visit::{self, MutVisitor}; | |
e74abb32 XL |
9 | use syntax::ptr::P; |
10 | use syntax::sess::ParseSess; | |
11 | use syntax::symbol::{kw, sym, Ident, Symbol}; | |
60c5eb7d XL |
12 | use syntax::ThinVec; |
13 | use syntax::token; | |
e74abb32 XL |
14 | use syntax::tokenstream::{self, TokenStream}; |
15 | use syntax::visit::Visitor; | |
1a4d82fc | 16 | |
83c7162d | 17 | use errors::{DiagnosticBuilder, DiagnosticId}; |
9fa01778 | 18 | use smallvec::{smallvec, SmallVec}; |
416331ca | 19 | use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP}; |
e74abb32 | 20 | use syntax_pos::hygiene::{AstPass, ExpnId, ExpnData, ExpnKind}; |
b7449926 | 21 | use rustc_data_structures::fx::FxHashMap; |
9fa01778 | 22 | use rustc_data_structures::sync::{self, Lrc}; |
60c5eb7d | 23 | |
ff7c6d11 | 24 | use std::iter; |
9e0c209e | 25 | use std::path::PathBuf; |
1a4d82fc | 26 | use std::rc::Rc; |
c34b1796 | 27 | use std::default::Default; |
1a4d82fc | 28 | |
e74abb32 | 29 | crate use syntax_pos::hygiene::MacroKind; |
223e47cc | 30 | |
85aaf69f SL |
31 | #[derive(Debug,Clone)] |
32 | pub enum Annotatable { | |
33 | Item(P<ast::Item>), | |
c34b1796 AL |
34 | TraitItem(P<ast::TraitItem>), |
35 | ImplItem(P<ast::ImplItem>), | |
83c7162d | 36 | ForeignItem(P<ast::ForeignItem>), |
0531ce1d XL |
37 | Stmt(P<ast::Stmt>), |
38 | Expr(P<ast::Expr>), | |
e1599b0c XL |
39 | Arm(ast::Arm), |
40 | Field(ast::Field), | |
41 | FieldPat(ast::FieldPat), | |
42 | GenericParam(ast::GenericParam), | |
43 | Param(ast::Param), | |
44 | StructField(ast::StructField), | |
45 | Variant(ast::Variant), | |
85aaf69f SL |
46 | } |
47 | ||
3157f602 | 48 | impl HasAttrs for Annotatable { |
9e0c209e | 49 | fn attrs(&self) -> &[Attribute] { |
85aaf69f | 50 | match *self { |
3157f602 XL |
51 | Annotatable::Item(ref item) => &item.attrs, |
52 | Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, | |
53 | Annotatable::ImplItem(ref impl_item) => &impl_item.attrs, | |
83c7162d | 54 | Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs, |
0531ce1d XL |
55 | Annotatable::Stmt(ref stmt) => stmt.attrs(), |
56 | Annotatable::Expr(ref expr) => &expr.attrs, | |
e1599b0c XL |
57 | Annotatable::Arm(ref arm) => &arm.attrs, |
58 | Annotatable::Field(ref field) => &field.attrs, | |
59 | Annotatable::FieldPat(ref fp) => &fp.attrs, | |
60 | Annotatable::GenericParam(ref gp) => &gp.attrs, | |
61 | Annotatable::Param(ref p) => &p.attrs, | |
62 | Annotatable::StructField(ref sf) => &sf.attrs, | |
63 | Annotatable::Variant(ref v) => &v.attrs(), | |
85aaf69f SL |
64 | } |
65 | } | |
66 | ||
9fa01778 | 67 | fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) { |
85aaf69f | 68 | match self { |
9fa01778 XL |
69 | Annotatable::Item(item) => item.visit_attrs(f), |
70 | Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f), | |
71 | Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f), | |
72 | Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f), | |
73 | Annotatable::Stmt(stmt) => stmt.visit_attrs(f), | |
74 | Annotatable::Expr(expr) => expr.visit_attrs(f), | |
e1599b0c XL |
75 | Annotatable::Arm(arm) => arm.visit_attrs(f), |
76 | Annotatable::Field(field) => field.visit_attrs(f), | |
77 | Annotatable::FieldPat(fp) => fp.visit_attrs(f), | |
78 | Annotatable::GenericParam(gp) => gp.visit_attrs(f), | |
79 | Annotatable::Param(p) => p.visit_attrs(f), | |
80 | Annotatable::StructField(sf) => sf.visit_attrs(f), | |
81 | Annotatable::Variant(v) => v.visit_attrs(f), | |
85aaf69f SL |
82 | } |
83 | } | |
3157f602 XL |
84 | } |
85 | ||
86 | impl Annotatable { | |
cc61c64b XL |
87 | pub fn span(&self) -> Span { |
88 | match *self { | |
89 | Annotatable::Item(ref item) => item.span, | |
90 | Annotatable::TraitItem(ref trait_item) => trait_item.span, | |
91 | Annotatable::ImplItem(ref impl_item) => impl_item.span, | |
83c7162d | 92 | Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, |
0531ce1d XL |
93 | Annotatable::Stmt(ref stmt) => stmt.span, |
94 | Annotatable::Expr(ref expr) => expr.span, | |
e1599b0c XL |
95 | Annotatable::Arm(ref arm) => arm.span, |
96 | Annotatable::Field(ref field) => field.span, | |
97 | Annotatable::FieldPat(ref fp) => fp.pat.span, | |
98 | Annotatable::GenericParam(ref gp) => gp.ident.span, | |
99 | Annotatable::Param(ref p) => p.span, | |
100 | Annotatable::StructField(ref sf) => sf.span, | |
101 | Annotatable::Variant(ref v) => v.span, | |
102 | } | |
103 | } | |
104 | ||
105 | pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { | |
106 | match self { | |
107 | Annotatable::Item(item) => visitor.visit_item(item), | |
108 | Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), | |
109 | Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), | |
110 | Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), | |
111 | Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), | |
112 | Annotatable::Expr(expr) => visitor.visit_expr(expr), | |
113 | Annotatable::Arm(arm) => visitor.visit_arm(arm), | |
114 | Annotatable::Field(field) => visitor.visit_field(field), | |
115 | Annotatable::FieldPat(fp) => visitor.visit_field_pattern(fp), | |
116 | Annotatable::GenericParam(gp) => visitor.visit_generic_param(gp), | |
117 | Annotatable::Param(p) => visitor.visit_param(p), | |
118 | Annotatable::StructField(sf) =>visitor.visit_struct_field(sf), | |
119 | Annotatable::Variant(v) => visitor.visit_variant(v), | |
cc61c64b XL |
120 | } |
121 | } | |
122 | ||
85aaf69f SL |
123 | pub fn expect_item(self) -> P<ast::Item> { |
124 | match self { | |
125 | Annotatable::Item(i) => i, | |
126 | _ => panic!("expected Item") | |
127 | } | |
128 | } | |
129 | ||
d9579d0f AL |
130 | pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable |
131 | where F: FnMut(P<ast::Item>) -> P<ast::Item>, | |
132 | G: FnMut(Annotatable) -> Annotatable | |
133 | { | |
134 | match self { | |
135 | Annotatable::Item(i) => Annotatable::Item(f(i)), | |
136 | _ => or(self) | |
137 | } | |
138 | } | |
139 | ||
7453a54e | 140 | pub fn expect_trait_item(self) -> ast::TraitItem { |
85aaf69f | 141 | match self { |
ff7c6d11 | 142 | Annotatable::TraitItem(i) => i.into_inner(), |
85aaf69f SL |
143 | _ => panic!("expected Item") |
144 | } | |
145 | } | |
146 | ||
7453a54e | 147 | pub fn expect_impl_item(self) -> ast::ImplItem { |
85aaf69f | 148 | match self { |
ff7c6d11 | 149 | Annotatable::ImplItem(i) => i.into_inner(), |
85aaf69f SL |
150 | _ => panic!("expected Item") |
151 | } | |
152 | } | |
ff7c6d11 | 153 | |
83c7162d XL |
154 | pub fn expect_foreign_item(self) -> ast::ForeignItem { |
155 | match self { | |
156 | Annotatable::ForeignItem(i) => i.into_inner(), | |
157 | _ => panic!("expected foreign item") | |
158 | } | |
159 | } | |
160 | ||
0531ce1d XL |
161 | pub fn expect_stmt(self) -> ast::Stmt { |
162 | match self { | |
163 | Annotatable::Stmt(stmt) => stmt.into_inner(), | |
164 | _ => panic!("expected statement"), | |
165 | } | |
166 | } | |
167 | ||
168 | pub fn expect_expr(self) -> P<ast::Expr> { | |
169 | match self { | |
170 | Annotatable::Expr(expr) => expr, | |
171 | _ => panic!("expected expression"), | |
172 | } | |
173 | } | |
174 | ||
e1599b0c XL |
175 | pub fn expect_arm(self) -> ast::Arm { |
176 | match self { | |
177 | Annotatable::Arm(arm) => arm, | |
178 | _ => panic!("expected match arm") | |
179 | } | |
180 | } | |
181 | ||
182 | pub fn expect_field(self) -> ast::Field { | |
183 | match self { | |
184 | Annotatable::Field(field) => field, | |
185 | _ => panic!("expected field") | |
186 | } | |
187 | } | |
188 | ||
189 | pub fn expect_field_pattern(self) -> ast::FieldPat { | |
190 | match self { | |
191 | Annotatable::FieldPat(fp) => fp, | |
192 | _ => panic!("expected field pattern") | |
193 | } | |
194 | } | |
195 | ||
196 | pub fn expect_generic_param(self) -> ast::GenericParam { | |
197 | match self { | |
198 | Annotatable::GenericParam(gp) => gp, | |
199 | _ => panic!("expected generic parameter") | |
200 | } | |
201 | } | |
202 | ||
203 | pub fn expect_param(self) -> ast::Param { | |
204 | match self { | |
205 | Annotatable::Param(param) => param, | |
206 | _ => panic!("expected parameter") | |
207 | } | |
208 | } | |
209 | ||
210 | pub fn expect_struct_field(self) -> ast::StructField { | |
211 | match self { | |
212 | Annotatable::StructField(sf) => sf, | |
213 | _ => panic!("expected struct field") | |
214 | } | |
215 | } | |
216 | ||
217 | pub fn expect_variant(self) -> ast::Variant { | |
218 | match self { | |
219 | Annotatable::Variant(v) => v, | |
220 | _ => panic!("expected variant") | |
221 | } | |
222 | } | |
223 | ||
ff7c6d11 XL |
224 | pub fn derive_allowed(&self) -> bool { |
225 | match *self { | |
e74abb32 | 226 | Annotatable::Item(ref item) => match item.kind { |
ff7c6d11 XL |
227 | ast::ItemKind::Struct(..) | |
228 | ast::ItemKind::Enum(..) | | |
229 | ast::ItemKind::Union(..) => true, | |
230 | _ => false, | |
231 | }, | |
232 | _ => false, | |
233 | } | |
234 | } | |
85aaf69f SL |
235 | } |
236 | ||
3157f602 | 237 | // `meta_item` is the annotation, and `item` is the item being modified. |
85aaf69f SL |
238 | // FIXME Decorators should follow the same pattern too. |
239 | pub trait MultiItemModifier { | |
240 | fn expand(&self, | |
9fa01778 | 241 | ecx: &mut ExtCtxt<'_>, |
85aaf69f SL |
242 | span: Span, |
243 | meta_item: &ast::MetaItem, | |
244 | item: Annotatable) | |
3157f602 | 245 | -> Vec<Annotatable>; |
85aaf69f SL |
246 | } |
247 | ||
3157f602 | 248 | impl<F, T> MultiItemModifier for F |
9fa01778 | 249 | where F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> T, |
3157f602 | 250 | T: Into<Vec<Annotatable>>, |
85aaf69f SL |
251 | { |
252 | fn expand(&self, | |
9fa01778 | 253 | ecx: &mut ExtCtxt<'_>, |
85aaf69f SL |
254 | span: Span, |
255 | meta_item: &ast::MetaItem, | |
256 | item: Annotatable) | |
3157f602 XL |
257 | -> Vec<Annotatable> { |
258 | (*self)(ecx, span, meta_item, item).into() | |
259 | } | |
260 | } | |
261 | ||
262 | impl Into<Vec<Annotatable>> for Annotatable { | |
263 | fn into(self) -> Vec<Annotatable> { | |
264 | vec![self] | |
85aaf69f SL |
265 | } |
266 | } | |
267 | ||
9e0c209e SL |
268 | pub trait ProcMacro { |
269 | fn expand<'cx>(&self, | |
9fa01778 | 270 | ecx: &'cx mut ExtCtxt<'_>, |
9e0c209e SL |
271 | span: Span, |
272 | ts: TokenStream) | |
273 | -> TokenStream; | |
274 | } | |
275 | ||
276 | impl<F> ProcMacro for F | |
277 | where F: Fn(TokenStream) -> TokenStream | |
278 | { | |
279 | fn expand<'cx>(&self, | |
9fa01778 | 280 | _ecx: &'cx mut ExtCtxt<'_>, |
9e0c209e SL |
281 | _span: Span, |
282 | ts: TokenStream) | |
283 | -> TokenStream { | |
284 | // FIXME setup implicit context in TLS before calling self. | |
285 | (*self)(ts) | |
286 | } | |
287 | } | |
288 | ||
289 | pub trait AttrProcMacro { | |
290 | fn expand<'cx>(&self, | |
9fa01778 | 291 | ecx: &'cx mut ExtCtxt<'_>, |
9e0c209e SL |
292 | span: Span, |
293 | annotation: TokenStream, | |
294 | annotated: TokenStream) | |
295 | -> TokenStream; | |
296 | } | |
297 | ||
298 | impl<F> AttrProcMacro for F | |
299 | where F: Fn(TokenStream, TokenStream) -> TokenStream | |
300 | { | |
301 | fn expand<'cx>(&self, | |
9fa01778 | 302 | _ecx: &'cx mut ExtCtxt<'_>, |
9e0c209e SL |
303 | _span: Span, |
304 | annotation: TokenStream, | |
305 | annotated: TokenStream) | |
306 | -> TokenStream { | |
307 | // FIXME setup implicit context in TLS before calling self. | |
308 | (*self)(annotation, annotated) | |
309 | } | |
310 | } | |
311 | ||
1a4d82fc JJ |
312 | /// Represents a thing that maps token trees to Macro Results |
313 | pub trait TTMacroExpander { | |
a1dfa0c6 XL |
314 | fn expand<'cx>( |
315 | &self, | |
9fa01778 | 316 | ecx: &'cx mut ExtCtxt<'_>, |
a1dfa0c6 XL |
317 | span: Span, |
318 | input: TokenStream, | |
a1dfa0c6 | 319 | ) -> Box<dyn MacResult+'cx>; |
223e47cc LB |
320 | } |
321 | ||
1a4d82fc | 322 | pub type MacroExpanderFn = |
e1599b0c | 323 | for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) |
8faf50e0 | 324 | -> Box<dyn MacResult+'cx>; |
223e47cc | 325 | |
1a4d82fc | 326 | impl<F> TTMacroExpander for F |
e1599b0c | 327 | where F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) |
8faf50e0 | 328 | -> Box<dyn MacResult+'cx> |
1a4d82fc | 329 | { |
a1dfa0c6 XL |
330 | fn expand<'cx>( |
331 | &self, | |
9fa01778 | 332 | ecx: &'cx mut ExtCtxt<'_>, |
a1dfa0c6 | 333 | span: Span, |
e1599b0c | 334 | mut input: TokenStream, |
a1dfa0c6 | 335 | ) -> Box<dyn MacResult+'cx> { |
cc61c64b XL |
336 | struct AvoidInterpolatedIdents; |
337 | ||
9fa01778 XL |
338 | impl MutVisitor for AvoidInterpolatedIdents { |
339 | fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { | |
dc9dc135 XL |
340 | if let tokenstream::TokenTree::Token(token) = tt { |
341 | if let token::Interpolated(nt) = &token.kind { | |
342 | if let token::NtIdent(ident, is_raw) = **nt { | |
343 | *tt = tokenstream::TokenTree::token( | |
344 | token::Ident(ident.name, is_raw), ident.span | |
345 | ); | |
346 | } | |
cc61c64b XL |
347 | } |
348 | } | |
9fa01778 | 349 | mut_visit::noop_visit_tt(tt, self) |
cc61c64b XL |
350 | } |
351 | ||
9fa01778 XL |
352 | fn visit_mac(&mut self, mac: &mut ast::Mac) { |
353 | mut_visit::noop_visit_mac(mac, self) | |
cc61c64b XL |
354 | } |
355 | } | |
e1599b0c XL |
356 | AvoidInterpolatedIdents.visit_tts(&mut input); |
357 | (*self)(ecx, span, input) | |
1a4d82fc | 358 | } |
223e47cc LB |
359 | } |
360 | ||
c34b1796 | 361 | // Use a macro because forwarding to a simple function has type system issues |
9346a6ac | 362 | macro_rules! make_stmts_default { |
c34b1796 | 363 | ($me:expr) => { |
b7449926 | 364 | $me.make_expr().map(|e| smallvec![ast::Stmt { |
3157f602 XL |
365 | id: ast::DUMMY_NODE_ID, |
366 | span: e.span, | |
e74abb32 | 367 | kind: ast::StmtKind::Expr(e), |
b7449926 | 368 | }]) |
c34b1796 AL |
369 | } |
370 | } | |
371 | ||
1a4d82fc | 372 | /// The result of a macro expansion. The return values of the various |
c34b1796 | 373 | /// methods are spliced into the AST at the callsite of the macro. |
1a4d82fc | 374 | pub trait MacResult { |
9fa01778 | 375 | /// Creates an expression. |
1a4d82fc JJ |
376 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { |
377 | None | |
378 | } | |
9fa01778 | 379 | /// Creates zero or more items. |
0bf4aa26 | 380 | fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
1a4d82fc JJ |
381 | None |
382 | } | |
223e47cc | 383 | |
9fa01778 | 384 | /// Creates zero or more impl items. |
0bf4aa26 | 385 | fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> { |
1a4d82fc JJ |
386 | None |
387 | } | |
223e47cc | 388 | |
9fa01778 | 389 | /// Creates zero or more trait items. |
0bf4aa26 | 390 | fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> { |
3157f602 XL |
391 | None |
392 | } | |
393 | ||
9fa01778 | 394 | /// Creates zero or more items in an `extern {}` block |
0bf4aa26 | 395 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[ast::ForeignItem; 1]>> { None } |
83c7162d | 396 | |
9fa01778 | 397 | /// Creates a pattern. |
1a4d82fc JJ |
398 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { |
399 | None | |
400 | } | |
223e47cc | 401 | |
9fa01778 | 402 | /// Creates zero or more statements. |
1a4d82fc JJ |
403 | /// |
404 | /// By default this attempts to create an expression statement, | |
405 | /// returning None if that fails. | |
0bf4aa26 | 406 | fn make_stmts(self: Box<Self>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
9346a6ac | 407 | make_stmts_default!(self) |
1a4d82fc | 408 | } |
e9174d1e SL |
409 | |
410 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
411 | None | |
412 | } | |
e1599b0c XL |
413 | |
414 | fn make_arms(self: Box<Self>) -> Option<SmallVec<[ast::Arm; 1]>> { | |
415 | None | |
416 | } | |
417 | ||
418 | fn make_fields(self: Box<Self>) -> Option<SmallVec<[ast::Field; 1]>> { | |
419 | None | |
420 | } | |
421 | ||
422 | fn make_field_patterns(self: Box<Self>) -> Option<SmallVec<[ast::FieldPat; 1]>> { | |
423 | None | |
424 | } | |
425 | ||
426 | fn make_generic_params(self: Box<Self>) -> Option<SmallVec<[ast::GenericParam; 1]>> { | |
427 | None | |
428 | } | |
429 | ||
430 | fn make_params(self: Box<Self>) -> Option<SmallVec<[ast::Param; 1]>> { | |
431 | None | |
432 | } | |
433 | ||
434 | fn make_struct_fields(self: Box<Self>) -> Option<SmallVec<[ast::StructField; 1]>> { | |
435 | None | |
436 | } | |
437 | ||
438 | fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> { | |
439 | None | |
440 | } | |
1a4d82fc | 441 | } |
223e47cc | 442 | |
c34b1796 AL |
443 | macro_rules! make_MacEager { |
444 | ( $( $fld:ident: $t:ty, )* ) => { | |
445 | /// `MacResult` implementation for the common case where you've already | |
446 | /// built each form of AST that you might return. | |
447 | #[derive(Default)] | |
448 | pub struct MacEager { | |
449 | $( | |
450 | pub $fld: Option<$t>, | |
451 | )* | |
452 | } | |
453 | ||
454 | impl MacEager { | |
455 | $( | |
8faf50e0 | 456 | pub fn $fld(v: $t) -> Box<dyn MacResult> { |
d9579d0f | 457 | Box::new(MacEager { |
c34b1796 AL |
458 | $fld: Some(v), |
459 | ..Default::default() | |
d9579d0f | 460 | }) |
c34b1796 AL |
461 | } |
462 | )* | |
1a4d82fc JJ |
463 | } |
464 | } | |
465 | } | |
c34b1796 AL |
466 | |
467 | make_MacEager! { | |
468 | expr: P<ast::Expr>, | |
469 | pat: P<ast::Pat>, | |
0bf4aa26 XL |
470 | items: SmallVec<[P<ast::Item>; 1]>, |
471 | impl_items: SmallVec<[ast::ImplItem; 1]>, | |
472 | trait_items: SmallVec<[ast::TraitItem; 1]>, | |
473 | foreign_items: SmallVec<[ast::ForeignItem; 1]>, | |
474 | stmts: SmallVec<[ast::Stmt; 1]>, | |
e9174d1e | 475 | ty: P<ast::Ty>, |
1a4d82fc | 476 | } |
c34b1796 AL |
477 | |
478 | impl MacResult for MacEager { | |
479 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { | |
480 | self.expr | |
1a4d82fc | 481 | } |
c34b1796 | 482 | |
0bf4aa26 | 483 | fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
c34b1796 | 484 | self.items |
1a4d82fc | 485 | } |
223e47cc | 486 | |
0bf4aa26 | 487 | fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> { |
c34b1796 | 488 | self.impl_items |
1a4d82fc | 489 | } |
223e47cc | 490 | |
0bf4aa26 | 491 | fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> { |
3157f602 XL |
492 | self.trait_items |
493 | } | |
494 | ||
0bf4aa26 | 495 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[ast::ForeignItem; 1]>> { |
83c7162d XL |
496 | self.foreign_items |
497 | } | |
498 | ||
0bf4aa26 | 499 | fn make_stmts(self: Box<Self>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
9346a6ac AL |
500 | match self.stmts.as_ref().map_or(0, |s| s.len()) { |
501 | 0 => make_stmts_default!(self), | |
502 | _ => self.stmts, | |
c34b1796 AL |
503 | } |
504 | } | |
505 | ||
506 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { | |
507 | if let Some(p) = self.pat { | |
508 | return Some(p); | |
509 | } | |
510 | if let Some(e) = self.expr { | |
e74abb32 | 511 | if let ast::ExprKind::Lit(_) = e.kind { |
c34b1796 AL |
512 | return Some(P(ast::Pat { |
513 | id: ast::DUMMY_NODE_ID, | |
514 | span: e.span, | |
e74abb32 | 515 | kind: PatKind::Lit(e), |
c34b1796 AL |
516 | })); |
517 | } | |
518 | } | |
519 | None | |
1a4d82fc | 520 | } |
e9174d1e SL |
521 | |
522 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
523 | self.ty | |
524 | } | |
1a4d82fc | 525 | } |
223e47cc | 526 | |
1a4d82fc JJ |
527 | /// Fill-in macro expansion result, to allow compilation to continue |
528 | /// after hitting errors. | |
c34b1796 | 529 | #[derive(Copy, Clone)] |
1a4d82fc | 530 | pub struct DummyResult { |
0731742a XL |
531 | is_error: bool, |
532 | span: Span, | |
223e47cc LB |
533 | } |
534 | ||
1a4d82fc | 535 | impl DummyResult { |
9fa01778 | 536 | /// Creates a default MacResult that can be anything. |
1a4d82fc JJ |
537 | /// |
538 | /// Use this as a return value after hitting any errors and | |
539 | /// calling `span_err`. | |
0731742a | 540 | pub fn any(span: Span) -> Box<dyn MacResult+'static> { |
e1599b0c | 541 | Box::new(DummyResult { is_error: true, span }) |
0731742a XL |
542 | } |
543 | ||
544 | /// Same as `any`, but must be a valid fragment, not error. | |
545 | pub fn any_valid(span: Span) -> Box<dyn MacResult+'static> { | |
e1599b0c | 546 | Box::new(DummyResult { is_error: false, span }) |
1a4d82fc JJ |
547 | } |
548 | ||
549 | /// A plain dummy expression. | |
0731742a | 550 | pub fn raw_expr(sp: Span, is_error: bool) -> P<ast::Expr> { |
1a4d82fc JJ |
551 | P(ast::Expr { |
552 | id: ast::DUMMY_NODE_ID, | |
e74abb32 | 553 | kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, |
1a4d82fc | 554 | span: sp, |
b7449926 | 555 | attrs: ThinVec::new(), |
1a4d82fc JJ |
556 | }) |
557 | } | |
558 | ||
559 | /// A plain dummy pattern. | |
560 | pub fn raw_pat(sp: Span) -> ast::Pat { | |
561 | ast::Pat { | |
562 | id: ast::DUMMY_NODE_ID, | |
e74abb32 | 563 | kind: PatKind::Wild, |
1a4d82fc JJ |
564 | span: sp, |
565 | } | |
566 | } | |
567 | ||
0731742a XL |
568 | /// A plain dummy type. |
569 | pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> { | |
e9174d1e SL |
570 | P(ast::Ty { |
571 | id: ast::DUMMY_NODE_ID, | |
e74abb32 | 572 | kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, |
e9174d1e SL |
573 | span: sp |
574 | }) | |
575 | } | |
1a4d82fc JJ |
576 | } |
577 | ||
578 | impl MacResult for DummyResult { | |
579 | fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> { | |
0731742a | 580 | Some(DummyResult::raw_expr(self.span, self.is_error)) |
1a4d82fc | 581 | } |
e9174d1e | 582 | |
1a4d82fc JJ |
583 | fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> { |
584 | Some(P(DummyResult::raw_pat(self.span))) | |
585 | } | |
e9174d1e | 586 | |
0bf4aa26 | 587 | fn make_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
e1599b0c | 588 | Some(SmallVec::new()) |
1a4d82fc | 589 | } |
e9174d1e | 590 | |
0bf4aa26 | 591 | fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::ImplItem; 1]>> { |
e1599b0c | 592 | Some(SmallVec::new()) |
1a4d82fc | 593 | } |
e9174d1e | 594 | |
0bf4aa26 | 595 | fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::TraitItem; 1]>> { |
e1599b0c | 596 | Some(SmallVec::new()) |
3157f602 XL |
597 | } |
598 | ||
0bf4aa26 | 599 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[ast::ForeignItem; 1]>> { |
e1599b0c | 600 | Some(SmallVec::new()) |
83c7162d XL |
601 | } |
602 | ||
0bf4aa26 | 603 | fn make_stmts(self: Box<DummyResult>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
b7449926 | 604 | Some(smallvec![ast::Stmt { |
3157f602 | 605 | id: ast::DUMMY_NODE_ID, |
e74abb32 | 606 | kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), |
3157f602 | 607 | span: self.span, |
b7449926 | 608 | }]) |
3157f602 XL |
609 | } |
610 | ||
611 | fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { | |
0731742a | 612 | Some(DummyResult::raw_ty(self.span, self.is_error)) |
1a4d82fc | 613 | } |
e1599b0c XL |
614 | |
615 | fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> { | |
616 | Some(SmallVec::new()) | |
617 | } | |
618 | ||
619 | fn make_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::Field; 1]>> { | |
620 | Some(SmallVec::new()) | |
621 | } | |
622 | ||
623 | fn make_field_patterns(self: Box<DummyResult>) -> Option<SmallVec<[ast::FieldPat; 1]>> { | |
624 | Some(SmallVec::new()) | |
625 | } | |
626 | ||
627 | fn make_generic_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::GenericParam; 1]>> { | |
628 | Some(SmallVec::new()) | |
629 | } | |
630 | ||
631 | fn make_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::Param; 1]>> { | |
632 | Some(SmallVec::new()) | |
633 | } | |
634 | ||
635 | fn make_struct_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::StructField; 1]>> { | |
636 | Some(SmallVec::new()) | |
637 | } | |
638 | ||
639 | fn make_variants(self: Box<DummyResult>) -> Option<SmallVec<[ast::Variant; 1]>> { | |
640 | Some(SmallVec::new()) | |
641 | } | |
1a4d82fc JJ |
642 | } |
643 | ||
dc9dc135 XL |
644 | /// A syntax extension kind. |
645 | pub enum SyntaxExtensionKind { | |
646 | /// A token-based function-like macro. | |
647 | Bang( | |
648 | /// An expander with signature TokenStream -> TokenStream. | |
649 | Box<dyn ProcMacro + sync::Sync + sync::Send>, | |
650 | ), | |
651 | ||
652 | /// An AST-based function-like macro. | |
653 | LegacyBang( | |
654 | /// An expander with signature TokenStream -> AST. | |
655 | Box<dyn TTMacroExpander + sync::Sync + sync::Send>, | |
656 | ), | |
657 | ||
658 | /// A token-based attribute macro. | |
659 | Attr( | |
660 | /// An expander with signature (TokenStream, TokenStream) -> TokenStream. | |
661 | /// The first TokenSteam is the attribute itself, the second is the annotated item. | |
662 | /// The produced TokenSteam replaces the input TokenSteam. | |
663 | Box<dyn AttrProcMacro + sync::Sync + sync::Send>, | |
664 | ), | |
665 | ||
666 | /// An AST-based attribute macro. | |
667 | LegacyAttr( | |
668 | /// An expander with signature (AST, AST) -> AST. | |
669 | /// The first AST fragment is the attribute itself, the second is the annotated item. | |
670 | /// The produced AST fragment replaces the input AST fragment. | |
671 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
672 | ), | |
673 | ||
674 | /// A trivial attribute "macro" that does nothing, | |
675 | /// only keeps the attribute and marks it as inert, | |
676 | /// thus making it ineligible for further expansion. | |
677 | NonMacroAttr { | |
678 | /// Suppresses the `unused_attributes` lint for this attribute. | |
679 | mark_used: bool, | |
8faf50e0 | 680 | }, |
9e0c209e | 681 | |
dc9dc135 XL |
682 | /// A token-based derive macro. |
683 | Derive( | |
684 | /// An expander with signature TokenStream -> TokenStream (not yet). | |
685 | /// The produced TokenSteam is appended to the input TokenSteam. | |
686 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
687 | ), | |
688 | ||
689 | /// An AST-based derive macro. | |
690 | LegacyDerive( | |
691 | /// An expander with signature AST -> AST. | |
692 | /// The produced AST fragment is appended to the input AST fragment. | |
693 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
694 | ), | |
695 | } | |
696 | ||
697 | /// A struct representing a macro definition in "lowered" form ready for expansion. | |
698 | pub struct SyntaxExtension { | |
699 | /// A syntax extension kind. | |
700 | pub kind: SyntaxExtensionKind, | |
416331ca XL |
701 | /// Span of the macro definition. |
702 | pub span: Span, | |
dc9dc135 XL |
703 | /// Whitelist of unstable features that are treated as stable inside this macro. |
704 | pub allow_internal_unstable: Option<Lrc<[Symbol]>>, | |
705 | /// Suppresses the `unsafe_code` lint for code produced by this macro. | |
706 | pub allow_internal_unsafe: bool, | |
707 | /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. | |
708 | pub local_inner_macros: bool, | |
416331ca XL |
709 | /// The macro's stability info. |
710 | pub stability: Option<Stability>, | |
711 | /// The macro's deprecation info. | |
712 | pub deprecation: Option<Deprecation>, | |
dc9dc135 XL |
713 | /// Names of helper attributes registered by this macro. |
714 | pub helper_attrs: Vec<Symbol>, | |
715 | /// Edition of the crate in which this macro is defined. | |
716 | pub edition: Edition, | |
416331ca XL |
717 | /// Built-in macros have a couple of special properties like availability |
718 | /// in `#[no_implicit_prelude]` modules, so we have to keep this flag. | |
719 | pub is_builtin: bool, | |
720 | /// We have to identify macros providing a `Copy` impl early for compatibility reasons. | |
721 | pub is_derive_copy: bool, | |
dc9dc135 XL |
722 | } |
723 | ||
8bb4bdeb | 724 | impl SyntaxExtension { |
9fa01778 | 725 | /// Returns which kind of macro calls this syntax extension. |
dc9dc135 XL |
726 | pub fn macro_kind(&self) -> MacroKind { |
727 | match self.kind { | |
728 | SyntaxExtensionKind::Bang(..) | | |
729 | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang, | |
730 | SyntaxExtensionKind::Attr(..) | | |
731 | SyntaxExtensionKind::LegacyAttr(..) | | |
732 | SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr, | |
733 | SyntaxExtensionKind::Derive(..) | | |
734 | SyntaxExtensionKind::LegacyDerive(..) => MacroKind::Derive, | |
7cac9316 XL |
735 | } |
736 | } | |
94b46f34 | 737 | |
dc9dc135 XL |
738 | /// Constructs a syntax extension with default properties. |
739 | pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { | |
740 | SyntaxExtension { | |
416331ca | 741 | span: DUMMY_SP, |
dc9dc135 XL |
742 | allow_internal_unstable: None, |
743 | allow_internal_unsafe: false, | |
744 | local_inner_macros: false, | |
416331ca XL |
745 | stability: None, |
746 | deprecation: None, | |
dc9dc135 XL |
747 | helper_attrs: Vec::new(), |
748 | edition, | |
416331ca XL |
749 | is_builtin: false, |
750 | is_derive_copy: false, | |
dc9dc135 XL |
751 | kind, |
752 | } | |
753 | } | |
754 | ||
e1599b0c XL |
755 | /// Constructs a syntax extension with the given properties |
756 | /// and other properties converted from attributes. | |
757 | pub fn new( | |
758 | sess: &ParseSess, | |
759 | kind: SyntaxExtensionKind, | |
760 | span: Span, | |
761 | helper_attrs: Vec<Symbol>, | |
762 | edition: Edition, | |
763 | name: Name, | |
764 | attrs: &[ast::Attribute], | |
765 | ) -> SyntaxExtension { | |
766 | let allow_internal_unstable = attr::allow_internal_unstable( | |
767 | &attrs, &sess.span_diagnostic, | |
768 | ).map(|features| features.collect::<Vec<Symbol>>().into()); | |
769 | ||
770 | let mut local_inner_macros = false; | |
771 | if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) { | |
772 | if let Some(l) = macro_export.meta_item_list() { | |
773 | local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); | |
774 | } | |
775 | } | |
776 | ||
777 | let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro); | |
60c5eb7d XL |
778 | let (stability, const_stability) = attr::find_stability(&sess, attrs, span); |
779 | if const_stability.is_some() { | |
780 | sess.span_diagnostic.span_err(span, "macros cannot have const stability attributes"); | |
781 | } | |
e1599b0c XL |
782 | |
783 | SyntaxExtension { | |
784 | kind, | |
785 | span, | |
786 | allow_internal_unstable, | |
787 | allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe), | |
788 | local_inner_macros, | |
60c5eb7d | 789 | stability, |
e1599b0c XL |
790 | deprecation: attr::find_deprecation(&sess, attrs, span), |
791 | helper_attrs, | |
792 | edition, | |
793 | is_builtin, | |
794 | is_derive_copy: is_builtin && name == sym::Copy, | |
795 | } | |
796 | } | |
797 | ||
416331ca | 798 | pub fn dummy_bang(edition: Edition) -> SyntaxExtension { |
e1599b0c | 799 | fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: TokenStream) |
416331ca XL |
800 | -> Box<dyn MacResult + 'cx> { |
801 | DummyResult::any(span) | |
dc9dc135 | 802 | } |
416331ca | 803 | SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) |
dc9dc135 XL |
804 | } |
805 | ||
416331ca XL |
806 | pub fn dummy_derive(edition: Edition) -> SyntaxExtension { |
807 | fn expander(_: &mut ExtCtxt<'_>, _: Span, _: &ast::MetaItem, _: Annotatable) | |
808 | -> Vec<Annotatable> { | |
809 | Vec::new() | |
810 | } | |
811 | SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition) | |
812 | } | |
813 | ||
814 | pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension { | |
815 | SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition) | |
816 | } | |
817 | ||
e1599b0c XL |
818 | pub fn expn_data(&self, parent: ExpnId, call_site: Span, descr: Symbol) -> ExpnData { |
819 | ExpnData { | |
416331ca | 820 | kind: ExpnKind::Macro(self.macro_kind(), descr), |
e1599b0c XL |
821 | parent, |
822 | call_site, | |
416331ca | 823 | def_site: self.span, |
dc9dc135 XL |
824 | allow_internal_unstable: self.allow_internal_unstable.clone(), |
825 | allow_internal_unsafe: self.allow_internal_unsafe, | |
826 | local_inner_macros: self.local_inner_macros, | |
827 | edition: self.edition, | |
94b46f34 XL |
828 | } |
829 | } | |
1a4d82fc JJ |
830 | } |
831 | ||
e1599b0c XL |
832 | /// Result of resolving a macro invocation. |
833 | pub enum InvocationRes { | |
834 | Single(Lrc<SyntaxExtension>), | |
835 | DeriveContainer(Vec<Lrc<SyntaxExtension>>), | |
836 | } | |
837 | ||
416331ca XL |
838 | /// Error type that denotes indeterminacy. |
839 | pub struct Indeterminate; | |
840 | ||
9e0c209e | 841 | pub trait Resolver { |
e1599b0c | 842 | fn next_node_id(&mut self) -> NodeId; |
9e0c209e | 843 | |
416331ca | 844 | fn resolve_dollar_crates(&mut self); |
e74abb32 | 845 | fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment); |
416331ca | 846 | fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension); |
9e0c209e | 847 | |
e1599b0c XL |
848 | fn expansion_for_ast_pass( |
849 | &mut self, | |
850 | call_site: Span, | |
851 | pass: AstPass, | |
852 | features: &[Symbol], | |
853 | parent_module_id: Option<NodeId>, | |
854 | ) -> ExpnId; | |
855 | ||
476ff2be | 856 | fn resolve_imports(&mut self); |
0531ce1d | 857 | |
e1599b0c XL |
858 | fn resolve_macro_invocation( |
859 | &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool | |
860 | ) -> Result<InvocationRes, Indeterminate>; | |
b7449926 | 861 | |
e74abb32 | 862 | fn check_unused_macros(&mut self); |
970d7e83 | 863 | |
60c5eb7d XL |
864 | fn has_derive_copy(&self, expn_id: ExpnId) -> bool; |
865 | fn add_derive_copy(&mut self, expn_id: ExpnId); | |
b7449926 XL |
866 | } |
867 | ||
9e0c209e SL |
868 | #[derive(Clone)] |
869 | pub struct ModuleData { | |
870 | pub mod_path: Vec<ast::Ident>, | |
871 | pub directory: PathBuf, | |
872 | } | |
873 | ||
874 | #[derive(Clone)] | |
875 | pub struct ExpansionData { | |
416331ca | 876 | pub id: ExpnId, |
9e0c209e | 877 | pub depth: usize, |
9e0c209e | 878 | pub module: Rc<ModuleData>, |
476ff2be | 879 | pub directory_ownership: DirectoryOwnership, |
416331ca | 880 | pub prior_type_ascription: Option<(Span, bool)>, |
3157f602 XL |
881 | } |
882 | ||
1a4d82fc | 883 | /// One of these is made during expansion and incrementally updated as we go; |
7cac9316 | 884 | /// when a macro expansion occurs, the resulting nodes have the `backtrace() |
e1599b0c | 885 | /// -> expn_data` of their expansion context stored into their span. |
1a4d82fc | 886 | pub struct ExtCtxt<'a> { |
e74abb32 | 887 | pub parse_sess: &'a ParseSess, |
85aaf69f | 888 | pub ecfg: expand::ExpansionConfig<'a>, |
ff7c6d11 | 889 | pub root_path: PathBuf, |
8faf50e0 | 890 | pub resolver: &'a mut dyn Resolver, |
9e0c209e | 891 | pub current_expansion: ExpansionData, |
b7449926 | 892 | pub expansions: FxHashMap<Span, Vec<String>>, |
1a4d82fc JJ |
893 | } |
894 | ||
895 | impl<'a> ExtCtxt<'a> { | |
e74abb32 | 896 | pub fn new(parse_sess: &'a ParseSess, |
e9174d1e | 897 | ecfg: expand::ExpansionConfig<'a>, |
8faf50e0 | 898 | resolver: &'a mut dyn Resolver) |
3157f602 | 899 | -> ExtCtxt<'a> { |
1a4d82fc | 900 | ExtCtxt { |
3b2f2976 XL |
901 | parse_sess, |
902 | ecfg, | |
ff7c6d11 | 903 | root_path: PathBuf::new(), |
3b2f2976 | 904 | resolver, |
9e0c209e | 905 | current_expansion: ExpansionData { |
416331ca | 906 | id: ExpnId::root(), |
9e0c209e | 907 | depth: 0, |
9e0c209e | 908 | module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), |
ff7c6d11 | 909 | directory_ownership: DirectoryOwnership::Owned { relative: None }, |
416331ca | 910 | prior_type_ascription: None, |
9e0c209e | 911 | }, |
b7449926 | 912 | expansions: FxHashMap::default(), |
970d7e83 LB |
913 | } |
914 | } | |
915 | ||
b039eaaf | 916 | /// Returns a `Folder` for deeply expanding all macros in an AST node. |
1a4d82fc | 917 | pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { |
9e0c209e SL |
918 | expand::MacroExpander::new(self, false) |
919 | } | |
920 | ||
9fa01778 XL |
921 | /// Returns a `Folder` that deeply expands all macros and assigns all `NodeId`s in an AST node. |
922 | /// Once `NodeId`s are assigned, the node may not be expanded, removed, or otherwise modified. | |
9e0c209e SL |
923 | pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { |
924 | expand::MacroExpander::new(self, true) | |
1a4d82fc | 925 | } |
e1599b0c | 926 | pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { |
60c5eb7d | 927 | rustc_parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS) |
1a4d82fc | 928 | } |
b7449926 | 929 | pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() } |
e74abb32 | 930 | pub fn parse_sess(&self) -> &'a ParseSess { self.parse_sess } |
1a4d82fc | 931 | pub fn call_site(&self) -> Span { |
e1599b0c XL |
932 | self.current_expansion.id.expn_data().call_site |
933 | } | |
934 | ||
935 | /// Equivalent of `Span::def_site` from the proc macro API, | |
936 | /// except that the location is taken from the span passed as an argument. | |
937 | pub fn with_def_site_ctxt(&self, span: Span) -> Span { | |
938 | span.with_def_site_ctxt(self.current_expansion.id) | |
cc61c64b | 939 | } |
e1599b0c XL |
940 | |
941 | /// Equivalent of `Span::call_site` from the proc macro API, | |
942 | /// except that the location is taken from the span passed as an argument. | |
943 | pub fn with_call_site_ctxt(&self, span: Span) -> Span { | |
944 | span.with_call_site_ctxt(self.current_expansion.id) | |
970d7e83 | 945 | } |
d9579d0f | 946 | |
e74abb32 XL |
947 | /// Equivalent of `Span::mixed_site` from the proc macro API, |
948 | /// except that the location is taken from the span passed as an argument. | |
949 | pub fn with_mixed_site_ctxt(&self, span: Span) -> Span { | |
950 | span.with_mixed_site_ctxt(self.current_expansion.id) | |
951 | } | |
952 | ||
d9579d0f AL |
953 | /// Returns span for the macro which originally caused the current expansion to happen. |
954 | /// | |
955 | /// Stops backtracing at include! boundary. | |
cc61c64b | 956 | pub fn expansion_cause(&self) -> Option<Span> { |
60c5eb7d | 957 | self.current_expansion.id.expansion_cause() |
1a4d82fc | 958 | } |
1a4d82fc | 959 | |
2c00a5a8 XL |
960 | pub fn struct_span_warn<S: Into<MultiSpan>>(&self, |
961 | sp: S, | |
962 | msg: &str) | |
963 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
964 | self.parse_sess.span_diagnostic.struct_span_warn(sp, msg) |
965 | } | |
2c00a5a8 XL |
966 | pub fn struct_span_err<S: Into<MultiSpan>>(&self, |
967 | sp: S, | |
968 | msg: &str) | |
969 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
970 | self.parse_sess.span_diagnostic.struct_span_err(sp, msg) |
971 | } | |
2c00a5a8 XL |
972 | pub fn struct_span_fatal<S: Into<MultiSpan>>(&self, |
973 | sp: S, | |
974 | msg: &str) | |
975 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
976 | self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg) |
977 | } | |
978 | ||
1a4d82fc JJ |
979 | /// Emit `msg` attached to `sp`, and stop compilation immediately. |
980 | /// | |
981 | /// `span_err` should be strongly preferred where-ever possible: | |
ff7c6d11 XL |
982 | /// this should *only* be used when: |
983 | /// | |
0731742a | 984 | /// - continuing has a high risk of flow-on errors (e.g., errors in |
1a4d82fc JJ |
985 | /// declaring a macro would cause all uses of that macro to |
986 | /// complain about "undefined macro"), or | |
987 | /// - there is literally nothing else that can be done (however, | |
988 | /// in most cases one can construct a dummy expression/item to | |
989 | /// substitute; we never hit resolve/type-checking so the dummy | |
990 | /// value doesn't have to match anything) | |
2c00a5a8 XL |
991 | pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
992 | self.parse_sess.span_diagnostic.span_fatal(sp, msg).raise(); | |
970d7e83 | 993 | } |
1a4d82fc JJ |
994 | |
995 | /// Emit `msg` attached to `sp`, without immediately stopping | |
996 | /// compilation. | |
997 | /// | |
998 | /// Compilation will be stopped in the near future (at the end of | |
999 | /// the macro expansion phase). | |
2c00a5a8 | 1000 | pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
970d7e83 LB |
1001 | self.parse_sess.span_diagnostic.span_err(sp, msg); |
1002 | } | |
83c7162d XL |
1003 | pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { |
1004 | self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code); | |
1005 | } | |
2c00a5a8 | 1006 | pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
970d7e83 LB |
1007 | self.parse_sess.span_diagnostic.span_warn(sp, msg); |
1008 | } | |
2c00a5a8 | 1009 | pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
970d7e83 LB |
1010 | self.parse_sess.span_diagnostic.span_bug(sp, msg); |
1011 | } | |
ea8adc8c | 1012 | pub fn trace_macros_diag(&mut self) { |
7cac9316 XL |
1013 | for (sp, notes) in self.expansions.iter() { |
1014 | let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro"); | |
1015 | for note in notes { | |
1016 | db.note(note); | |
1017 | } | |
1018 | db.emit(); | |
1019 | } | |
ea8adc8c XL |
1020 | // Fixme: does this result in errors? |
1021 | self.expansions.clear(); | |
7cac9316 | 1022 | } |
970d7e83 | 1023 | pub fn bug(&self, msg: &str) -> ! { |
9cc50fc6 | 1024 | self.parse_sess.span_diagnostic.bug(msg); |
970d7e83 | 1025 | } |
970d7e83 | 1026 | pub fn trace_macros(&self) -> bool { |
d9579d0f | 1027 | self.ecfg.trace_mac |
970d7e83 | 1028 | } |
1a4d82fc | 1029 | pub fn set_trace_macros(&mut self, x: bool) { |
d9579d0f | 1030 | self.ecfg.trace_mac = x |
970d7e83 | 1031 | } |
e1599b0c XL |
1032 | pub fn ident_of(&self, st: &str, sp: Span) -> ast::Ident { |
1033 | ast::Ident::from_str_and_span(st, sp) | |
970d7e83 | 1034 | } |
dc9dc135 | 1035 | pub fn std_path(&self, components: &[Symbol]) -> Vec<ast::Ident> { |
e1599b0c | 1036 | let def_site = self.with_def_site_ctxt(DUMMY_SP); |
dc9dc135 | 1037 | iter::once(Ident::new(kw::DollarCrate, def_site)) |
e1599b0c | 1038 | .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) |
ff7c6d11 | 1039 | .collect() |
85aaf69f | 1040 | } |
1a4d82fc | 1041 | pub fn name_of(&self, st: &str) -> ast::Name { |
476ff2be | 1042 | Symbol::intern(st) |
223e47cc | 1043 | } |
7cac9316 | 1044 | |
e74abb32 | 1045 | pub fn check_unused_macros(&mut self) { |
7cac9316 XL |
1046 | self.resolver.check_unused_macros(); |
1047 | } | |
416331ca | 1048 | |
e1599b0c | 1049 | /// Resolves a path mentioned inside Rust code. |
416331ca XL |
1050 | /// |
1051 | /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. | |
1052 | /// | |
1053 | /// Returns an absolute path to the file that `path` refers to. | |
e74abb32 XL |
1054 | pub fn resolve_path( |
1055 | &self, | |
1056 | path: impl Into<PathBuf>, | |
1057 | span: Span, | |
1058 | ) -> Result<PathBuf, DiagnosticBuilder<'a>> { | |
416331ca XL |
1059 | let path = path.into(); |
1060 | ||
1061 | // Relative paths are resolved relative to the file in which they are found | |
1062 | // after macro expansion (that is, they are unhygienic). | |
1063 | if !path.is_absolute() { | |
1064 | let callsite = span.source_callsite(); | |
1065 | let mut result = match self.source_map().span_to_unmapped_path(callsite) { | |
1066 | FileName::Real(path) => path, | |
1067 | FileName::DocTest(path, _) => path, | |
e74abb32 XL |
1068 | other => return Err(self.struct_span_err( |
1069 | span, | |
1070 | &format!("cannot resolve relative path in non-file source `{}`", other), | |
1071 | )), | |
416331ca XL |
1072 | }; |
1073 | result.pop(); | |
1074 | result.push(path); | |
e74abb32 | 1075 | Ok(result) |
416331ca | 1076 | } else { |
e74abb32 | 1077 | Ok(path) |
416331ca XL |
1078 | } |
1079 | } | |
223e47cc LB |
1080 | } |
1081 | ||
9fa01778 | 1082 | /// Extracts a string literal from the macro expanded version of `expr`, |
1a4d82fc | 1083 | /// emitting `err_msg` if `expr` is not a string literal. This does not stop |
9fa01778 | 1084 | /// compilation on error, merely emits a non-fatal error and returns `None`. |
8faf50e0 | 1085 | pub fn expr_to_spanned_string<'a>( |
9fa01778 | 1086 | cx: &'a mut ExtCtxt<'_>, |
e1599b0c | 1087 | expr: P<ast::Expr>, |
8faf50e0 | 1088 | err_msg: &str, |
e1599b0c XL |
1089 | ) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> { |
1090 | // Perform eager expansion on the expression. | |
1091 | // We want to be able to handle e.g., `concat!("foo", "bar")`. | |
1092 | let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); | |
1093 | ||
e74abb32 XL |
1094 | Err(match expr.kind { |
1095 | ast::ExprKind::Lit(ref l) => match l.kind { | |
e1599b0c | 1096 | ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), |
48663c56 | 1097 | ast::LitKind::Err(_) => None, |
0731742a | 1098 | _ => Some(cx.struct_span_err(l.span, err_msg)) |
1a4d82fc | 1099 | }, |
0731742a XL |
1100 | ast::ExprKind::Err => None, |
1101 | _ => Some(cx.struct_span_err(expr.span, err_msg)) | |
8faf50e0 | 1102 | }) |
223e47cc LB |
1103 | } |
1104 | ||
9fa01778 | 1105 | pub fn expr_to_string(cx: &mut ExtCtxt<'_>, expr: P<ast::Expr>, err_msg: &str) |
476ff2be | 1106 | -> Option<(Symbol, ast::StrStyle)> { |
8faf50e0 | 1107 | expr_to_spanned_string(cx, expr, err_msg) |
0731742a | 1108 | .map_err(|err| err.map(|mut err| err.emit())) |
8faf50e0 | 1109 | .ok() |
e1599b0c | 1110 | .map(|(symbol, style, _)| (symbol, style)) |
9e0c209e SL |
1111 | } |
1112 | ||
1a4d82fc JJ |
1113 | /// Non-fatally assert that `tts` is empty. Note that this function |
1114 | /// returns even when `tts` is non-empty, macros that *need* to stop | |
1115 | /// compilation should call | |
1116 | /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be | |
1117 | /// done as rarely as possible). | |
9fa01778 | 1118 | pub fn check_zero_tts(cx: &ExtCtxt<'_>, |
1a4d82fc | 1119 | sp: Span, |
e1599b0c | 1120 | tts: TokenStream, |
223e47cc | 1121 | name: &str) { |
9346a6ac | 1122 | if !tts.is_empty() { |
c34b1796 | 1123 | cx.span_err(sp, &format!("{} takes no arguments", name)); |
223e47cc LB |
1124 | } |
1125 | } | |
1126 | ||
0531ce1d | 1127 | /// Interpreting `tts` as a comma-separated sequence of expressions, |
9fa01778 XL |
1128 | /// expect exactly one string literal, or emit an error and return `None`. |
1129 | pub fn get_single_str_from_tts(cx: &mut ExtCtxt<'_>, | |
1a4d82fc | 1130 | sp: Span, |
e1599b0c | 1131 | tts: TokenStream, |
1a4d82fc JJ |
1132 | name: &str) |
1133 | -> Option<String> { | |
1134 | let mut p = cx.new_parser_from_tts(tts); | |
1135 | if p.token == token::Eof { | |
c34b1796 | 1136 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
1a4d82fc JJ |
1137 | return None |
1138 | } | |
9e0c209e | 1139 | let ret = panictry!(p.parse_expr()); |
0531ce1d XL |
1140 | let _ = p.eat(&token::Comma); |
1141 | ||
1a4d82fc | 1142 | if p.token != token::Eof { |
c34b1796 | 1143 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
1a4d82fc JJ |
1144 | } |
1145 | expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| { | |
85aaf69f | 1146 | s.to_string() |
1a4d82fc | 1147 | }) |
223e47cc LB |
1148 | } |
1149 | ||
9fa01778 XL |
1150 | /// Extracts comma-separated expressions from `tts`. If there is a |
1151 | /// parsing error, emit a non-fatal error and return `None`. | |
1152 | pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, | |
1a4d82fc | 1153 | sp: Span, |
e1599b0c | 1154 | tts: TokenStream) -> Option<Vec<P<ast::Expr>>> { |
1a4d82fc JJ |
1155 | let mut p = cx.new_parser_from_tts(tts); |
1156 | let mut es = Vec::new(); | |
1157 | while p.token != token::Eof { | |
e1599b0c XL |
1158 | let expr = panictry!(p.parse_expr()); |
1159 | ||
1160 | // Perform eager expansion on the expression. | |
1161 | // We want to be able to handle e.g., `concat!("foo", "bar")`. | |
1162 | let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); | |
1163 | ||
9fa01778 | 1164 | es.push(expr); |
9cc50fc6 | 1165 | if p.eat(&token::Comma) { |
1a4d82fc JJ |
1166 | continue; |
1167 | } | |
1168 | if p.token != token::Eof { | |
1169 | cx.span_err(sp, "expected token: `,`"); | |
1170 | return None; | |
223e47cc | 1171 | } |
223e47cc | 1172 | } |
1a4d82fc | 1173 | Some(es) |
223e47cc | 1174 | } |