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