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