]>
Commit | Line | Data |
---|---|---|
e74abb32 | 1 | use crate::expand::{self, AstFragment, Invocation}; |
6a06907d | 2 | use crate::module::DirOwnership; |
e74abb32 | 3 | |
94222f64 | 4 | use rustc_ast::attr::MarkedAttrs; |
74b04a01 | 5 | use rustc_ast::ptr::P; |
5869c6ff | 6 | use rustc_ast::token::{self, Nonterminal}; |
cdc7bbd5 | 7 | use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; |
74b04a01 | 8 | use rustc_ast::visit::{AssocCtxt, Visitor}; |
6a06907d XL |
9 | use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; |
10 | use rustc_attr::{self as attr, Deprecation, Stability}; | |
5099ac24 | 11 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
dfeec247 | 12 | use rustc_data_structures::sync::{self, Lrc}; |
ee023bcb | 13 | use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; |
6a06907d XL |
14 | use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; |
15 | use rustc_lint_defs::BuiltinLintDiagnostics; | |
f035d41b | 16 | use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; |
3dfed10e | 17 | use rustc_session::{parse::ParseSess, Limit, Session}; |
c295e0f8 | 18 | use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; |
dfeec247 | 19 | use rustc_span::edition::Edition; |
136023e0 | 20 | use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; |
dfeec247 XL |
21 | use rustc_span::source_map::SourceMap; |
22 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; | |
ee023bcb | 23 | use rustc_span::{MultiSpan, Span, DUMMY_SP}; |
dfeec247 | 24 | use smallvec::{smallvec, SmallVec}; |
1a4d82fc | 25 | |
dfeec247 | 26 | use std::default::Default; |
ff7c6d11 | 27 | use std::iter; |
9e0c209e | 28 | use std::path::PathBuf; |
1a4d82fc JJ |
29 | use std::rc::Rc; |
30 | ||
dfeec247 | 31 | crate use rustc_span::hygiene::MacroKind; |
223e47cc | 32 | |
136023e0 XL |
33 | // When adding new variants, make sure to |
34 | // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector` | |
35 | // to use `assign_id!` | |
dfeec247 | 36 | #[derive(Debug, Clone)] |
85aaf69f SL |
37 | pub enum Annotatable { |
38 | Item(P<ast::Item>), | |
dfeec247 XL |
39 | TraitItem(P<ast::AssocItem>), |
40 | ImplItem(P<ast::AssocItem>), | |
83c7162d | 41 | ForeignItem(P<ast::ForeignItem>), |
0531ce1d XL |
42 | Stmt(P<ast::Stmt>), |
43 | Expr(P<ast::Expr>), | |
e1599b0c | 44 | Arm(ast::Arm), |
6a06907d XL |
45 | ExprField(ast::ExprField), |
46 | PatField(ast::PatField), | |
e1599b0c XL |
47 | GenericParam(ast::GenericParam), |
48 | Param(ast::Param), | |
6a06907d | 49 | FieldDef(ast::FieldDef), |
e1599b0c | 50 | Variant(ast::Variant), |
a2a8927a | 51 | Crate(ast::Crate), |
85aaf69f SL |
52 | } |
53 | ||
cdc7bbd5 XL |
54 | impl Annotatable { |
55 | pub fn span(&self) -> Span { | |
85aaf69f | 56 | match *self { |
cdc7bbd5 XL |
57 | Annotatable::Item(ref item) => item.span, |
58 | Annotatable::TraitItem(ref trait_item) => trait_item.span, | |
59 | Annotatable::ImplItem(ref impl_item) => impl_item.span, | |
60 | Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, | |
61 | Annotatable::Stmt(ref stmt) => stmt.span, | |
62 | Annotatable::Expr(ref expr) => expr.span, | |
63 | Annotatable::Arm(ref arm) => arm.span, | |
64 | Annotatable::ExprField(ref field) => field.span, | |
65 | Annotatable::PatField(ref fp) => fp.pat.span, | |
66 | Annotatable::GenericParam(ref gp) => gp.ident.span, | |
67 | Annotatable::Param(ref p) => p.span, | |
68 | Annotatable::FieldDef(ref sf) => sf.span, | |
69 | Annotatable::Variant(ref v) => v.span, | |
ee023bcb | 70 | Annotatable::Crate(ref c) => c.spans.inner_span, |
85aaf69f SL |
71 | } |
72 | } | |
73 | ||
cdc7bbd5 | 74 | pub fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
85aaf69f | 75 | match self { |
9fa01778 XL |
76 | Annotatable::Item(item) => item.visit_attrs(f), |
77 | Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f), | |
78 | Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f), | |
79 | Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f), | |
80 | Annotatable::Stmt(stmt) => stmt.visit_attrs(f), | |
81 | Annotatable::Expr(expr) => expr.visit_attrs(f), | |
e1599b0c | 82 | Annotatable::Arm(arm) => arm.visit_attrs(f), |
6a06907d XL |
83 | Annotatable::ExprField(field) => field.visit_attrs(f), |
84 | Annotatable::PatField(fp) => fp.visit_attrs(f), | |
e1599b0c XL |
85 | Annotatable::GenericParam(gp) => gp.visit_attrs(f), |
86 | Annotatable::Param(p) => p.visit_attrs(f), | |
6a06907d | 87 | Annotatable::FieldDef(sf) => sf.visit_attrs(f), |
e1599b0c | 88 | Annotatable::Variant(v) => v.visit_attrs(f), |
a2a8927a | 89 | Annotatable::Crate(c) => c.visit_attrs(f), |
85aaf69f SL |
90 | } |
91 | } | |
6a06907d | 92 | |
e1599b0c XL |
93 | pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { |
94 | match self { | |
95 | Annotatable::Item(item) => visitor.visit_item(item), | |
74b04a01 XL |
96 | Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait), |
97 | Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl), | |
e1599b0c XL |
98 | Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), |
99 | Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), | |
100 | Annotatable::Expr(expr) => visitor.visit_expr(expr), | |
101 | Annotatable::Arm(arm) => visitor.visit_arm(arm), | |
6a06907d XL |
102 | Annotatable::ExprField(field) => visitor.visit_expr_field(field), |
103 | Annotatable::PatField(fp) => visitor.visit_pat_field(fp), | |
e1599b0c XL |
104 | Annotatable::GenericParam(gp) => visitor.visit_generic_param(gp), |
105 | Annotatable::Param(p) => visitor.visit_param(p), | |
6a06907d | 106 | Annotatable::FieldDef(sf) => visitor.visit_field_def(sf), |
e1599b0c | 107 | Annotatable::Variant(v) => visitor.visit_variant(v), |
a2a8927a | 108 | Annotatable::Crate(c) => visitor.visit_crate(c), |
cc61c64b XL |
109 | } |
110 | } | |
111 | ||
cdc7bbd5 | 112 | pub fn into_nonterminal(self) -> Nonterminal { |
5869c6ff | 113 | match self { |
74b04a01 XL |
114 | Annotatable::Item(item) => token::NtItem(item), |
115 | Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { | |
116 | token::NtItem(P(item.and_then(ast::AssocItem::into_item))) | |
117 | } | |
118 | Annotatable::ForeignItem(item) => { | |
119 | token::NtItem(P(item.and_then(ast::ForeignItem::into_item))) | |
120 | } | |
121 | Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), | |
122 | Annotatable::Expr(expr) => token::NtExpr(expr), | |
123 | Annotatable::Arm(..) | |
6a06907d XL |
124 | | Annotatable::ExprField(..) |
125 | | Annotatable::PatField(..) | |
74b04a01 XL |
126 | | Annotatable::GenericParam(..) |
127 | | Annotatable::Param(..) | |
6a06907d | 128 | | Annotatable::FieldDef(..) |
a2a8927a XL |
129 | | Annotatable::Variant(..) |
130 | | Annotatable::Crate(..) => panic!("unexpected annotatable"), | |
5869c6ff XL |
131 | } |
132 | } | |
133 | ||
134 | crate fn into_tokens(self, sess: &ParseSess) -> TokenStream { | |
cdc7bbd5 | 135 | nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No) |
74b04a01 XL |
136 | } |
137 | ||
85aaf69f SL |
138 | pub fn expect_item(self) -> P<ast::Item> { |
139 | match self { | |
140 | Annotatable::Item(i) => i, | |
dfeec247 | 141 | _ => panic!("expected Item"), |
85aaf69f SL |
142 | } |
143 | } | |
144 | ||
74b04a01 | 145 | pub fn expect_trait_item(self) -> P<ast::AssocItem> { |
85aaf69f | 146 | match self { |
74b04a01 | 147 | Annotatable::TraitItem(i) => i, |
dfeec247 | 148 | _ => panic!("expected Item"), |
85aaf69f SL |
149 | } |
150 | } | |
151 | ||
74b04a01 | 152 | pub fn expect_impl_item(self) -> P<ast::AssocItem> { |
85aaf69f | 153 | match self { |
74b04a01 | 154 | Annotatable::ImplItem(i) => i, |
dfeec247 | 155 | _ => panic!("expected Item"), |
85aaf69f SL |
156 | } |
157 | } | |
ff7c6d11 | 158 | |
74b04a01 | 159 | pub fn expect_foreign_item(self) -> P<ast::ForeignItem> { |
83c7162d | 160 | match self { |
74b04a01 | 161 | Annotatable::ForeignItem(i) => i, |
dfeec247 | 162 | _ => panic!("expected foreign item"), |
83c7162d XL |
163 | } |
164 | } | |
165 | ||
0531ce1d XL |
166 | pub fn expect_stmt(self) -> ast::Stmt { |
167 | match self { | |
168 | Annotatable::Stmt(stmt) => stmt.into_inner(), | |
169 | _ => panic!("expected statement"), | |
170 | } | |
171 | } | |
172 | ||
173 | pub fn expect_expr(self) -> P<ast::Expr> { | |
174 | match self { | |
175 | Annotatable::Expr(expr) => expr, | |
176 | _ => panic!("expected expression"), | |
177 | } | |
178 | } | |
179 | ||
e1599b0c XL |
180 | pub fn expect_arm(self) -> ast::Arm { |
181 | match self { | |
182 | Annotatable::Arm(arm) => arm, | |
dfeec247 | 183 | _ => panic!("expected match arm"), |
e1599b0c XL |
184 | } |
185 | } | |
186 | ||
6a06907d | 187 | pub fn expect_expr_field(self) -> ast::ExprField { |
e1599b0c | 188 | match self { |
6a06907d | 189 | Annotatable::ExprField(field) => field, |
dfeec247 | 190 | _ => panic!("expected field"), |
e1599b0c XL |
191 | } |
192 | } | |
193 | ||
6a06907d | 194 | pub fn expect_pat_field(self) -> ast::PatField { |
e1599b0c | 195 | match self { |
6a06907d | 196 | Annotatable::PatField(fp) => fp, |
dfeec247 | 197 | _ => panic!("expected field pattern"), |
e1599b0c XL |
198 | } |
199 | } | |
200 | ||
201 | pub fn expect_generic_param(self) -> ast::GenericParam { | |
202 | match self { | |
203 | Annotatable::GenericParam(gp) => gp, | |
dfeec247 | 204 | _ => panic!("expected generic parameter"), |
e1599b0c XL |
205 | } |
206 | } | |
207 | ||
208 | pub fn expect_param(self) -> ast::Param { | |
209 | match self { | |
210 | Annotatable::Param(param) => param, | |
dfeec247 | 211 | _ => panic!("expected parameter"), |
e1599b0c XL |
212 | } |
213 | } | |
214 | ||
6a06907d | 215 | pub fn expect_field_def(self) -> ast::FieldDef { |
e1599b0c | 216 | match self { |
6a06907d | 217 | Annotatable::FieldDef(sf) => sf, |
dfeec247 | 218 | _ => panic!("expected struct field"), |
e1599b0c XL |
219 | } |
220 | } | |
221 | ||
222 | pub fn expect_variant(self) -> ast::Variant { | |
223 | match self { | |
224 | Annotatable::Variant(v) => v, | |
dfeec247 | 225 | _ => panic!("expected variant"), |
e1599b0c XL |
226 | } |
227 | } | |
a2a8927a XL |
228 | |
229 | pub fn expect_crate(self) -> ast::Crate { | |
230 | match self { | |
231 | Annotatable::Crate(krate) => krate, | |
232 | _ => panic!("expected krate"), | |
233 | } | |
234 | } | |
85aaf69f SL |
235 | } |
236 | ||
ba9703b0 XL |
237 | /// Result of an expansion that may need to be retried. |
238 | /// Consider using this for non-`MultiItemModifier` expanders as well. | |
239 | pub enum ExpandResult<T, U> { | |
240 | /// Expansion produced a result (possibly dummy). | |
241 | Ready(T), | |
242 | /// Expansion could not produce a result and needs to be retried. | |
fc512014 | 243 | Retry(U), |
ba9703b0 XL |
244 | } |
245 | ||
246 | // `meta_item` is the attribute, and `item` is the item being modified. | |
85aaf69f | 247 | pub trait MultiItemModifier { |
dfeec247 XL |
248 | fn expand( |
249 | &self, | |
250 | ecx: &mut ExtCtxt<'_>, | |
251 | span: Span, | |
252 | meta_item: &ast::MetaItem, | |
253 | item: Annotatable, | |
ba9703b0 | 254 | ) -> ExpandResult<Vec<Annotatable>, Annotatable>; |
85aaf69f SL |
255 | } |
256 | ||
ba9703b0 | 257 | impl<F> MultiItemModifier for F |
dfeec247 | 258 | where |
ba9703b0 | 259 | F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> Vec<Annotatable>, |
85aaf69f | 260 | { |
dfeec247 XL |
261 | fn expand( |
262 | &self, | |
263 | ecx: &mut ExtCtxt<'_>, | |
264 | span: Span, | |
265 | meta_item: &ast::MetaItem, | |
266 | item: Annotatable, | |
ba9703b0 XL |
267 | ) -> ExpandResult<Vec<Annotatable>, Annotatable> { |
268 | ExpandResult::Ready(self(ecx, span, meta_item, item)) | |
85aaf69f SL |
269 | } |
270 | } | |
271 | ||
9e0c209e | 272 | pub trait ProcMacro { |
ba9703b0 XL |
273 | fn expand<'cx>( |
274 | &self, | |
275 | ecx: &'cx mut ExtCtxt<'_>, | |
276 | span: Span, | |
277 | ts: TokenStream, | |
ee023bcb | 278 | ) -> Result<TokenStream, ErrorGuaranteed>; |
9e0c209e SL |
279 | } |
280 | ||
281 | impl<F> ProcMacro for F | |
dfeec247 XL |
282 | where |
283 | F: Fn(TokenStream) -> TokenStream, | |
9e0c209e | 284 | { |
ba9703b0 XL |
285 | fn expand<'cx>( |
286 | &self, | |
287 | _ecx: &'cx mut ExtCtxt<'_>, | |
288 | _span: Span, | |
289 | ts: TokenStream, | |
ee023bcb | 290 | ) -> Result<TokenStream, ErrorGuaranteed> { |
9e0c209e | 291 | // FIXME setup implicit context in TLS before calling self. |
1b1a35ee | 292 | Ok(self(ts)) |
9e0c209e SL |
293 | } |
294 | } | |
295 | ||
296 | pub trait AttrProcMacro { | |
dfeec247 XL |
297 | fn expand<'cx>( |
298 | &self, | |
299 | ecx: &'cx mut ExtCtxt<'_>, | |
300 | span: Span, | |
301 | annotation: TokenStream, | |
302 | annotated: TokenStream, | |
ee023bcb | 303 | ) -> Result<TokenStream, ErrorGuaranteed>; |
9e0c209e SL |
304 | } |
305 | ||
306 | impl<F> AttrProcMacro for F | |
dfeec247 XL |
307 | where |
308 | F: Fn(TokenStream, TokenStream) -> TokenStream, | |
9e0c209e | 309 | { |
dfeec247 XL |
310 | fn expand<'cx>( |
311 | &self, | |
312 | _ecx: &'cx mut ExtCtxt<'_>, | |
313 | _span: Span, | |
314 | annotation: TokenStream, | |
315 | annotated: TokenStream, | |
ee023bcb | 316 | ) -> Result<TokenStream, ErrorGuaranteed> { |
9e0c209e | 317 | // FIXME setup implicit context in TLS before calling self. |
1b1a35ee | 318 | Ok(self(annotation, annotated)) |
9e0c209e SL |
319 | } |
320 | } | |
321 | ||
1a4d82fc JJ |
322 | /// Represents a thing that maps token trees to Macro Results |
323 | pub trait TTMacroExpander { | |
a1dfa0c6 XL |
324 | fn expand<'cx>( |
325 | &self, | |
9fa01778 | 326 | ecx: &'cx mut ExtCtxt<'_>, |
a1dfa0c6 XL |
327 | span: Span, |
328 | input: TokenStream, | |
dfeec247 | 329 | ) -> Box<dyn MacResult + 'cx>; |
223e47cc LB |
330 | } |
331 | ||
1a4d82fc | 332 | pub type MacroExpanderFn = |
dfeec247 | 333 | for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>; |
223e47cc | 334 | |
1a4d82fc | 335 | impl<F> TTMacroExpander for F |
dfeec247 XL |
336 | where |
337 | F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>, | |
1a4d82fc | 338 | { |
a1dfa0c6 XL |
339 | fn expand<'cx>( |
340 | &self, | |
9fa01778 | 341 | ecx: &'cx mut ExtCtxt<'_>, |
a1dfa0c6 | 342 | span: Span, |
1b1a35ee | 343 | input: TokenStream, |
dfeec247 | 344 | ) -> Box<dyn MacResult + 'cx> { |
1b1a35ee | 345 | self(ecx, span, input) |
1a4d82fc | 346 | } |
223e47cc LB |
347 | } |
348 | ||
c34b1796 | 349 | // Use a macro because forwarding to a simple function has type system issues |
9346a6ac | 350 | macro_rules! make_stmts_default { |
c34b1796 | 351 | ($me:expr) => { |
dfeec247 XL |
352 | $me.make_expr().map(|e| { |
353 | smallvec![ast::Stmt { | |
354 | id: ast::DUMMY_NODE_ID, | |
355 | span: e.span, | |
356 | kind: ast::StmtKind::Expr(e), | |
357 | }] | |
358 | }) | |
359 | }; | |
c34b1796 AL |
360 | } |
361 | ||
1a4d82fc | 362 | /// The result of a macro expansion. The return values of the various |
c34b1796 | 363 | /// methods are spliced into the AST at the callsite of the macro. |
1a4d82fc | 364 | pub trait MacResult { |
9fa01778 | 365 | /// Creates an expression. |
1a4d82fc JJ |
366 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { |
367 | None | |
368 | } | |
94222f64 | 369 | |
9fa01778 | 370 | /// Creates zero or more items. |
0bf4aa26 | 371 | fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
1a4d82fc JJ |
372 | None |
373 | } | |
223e47cc | 374 | |
9fa01778 | 375 | /// Creates zero or more impl items. |
74b04a01 | 376 | fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
1a4d82fc JJ |
377 | None |
378 | } | |
223e47cc | 379 | |
9fa01778 | 380 | /// Creates zero or more trait items. |
74b04a01 | 381 | fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
3157f602 XL |
382 | None |
383 | } | |
384 | ||
9fa01778 | 385 | /// Creates zero or more items in an `extern {}` block |
74b04a01 | 386 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { |
dfeec247 XL |
387 | None |
388 | } | |
83c7162d | 389 | |
9fa01778 | 390 | /// Creates a pattern. |
1a4d82fc JJ |
391 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { |
392 | None | |
393 | } | |
223e47cc | 394 | |
9fa01778 | 395 | /// Creates zero or more statements. |
1a4d82fc JJ |
396 | /// |
397 | /// By default this attempts to create an expression statement, | |
398 | /// returning None if that fails. | |
0bf4aa26 | 399 | fn make_stmts(self: Box<Self>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
9346a6ac | 400 | make_stmts_default!(self) |
1a4d82fc | 401 | } |
e9174d1e SL |
402 | |
403 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
404 | None | |
405 | } | |
e1599b0c XL |
406 | |
407 | fn make_arms(self: Box<Self>) -> Option<SmallVec<[ast::Arm; 1]>> { | |
408 | None | |
409 | } | |
410 | ||
6a06907d | 411 | fn make_expr_fields(self: Box<Self>) -> Option<SmallVec<[ast::ExprField; 1]>> { |
e1599b0c XL |
412 | None |
413 | } | |
414 | ||
6a06907d | 415 | fn make_pat_fields(self: Box<Self>) -> Option<SmallVec<[ast::PatField; 1]>> { |
e1599b0c XL |
416 | None |
417 | } | |
418 | ||
419 | fn make_generic_params(self: Box<Self>) -> Option<SmallVec<[ast::GenericParam; 1]>> { | |
420 | None | |
421 | } | |
422 | ||
423 | fn make_params(self: Box<Self>) -> Option<SmallVec<[ast::Param; 1]>> { | |
424 | None | |
425 | } | |
426 | ||
6a06907d | 427 | fn make_field_defs(self: Box<Self>) -> Option<SmallVec<[ast::FieldDef; 1]>> { |
e1599b0c XL |
428 | None |
429 | } | |
430 | ||
431 | fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> { | |
432 | None | |
433 | } | |
a2a8927a XL |
434 | |
435 | fn make_crate(self: Box<Self>) -> Option<ast::Crate> { | |
436 | // Fn-like macros cannot produce a crate. | |
437 | unreachable!() | |
438 | } | |
1a4d82fc | 439 | } |
223e47cc | 440 | |
c34b1796 AL |
441 | macro_rules! make_MacEager { |
442 | ( $( $fld:ident: $t:ty, )* ) => { | |
443 | /// `MacResult` implementation for the common case where you've already | |
444 | /// built each form of AST that you might return. | |
445 | #[derive(Default)] | |
446 | pub struct MacEager { | |
447 | $( | |
448 | pub $fld: Option<$t>, | |
449 | )* | |
450 | } | |
451 | ||
452 | impl MacEager { | |
453 | $( | |
8faf50e0 | 454 | pub fn $fld(v: $t) -> Box<dyn MacResult> { |
d9579d0f | 455 | Box::new(MacEager { |
c34b1796 AL |
456 | $fld: Some(v), |
457 | ..Default::default() | |
d9579d0f | 458 | }) |
c34b1796 AL |
459 | } |
460 | )* | |
1a4d82fc JJ |
461 | } |
462 | } | |
463 | } | |
c34b1796 AL |
464 | |
465 | make_MacEager! { | |
466 | expr: P<ast::Expr>, | |
467 | pat: P<ast::Pat>, | |
0bf4aa26 | 468 | items: SmallVec<[P<ast::Item>; 1]>, |
74b04a01 XL |
469 | impl_items: SmallVec<[P<ast::AssocItem>; 1]>, |
470 | trait_items: SmallVec<[P<ast::AssocItem>; 1]>, | |
471 | foreign_items: SmallVec<[P<ast::ForeignItem>; 1]>, | |
0bf4aa26 | 472 | stmts: SmallVec<[ast::Stmt; 1]>, |
e9174d1e | 473 | ty: P<ast::Ty>, |
1a4d82fc | 474 | } |
c34b1796 AL |
475 | |
476 | impl MacResult for MacEager { | |
477 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { | |
478 | self.expr | |
1a4d82fc | 479 | } |
c34b1796 | 480 | |
0bf4aa26 | 481 | fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
c34b1796 | 482 | self.items |
1a4d82fc | 483 | } |
223e47cc | 484 | |
74b04a01 | 485 | fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
c34b1796 | 486 | self.impl_items |
1a4d82fc | 487 | } |
223e47cc | 488 | |
74b04a01 | 489 | fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
3157f602 XL |
490 | self.trait_items |
491 | } | |
492 | ||
74b04a01 | 493 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { |
83c7162d XL |
494 | self.foreign_items |
495 | } | |
496 | ||
0bf4aa26 | 497 | fn make_stmts(self: Box<Self>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
9346a6ac AL |
498 | match self.stmts.as_ref().map_or(0, |s| s.len()) { |
499 | 0 => make_stmts_default!(self), | |
500 | _ => self.stmts, | |
c34b1796 AL |
501 | } |
502 | } | |
503 | ||
504 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { | |
505 | if let Some(p) = self.pat { | |
506 | return Some(p); | |
507 | } | |
508 | if let Some(e) = self.expr { | |
e74abb32 | 509 | if let ast::ExprKind::Lit(_) = e.kind { |
c34b1796 AL |
510 | return Some(P(ast::Pat { |
511 | id: ast::DUMMY_NODE_ID, | |
512 | span: e.span, | |
e74abb32 | 513 | kind: PatKind::Lit(e), |
3dfed10e | 514 | tokens: None, |
c34b1796 AL |
515 | })); |
516 | } | |
517 | } | |
518 | None | |
1a4d82fc | 519 | } |
e9174d1e SL |
520 | |
521 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
522 | self.ty | |
523 | } | |
1a4d82fc | 524 | } |
223e47cc | 525 | |
1a4d82fc JJ |
526 | /// Fill-in macro expansion result, to allow compilation to continue |
527 | /// after hitting errors. | |
c34b1796 | 528 | #[derive(Copy, Clone)] |
1a4d82fc | 529 | pub struct DummyResult { |
0731742a XL |
530 | is_error: bool, |
531 | span: Span, | |
223e47cc LB |
532 | } |
533 | ||
1a4d82fc | 534 | impl DummyResult { |
9fa01778 | 535 | /// Creates a default MacResult that can be anything. |
1a4d82fc JJ |
536 | /// |
537 | /// Use this as a return value after hitting any errors and | |
538 | /// calling `span_err`. | |
dfeec247 | 539 | pub fn any(span: Span) -> Box<dyn MacResult + 'static> { |
e1599b0c | 540 | Box::new(DummyResult { is_error: true, span }) |
0731742a XL |
541 | } |
542 | ||
543 | /// Same as `any`, but must be a valid fragment, not error. | |
dfeec247 | 544 | pub fn any_valid(span: Span) -> Box<dyn MacResult + 'static> { |
e1599b0c | 545 | Box::new(DummyResult { is_error: false, span }) |
1a4d82fc JJ |
546 | } |
547 | ||
548 | /// A plain dummy expression. | |
0731742a | 549 | pub fn raw_expr(sp: Span, is_error: bool) -> P<ast::Expr> { |
1a4d82fc JJ |
550 | P(ast::Expr { |
551 | id: ast::DUMMY_NODE_ID, | |
e74abb32 | 552 | kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, |
1a4d82fc | 553 | span: sp, |
dfeec247 | 554 | attrs: ast::AttrVec::new(), |
f9f354fc | 555 | tokens: None, |
1a4d82fc JJ |
556 | }) |
557 | } | |
558 | ||
559 | /// A plain dummy pattern. | |
560 | pub fn raw_pat(sp: Span) -> ast::Pat { | |
3dfed10e | 561 | ast::Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Wild, span: sp, tokens: None } |
1a4d82fc JJ |
562 | } |
563 | ||
0731742a XL |
564 | /// A plain dummy type. |
565 | pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> { | |
e9174d1e SL |
566 | P(ast::Ty { |
567 | id: ast::DUMMY_NODE_ID, | |
e74abb32 | 568 | kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, |
dfeec247 | 569 | span: sp, |
1b1a35ee | 570 | tokens: None, |
e9174d1e SL |
571 | }) |
572 | } | |
1a4d82fc JJ |
573 | } |
574 | ||
575 | impl MacResult for DummyResult { | |
576 | fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> { | |
0731742a | 577 | Some(DummyResult::raw_expr(self.span, self.is_error)) |
1a4d82fc | 578 | } |
e9174d1e | 579 | |
1a4d82fc JJ |
580 | fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> { |
581 | Some(P(DummyResult::raw_pat(self.span))) | |
582 | } | |
e9174d1e | 583 | |
0bf4aa26 | 584 | fn make_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::Item>; 1]>> { |
e1599b0c | 585 | Some(SmallVec::new()) |
1a4d82fc | 586 | } |
e9174d1e | 587 | |
74b04a01 | 588 | fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
e1599b0c | 589 | Some(SmallVec::new()) |
1a4d82fc | 590 | } |
e9174d1e | 591 | |
74b04a01 | 592 | fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[P<ast::AssocItem>; 1]>> { |
e1599b0c | 593 | Some(SmallVec::new()) |
3157f602 XL |
594 | } |
595 | ||
74b04a01 | 596 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVec<[P<ast::ForeignItem>; 1]>> { |
e1599b0c | 597 | Some(SmallVec::new()) |
83c7162d XL |
598 | } |
599 | ||
0bf4aa26 | 600 | fn make_stmts(self: Box<DummyResult>) -> Option<SmallVec<[ast::Stmt; 1]>> { |
b7449926 | 601 | Some(smallvec![ast::Stmt { |
3157f602 | 602 | id: ast::DUMMY_NODE_ID, |
e74abb32 | 603 | kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), |
3157f602 | 604 | span: self.span, |
b7449926 | 605 | }]) |
3157f602 XL |
606 | } |
607 | ||
608 | fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { | |
0731742a | 609 | Some(DummyResult::raw_ty(self.span, self.is_error)) |
1a4d82fc | 610 | } |
e1599b0c XL |
611 | |
612 | fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> { | |
dfeec247 | 613 | Some(SmallVec::new()) |
e1599b0c XL |
614 | } |
615 | ||
6a06907d | 616 | fn make_expr_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::ExprField; 1]>> { |
e1599b0c XL |
617 | Some(SmallVec::new()) |
618 | } | |
619 | ||
6a06907d | 620 | fn make_pat_fields(self: Box<DummyResult>) -> Option<SmallVec<[ast::PatField; 1]>> { |
e1599b0c XL |
621 | Some(SmallVec::new()) |
622 | } | |
623 | ||
624 | fn make_generic_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::GenericParam; 1]>> { | |
625 | Some(SmallVec::new()) | |
626 | } | |
627 | ||
628 | fn make_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::Param; 1]>> { | |
629 | Some(SmallVec::new()) | |
630 | } | |
631 | ||
6a06907d | 632 | fn make_field_defs(self: Box<DummyResult>) -> Option<SmallVec<[ast::FieldDef; 1]>> { |
e1599b0c XL |
633 | Some(SmallVec::new()) |
634 | } | |
635 | ||
636 | fn make_variants(self: Box<DummyResult>) -> Option<SmallVec<[ast::Variant; 1]>> { | |
637 | Some(SmallVec::new()) | |
638 | } | |
1a4d82fc JJ |
639 | } |
640 | ||
dc9dc135 XL |
641 | /// A syntax extension kind. |
642 | pub enum SyntaxExtensionKind { | |
643 | /// A token-based function-like macro. | |
644 | Bang( | |
645 | /// An expander with signature TokenStream -> TokenStream. | |
646 | Box<dyn ProcMacro + sync::Sync + sync::Send>, | |
647 | ), | |
648 | ||
649 | /// An AST-based function-like macro. | |
650 | LegacyBang( | |
651 | /// An expander with signature TokenStream -> AST. | |
652 | Box<dyn TTMacroExpander + sync::Sync + sync::Send>, | |
653 | ), | |
654 | ||
655 | /// A token-based attribute macro. | |
656 | Attr( | |
657 | /// An expander with signature (TokenStream, TokenStream) -> TokenStream. | |
658 | /// The first TokenSteam is the attribute itself, the second is the annotated item. | |
659 | /// The produced TokenSteam replaces the input TokenSteam. | |
660 | Box<dyn AttrProcMacro + sync::Sync + sync::Send>, | |
661 | ), | |
662 | ||
663 | /// An AST-based attribute macro. | |
664 | LegacyAttr( | |
665 | /// An expander with signature (AST, AST) -> AST. | |
666 | /// The first AST fragment is the attribute itself, the second is the annotated item. | |
667 | /// The produced AST fragment replaces the input AST fragment. | |
668 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
669 | ), | |
670 | ||
671 | /// A trivial attribute "macro" that does nothing, | |
672 | /// only keeps the attribute and marks it as inert, | |
673 | /// thus making it ineligible for further expansion. | |
94222f64 | 674 | NonMacroAttr, |
9e0c209e | 675 | |
dc9dc135 XL |
676 | /// A token-based derive macro. |
677 | Derive( | |
678 | /// An expander with signature TokenStream -> TokenStream (not yet). | |
679 | /// The produced TokenSteam is appended to the input TokenSteam. | |
680 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
681 | ), | |
682 | ||
683 | /// An AST-based derive macro. | |
684 | LegacyDerive( | |
685 | /// An expander with signature AST -> AST. | |
686 | /// The produced AST fragment is appended to the input AST fragment. | |
687 | Box<dyn MultiItemModifier + sync::Sync + sync::Send>, | |
688 | ), | |
689 | } | |
690 | ||
691 | /// A struct representing a macro definition in "lowered" form ready for expansion. | |
692 | pub struct SyntaxExtension { | |
693 | /// A syntax extension kind. | |
694 | pub kind: SyntaxExtensionKind, | |
416331ca XL |
695 | /// Span of the macro definition. |
696 | pub span: Span, | |
f035d41b | 697 | /// List of unstable features that are treated as stable inside this macro. |
dc9dc135 XL |
698 | pub allow_internal_unstable: Option<Lrc<[Symbol]>>, |
699 | /// Suppresses the `unsafe_code` lint for code produced by this macro. | |
700 | pub allow_internal_unsafe: bool, | |
701 | /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. | |
702 | pub local_inner_macros: bool, | |
416331ca XL |
703 | /// The macro's stability info. |
704 | pub stability: Option<Stability>, | |
705 | /// The macro's deprecation info. | |
706 | pub deprecation: Option<Deprecation>, | |
dc9dc135 XL |
707 | /// Names of helper attributes registered by this macro. |
708 | pub helper_attrs: Vec<Symbol>, | |
709 | /// Edition of the crate in which this macro is defined. | |
710 | pub edition: Edition, | |
416331ca XL |
711 | /// Built-in macros have a couple of special properties like availability |
712 | /// in `#[no_implicit_prelude]` modules, so we have to keep this flag. | |
5869c6ff | 713 | pub builtin_name: Option<Symbol>, |
dc9dc135 XL |
714 | } |
715 | ||
8bb4bdeb | 716 | impl SyntaxExtension { |
9fa01778 | 717 | /// Returns which kind of macro calls this syntax extension. |
dc9dc135 XL |
718 | pub fn macro_kind(&self) -> MacroKind { |
719 | match self.kind { | |
dfeec247 XL |
720 | SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang, |
721 | SyntaxExtensionKind::Attr(..) | |
722 | | SyntaxExtensionKind::LegacyAttr(..) | |
94222f64 | 723 | | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr, |
dfeec247 XL |
724 | SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { |
725 | MacroKind::Derive | |
726 | } | |
7cac9316 XL |
727 | } |
728 | } | |
94b46f34 | 729 | |
dc9dc135 XL |
730 | /// Constructs a syntax extension with default properties. |
731 | pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { | |
732 | SyntaxExtension { | |
416331ca | 733 | span: DUMMY_SP, |
dc9dc135 XL |
734 | allow_internal_unstable: None, |
735 | allow_internal_unsafe: false, | |
736 | local_inner_macros: false, | |
416331ca XL |
737 | stability: None, |
738 | deprecation: None, | |
dc9dc135 XL |
739 | helper_attrs: Vec::new(), |
740 | edition, | |
5869c6ff | 741 | builtin_name: None, |
dc9dc135 XL |
742 | kind, |
743 | } | |
744 | } | |
745 | ||
e1599b0c XL |
746 | /// Constructs a syntax extension with the given properties |
747 | /// and other properties converted from attributes. | |
748 | pub fn new( | |
3dfed10e | 749 | sess: &Session, |
e1599b0c XL |
750 | kind: SyntaxExtensionKind, |
751 | span: Span, | |
752 | helper_attrs: Vec<Symbol>, | |
753 | edition: Edition, | |
f9f354fc | 754 | name: Symbol, |
e1599b0c XL |
755 | attrs: &[ast::Attribute], |
756 | ) -> SyntaxExtension { | |
6a06907d XL |
757 | let allow_internal_unstable = |
758 | attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>(); | |
e1599b0c XL |
759 | |
760 | let mut local_inner_macros = false; | |
3dfed10e | 761 | if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) { |
e1599b0c XL |
762 | if let Some(l) = macro_export.meta_item_list() { |
763 | local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); | |
764 | } | |
765 | } | |
766 | ||
136023e0 | 767 | let (builtin_name, helper_attrs) = sess |
5869c6ff | 768 | .find_by_name(attrs, sym::rustc_builtin_macro) |
136023e0 XL |
769 | .map(|attr| { |
770 | // Override `helper_attrs` passed above if it's a built-in macro, | |
771 | // marking `proc_macro_derive` macros as built-in is not a realistic use case. | |
772 | parse_macro_name_and_helper_attrs(sess.diagnostic(), attr, "built-in").map_or_else( | |
773 | || (Some(name), Vec::new()), | |
774 | |(name, helper_attrs)| (Some(name), helper_attrs), | |
775 | ) | |
776 | }) | |
777 | .unwrap_or_else(|| (None, helper_attrs)); | |
60c5eb7d | 778 | let (stability, const_stability) = attr::find_stability(&sess, attrs, span); |
6a06907d | 779 | if let Some((_, sp)) = const_stability { |
3dfed10e XL |
780 | sess.parse_sess |
781 | .span_diagnostic | |
6a06907d XL |
782 | .struct_span_err(sp, "macros cannot have const stability attributes") |
783 | .span_label(sp, "invalid const stability attribute") | |
784 | .span_label( | |
785 | sess.source_map().guess_head_span(span), | |
786 | "const stability attribute affects this macro", | |
787 | ) | |
788 | .emit(); | |
60c5eb7d | 789 | } |
e1599b0c XL |
790 | |
791 | SyntaxExtension { | |
792 | kind, | |
793 | span, | |
6a06907d XL |
794 | allow_internal_unstable: (!allow_internal_unstable.is_empty()) |
795 | .then(|| allow_internal_unstable.into()), | |
3dfed10e | 796 | allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe), |
e1599b0c | 797 | local_inner_macros, |
6a06907d | 798 | stability: stability.map(|(s, _)| s), |
29967ef6 | 799 | deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d), |
e1599b0c XL |
800 | helper_attrs, |
801 | edition, | |
5869c6ff | 802 | builtin_name, |
e1599b0c XL |
803 | } |
804 | } | |
805 | ||
416331ca | 806 | pub fn dummy_bang(edition: Edition) -> SyntaxExtension { |
dfeec247 XL |
807 | fn expander<'cx>( |
808 | _: &'cx mut ExtCtxt<'_>, | |
809 | span: Span, | |
810 | _: TokenStream, | |
811 | ) -> Box<dyn MacResult + 'cx> { | |
416331ca | 812 | DummyResult::any(span) |
dc9dc135 | 813 | } |
416331ca | 814 | SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) |
dc9dc135 XL |
815 | } |
816 | ||
416331ca | 817 | pub fn dummy_derive(edition: Edition) -> SyntaxExtension { |
dfeec247 XL |
818 | fn expander( |
819 | _: &mut ExtCtxt<'_>, | |
820 | _: Span, | |
821 | _: &ast::MetaItem, | |
822 | _: Annotatable, | |
823 | ) -> Vec<Annotatable> { | |
416331ca XL |
824 | Vec::new() |
825 | } | |
826 | SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition) | |
827 | } | |
828 | ||
94222f64 XL |
829 | pub fn non_macro_attr(edition: Edition) -> SyntaxExtension { |
830 | SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition) | |
416331ca XL |
831 | } |
832 | ||
f9f354fc XL |
833 | pub fn expn_data( |
834 | &self, | |
136023e0 | 835 | parent: LocalExpnId, |
f9f354fc XL |
836 | call_site: Span, |
837 | descr: Symbol, | |
838 | macro_def_id: Option<DefId>, | |
136023e0 | 839 | parent_module: Option<DefId>, |
f9f354fc | 840 | ) -> ExpnData { |
5869c6ff | 841 | ExpnData::new( |
136023e0 XL |
842 | ExpnKind::Macro(self.macro_kind(), descr), |
843 | parent.to_expn_id(), | |
e1599b0c | 844 | call_site, |
5869c6ff XL |
845 | self.span, |
846 | self.allow_internal_unstable.clone(), | |
847 | self.allow_internal_unsafe, | |
848 | self.local_inner_macros, | |
849 | self.edition, | |
f9f354fc | 850 | macro_def_id, |
136023e0 | 851 | parent_module, |
5869c6ff | 852 | ) |
94b46f34 | 853 | } |
1a4d82fc JJ |
854 | } |
855 | ||
416331ca XL |
856 | /// Error type that denotes indeterminacy. |
857 | pub struct Indeterminate; | |
858 | ||
136023e0 | 859 | pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>)>; |
cdc7bbd5 | 860 | |
f035d41b | 861 | pub trait ResolverExpand { |
e1599b0c | 862 | fn next_node_id(&mut self) -> NodeId; |
c295e0f8 | 863 | fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId; |
9e0c209e | 864 | |
416331ca | 865 | fn resolve_dollar_crates(&mut self); |
136023e0 XL |
866 | fn visit_ast_fragment_with_placeholders( |
867 | &mut self, | |
868 | expn_id: LocalExpnId, | |
869 | fragment: &AstFragment, | |
870 | ); | |
5869c6ff | 871 | fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind); |
9e0c209e | 872 | |
e1599b0c XL |
873 | fn expansion_for_ast_pass( |
874 | &mut self, | |
875 | call_site: Span, | |
876 | pass: AstPass, | |
877 | features: &[Symbol], | |
878 | parent_module_id: Option<NodeId>, | |
136023e0 | 879 | ) -> LocalExpnId; |
e1599b0c | 880 | |
476ff2be | 881 | fn resolve_imports(&mut self); |
0531ce1d | 882 | |
e1599b0c | 883 | fn resolve_macro_invocation( |
dfeec247 XL |
884 | &mut self, |
885 | invoc: &Invocation, | |
136023e0 | 886 | eager_expansion_root: LocalExpnId, |
dfeec247 | 887 | force: bool, |
6a06907d | 888 | ) -> Result<Lrc<SyntaxExtension>, Indeterminate>; |
b7449926 | 889 | |
e74abb32 | 890 | fn check_unused_macros(&mut self); |
970d7e83 | 891 | |
fc512014 XL |
892 | // Resolver interfaces for specific built-in macros. |
893 | /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it? | |
136023e0 | 894 | fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool; |
6a06907d XL |
895 | /// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`. |
896 | fn resolve_derives( | |
897 | &mut self, | |
136023e0 | 898 | expn_id: LocalExpnId, |
6a06907d | 899 | force: bool, |
cdc7bbd5 | 900 | derive_paths: &dyn Fn() -> DeriveResolutions, |
6a06907d XL |
901 | ) -> Result<(), Indeterminate>; |
902 | /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId` | |
903 | /// back from resolver. | |
136023e0 | 904 | fn take_derive_resolutions(&mut self, expn_id: LocalExpnId) -> Option<DeriveResolutions>; |
fc512014 | 905 | /// Path resolution logic for `#[cfg_accessible(path)]`. |
136023e0 XL |
906 | fn cfg_accessible( |
907 | &mut self, | |
908 | expn_id: LocalExpnId, | |
909 | path: &ast::Path, | |
910 | ) -> Result<bool, Indeterminate>; | |
17df50a5 XL |
911 | |
912 | /// Decodes the proc-macro quoted span in the specified crate, with the specified id. | |
913 | /// No caching is performed. | |
914 | fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span; | |
94222f64 XL |
915 | |
916 | /// The order of items in the HIR is unrelated to the order of | |
917 | /// items in the AST. However, we generate proc macro harnesses | |
918 | /// based on the AST order, and later refer to these harnesses | |
919 | /// from the HIR. This field keeps track of the order in which | |
920 | /// we generated proc macros harnesses, so that we can map | |
921 | /// HIR proc macros items back to their harness items. | |
922 | fn declare_proc_macro(&mut self, id: NodeId); | |
5099ac24 FG |
923 | |
924 | /// Tools registered with `#![register_tool]` and used by tool attributes and lints. | |
925 | fn registered_tools(&self) -> &FxHashSet<Ident>; | |
b7449926 XL |
926 | } |
927 | ||
5099ac24 FG |
928 | pub trait LintStoreExpand { |
929 | fn pre_expansion_lint( | |
930 | &self, | |
931 | sess: &Session, | |
932 | registered_tools: &FxHashSet<Ident>, | |
933 | node_id: NodeId, | |
934 | attrs: &[Attribute], | |
935 | items: &[P<Item>], | |
936 | name: &str, | |
937 | ); | |
938 | } | |
939 | ||
940 | type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>; | |
941 | ||
6a06907d | 942 | #[derive(Clone, Default)] |
9e0c209e | 943 | pub struct ModuleData { |
6a06907d | 944 | /// Path to the module starting from the crate name, like `my_crate::foo::bar`. |
f9f354fc | 945 | pub mod_path: Vec<Ident>, |
6a06907d XL |
946 | /// Stack of paths to files loaded by out-of-line module items, |
947 | /// used to detect and report recursive module inclusions. | |
948 | pub file_path_stack: Vec<PathBuf>, | |
949 | /// Directory to search child module files in, | |
950 | /// often (but not necessarily) the parent of the top file path on the `file_path_stack`. | |
951 | pub dir_path: PathBuf, | |
952 | } | |
953 | ||
954 | impl ModuleData { | |
955 | pub fn with_dir_path(&self, dir_path: PathBuf) -> ModuleData { | |
956 | ModuleData { | |
957 | mod_path: self.mod_path.clone(), | |
958 | file_path_stack: self.file_path_stack.clone(), | |
959 | dir_path, | |
960 | } | |
961 | } | |
9e0c209e SL |
962 | } |
963 | ||
964 | #[derive(Clone)] | |
965 | pub struct ExpansionData { | |
136023e0 | 966 | pub id: LocalExpnId, |
9e0c209e | 967 | pub depth: usize, |
9e0c209e | 968 | pub module: Rc<ModuleData>, |
6a06907d | 969 | pub dir_ownership: DirOwnership, |
416331ca | 970 | pub prior_type_ascription: Option<(Span, bool)>, |
136023e0 XL |
971 | /// Some parent node that is close to this macro call |
972 | pub lint_node_id: NodeId, | |
94222f64 | 973 | pub is_trailing_mac: bool, |
3157f602 XL |
974 | } |
975 | ||
1a4d82fc | 976 | /// One of these is made during expansion and incrementally updated as we go; |
7cac9316 | 977 | /// when a macro expansion occurs, the resulting nodes have the `backtrace() |
e1599b0c | 978 | /// -> expn_data` of their expansion context stored into their span. |
1a4d82fc | 979 | pub struct ExtCtxt<'a> { |
3dfed10e | 980 | pub sess: &'a Session, |
85aaf69f | 981 | pub ecfg: expand::ExpansionConfig<'a>, |
f9f354fc | 982 | pub reduced_recursion_limit: Option<Limit>, |
ff7c6d11 | 983 | pub root_path: PathBuf, |
f035d41b | 984 | pub resolver: &'a mut dyn ResolverExpand, |
9e0c209e | 985 | pub current_expansion: ExpansionData, |
fc512014 XL |
986 | /// Error recovery mode entered when expansion is stuck |
987 | /// (or during eager expansion, but that's a hack). | |
988 | pub force_mode: bool, | |
b7449926 | 989 | pub expansions: FxHashMap<Span, Vec<String>>, |
5099ac24 FG |
990 | /// Used for running pre-expansion lints on freshly loaded modules. |
991 | pub(super) lint_store: LintStoreExpandDyn<'a>, | |
94222f64 XL |
992 | /// When we 'expand' an inert attribute, we leave it |
993 | /// in the AST, but insert it here so that we know | |
994 | /// not to expand it again. | |
995 | pub(super) expanded_inert_attrs: MarkedAttrs, | |
1a4d82fc JJ |
996 | } |
997 | ||
998 | impl<'a> ExtCtxt<'a> { | |
dfeec247 | 999 | pub fn new( |
3dfed10e | 1000 | sess: &'a Session, |
dfeec247 | 1001 | ecfg: expand::ExpansionConfig<'a>, |
f035d41b | 1002 | resolver: &'a mut dyn ResolverExpand, |
5099ac24 | 1003 | lint_store: LintStoreExpandDyn<'a>, |
dfeec247 | 1004 | ) -> ExtCtxt<'a> { |
1a4d82fc | 1005 | ExtCtxt { |
3dfed10e | 1006 | sess, |
3b2f2976 | 1007 | ecfg, |
ba9703b0 | 1008 | reduced_recursion_limit: None, |
3b2f2976 | 1009 | resolver, |
5099ac24 | 1010 | lint_store, |
ba9703b0 | 1011 | root_path: PathBuf::new(), |
9e0c209e | 1012 | current_expansion: ExpansionData { |
136023e0 | 1013 | id: LocalExpnId::ROOT, |
9e0c209e | 1014 | depth: 0, |
6a06907d XL |
1015 | module: Default::default(), |
1016 | dir_ownership: DirOwnership::Owned { relative: None }, | |
416331ca | 1017 | prior_type_ascription: None, |
136023e0 | 1018 | lint_node_id: ast::CRATE_NODE_ID, |
94222f64 | 1019 | is_trailing_mac: false, |
9e0c209e | 1020 | }, |
fc512014 | 1021 | force_mode: false, |
b7449926 | 1022 | expansions: FxHashMap::default(), |
94222f64 | 1023 | expanded_inert_attrs: MarkedAttrs::new(), |
970d7e83 LB |
1024 | } |
1025 | } | |
1026 | ||
b039eaaf | 1027 | /// Returns a `Folder` for deeply expanding all macros in an AST node. |
1a4d82fc | 1028 | pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { |
9e0c209e SL |
1029 | expand::MacroExpander::new(self, false) |
1030 | } | |
1031 | ||
9fa01778 XL |
1032 | /// Returns a `Folder` that deeply expands all macros and assigns all `NodeId`s in an AST node. |
1033 | /// Once `NodeId`s are assigned, the node may not be expanded, removed, or otherwise modified. | |
9e0c209e SL |
1034 | pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { |
1035 | expand::MacroExpander::new(self, true) | |
1a4d82fc | 1036 | } |
e1599b0c | 1037 | pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { |
3dfed10e | 1038 | rustc_parse::stream_to_parser(&self.sess.parse_sess, stream, MACRO_ARGUMENTS) |
1a4d82fc | 1039 | } |
dfeec247 | 1040 | pub fn source_map(&self) -> &'a SourceMap { |
3dfed10e | 1041 | self.sess.parse_sess.source_map() |
dfeec247 XL |
1042 | } |
1043 | pub fn parse_sess(&self) -> &'a ParseSess { | |
3dfed10e | 1044 | &self.sess.parse_sess |
dfeec247 | 1045 | } |
1a4d82fc | 1046 | pub fn call_site(&self) -> Span { |
e1599b0c XL |
1047 | self.current_expansion.id.expn_data().call_site |
1048 | } | |
1049 | ||
1050 | /// Equivalent of `Span::def_site` from the proc macro API, | |
1051 | /// except that the location is taken from the span passed as an argument. | |
1052 | pub fn with_def_site_ctxt(&self, span: Span) -> Span { | |
136023e0 | 1053 | span.with_def_site_ctxt(self.current_expansion.id.to_expn_id()) |
cc61c64b | 1054 | } |
e1599b0c XL |
1055 | |
1056 | /// Equivalent of `Span::call_site` from the proc macro API, | |
1057 | /// except that the location is taken from the span passed as an argument. | |
1058 | pub fn with_call_site_ctxt(&self, span: Span) -> Span { | |
136023e0 | 1059 | span.with_call_site_ctxt(self.current_expansion.id.to_expn_id()) |
970d7e83 | 1060 | } |
d9579d0f | 1061 | |
e74abb32 XL |
1062 | /// Equivalent of `Span::mixed_site` from the proc macro API, |
1063 | /// except that the location is taken from the span passed as an argument. | |
1064 | pub fn with_mixed_site_ctxt(&self, span: Span) -> Span { | |
136023e0 | 1065 | span.with_mixed_site_ctxt(self.current_expansion.id.to_expn_id()) |
e74abb32 XL |
1066 | } |
1067 | ||
d9579d0f AL |
1068 | /// Returns span for the macro which originally caused the current expansion to happen. |
1069 | /// | |
1070 | /// Stops backtracing at include! boundary. | |
cc61c64b | 1071 | pub fn expansion_cause(&self) -> Option<Span> { |
60c5eb7d | 1072 | self.current_expansion.id.expansion_cause() |
1a4d82fc | 1073 | } |
1a4d82fc | 1074 | |
ee023bcb FG |
1075 | pub fn struct_span_err<S: Into<MultiSpan>>( |
1076 | &self, | |
1077 | sp: S, | |
1078 | msg: &str, | |
1079 | ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { | |
3dfed10e | 1080 | self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) |
9cc50fc6 | 1081 | } |
1a4d82fc JJ |
1082 | |
1083 | /// Emit `msg` attached to `sp`, without immediately stopping | |
1084 | /// compilation. | |
1085 | /// | |
1086 | /// Compilation will be stopped in the near future (at the end of | |
1087 | /// the macro expansion phase). | |
2c00a5a8 | 1088 | pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
3dfed10e | 1089 | self.sess.parse_sess.span_diagnostic.span_err(sp, msg); |
970d7e83 | 1090 | } |
2c00a5a8 | 1091 | pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
3dfed10e | 1092 | self.sess.parse_sess.span_diagnostic.span_warn(sp, msg); |
970d7e83 | 1093 | } |
2c00a5a8 | 1094 | pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
3dfed10e | 1095 | self.sess.parse_sess.span_diagnostic.span_bug(sp, msg); |
970d7e83 | 1096 | } |
ea8adc8c | 1097 | pub fn trace_macros_diag(&mut self) { |
7cac9316 | 1098 | for (sp, notes) in self.expansions.iter() { |
3dfed10e | 1099 | let mut db = self.sess.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro"); |
7cac9316 XL |
1100 | for note in notes { |
1101 | db.note(note); | |
1102 | } | |
1103 | db.emit(); | |
1104 | } | |
ea8adc8c XL |
1105 | // Fixme: does this result in errors? |
1106 | self.expansions.clear(); | |
7cac9316 | 1107 | } |
970d7e83 | 1108 | pub fn bug(&self, msg: &str) -> ! { |
3dfed10e | 1109 | self.sess.parse_sess.span_diagnostic.bug(msg); |
970d7e83 | 1110 | } |
970d7e83 | 1111 | pub fn trace_macros(&self) -> bool { |
d9579d0f | 1112 | self.ecfg.trace_mac |
970d7e83 | 1113 | } |
1a4d82fc | 1114 | pub fn set_trace_macros(&mut self, x: bool) { |
d9579d0f | 1115 | self.ecfg.trace_mac = x |
970d7e83 | 1116 | } |
f9f354fc | 1117 | pub fn std_path(&self, components: &[Symbol]) -> Vec<Ident> { |
e1599b0c | 1118 | let def_site = self.with_def_site_ctxt(DUMMY_SP); |
dc9dc135 | 1119 | iter::once(Ident::new(kw::DollarCrate, def_site)) |
e1599b0c | 1120 | .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) |
ff7c6d11 | 1121 | .collect() |
85aaf69f | 1122 | } |
6a06907d XL |
1123 | pub fn def_site_path(&self, components: &[Symbol]) -> Vec<Ident> { |
1124 | let def_site = self.with_def_site_ctxt(DUMMY_SP); | |
1125 | components.iter().map(|&s| Ident::new(s, def_site)).collect() | |
1126 | } | |
7cac9316 | 1127 | |
e74abb32 | 1128 | pub fn check_unused_macros(&mut self) { |
7cac9316 XL |
1129 | self.resolver.check_unused_macros(); |
1130 | } | |
223e47cc LB |
1131 | } |
1132 | ||
9fa01778 | 1133 | /// Extracts a string literal from the macro expanded version of `expr`, |
c295e0f8 XL |
1134 | /// returning a diagnostic error of `err_msg` if `expr` is not a string literal. |
1135 | /// The returned bool indicates whether an applicable suggestion has already been | |
1136 | /// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` | |
1137 | /// indicates that an ast error was encountered. | |
8faf50e0 | 1138 | pub fn expr_to_spanned_string<'a>( |
9fa01778 | 1139 | cx: &'a mut ExtCtxt<'_>, |
e1599b0c | 1140 | expr: P<ast::Expr>, |
8faf50e0 | 1141 | err_msg: &str, |
ee023bcb | 1142 | ) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorGuaranteed>, bool)>> { |
e1599b0c XL |
1143 | // Perform eager expansion on the expression. |
1144 | // We want to be able to handle e.g., `concat!("foo", "bar")`. | |
1145 | let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); | |
1146 | ||
e74abb32 XL |
1147 | Err(match expr.kind { |
1148 | ast::ExprKind::Lit(ref l) => match l.kind { | |
e1599b0c | 1149 | ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), |
c295e0f8 XL |
1150 | ast::LitKind::ByteStr(_) => { |
1151 | let mut err = cx.struct_span_err(l.span, err_msg); | |
1152 | err.span_suggestion( | |
1153 | expr.span.shrink_to_lo(), | |
1154 | "consider removing the leading `b`", | |
1155 | String::new(), | |
1156 | Applicability::MaybeIncorrect, | |
1157 | ); | |
1158 | Some((err, true)) | |
1159 | } | |
48663c56 | 1160 | ast::LitKind::Err(_) => None, |
c295e0f8 | 1161 | _ => Some((cx.struct_span_err(l.span, err_msg), false)), |
1a4d82fc | 1162 | }, |
0731742a | 1163 | ast::ExprKind::Err => None, |
c295e0f8 | 1164 | _ => Some((cx.struct_span_err(expr.span, err_msg), false)), |
8faf50e0 | 1165 | }) |
223e47cc LB |
1166 | } |
1167 | ||
c295e0f8 XL |
1168 | /// Extracts a string literal from the macro expanded version of `expr`, |
1169 | /// emitting `err_msg` if `expr` is not a string literal. This does not stop | |
1170 | /// compilation on error, merely emits a non-fatal error and returns `None`. | |
dfeec247 XL |
1171 | pub fn expr_to_string( |
1172 | cx: &mut ExtCtxt<'_>, | |
1173 | expr: P<ast::Expr>, | |
1174 | err_msg: &str, | |
1175 | ) -> Option<(Symbol, ast::StrStyle)> { | |
8faf50e0 | 1176 | expr_to_spanned_string(cx, expr, err_msg) |
74b04a01 | 1177 | .map_err(|err| { |
c295e0f8 | 1178 | err.map(|(mut err, _)| { |
74b04a01 XL |
1179 | err.emit(); |
1180 | }) | |
1181 | }) | |
8faf50e0 | 1182 | .ok() |
e1599b0c | 1183 | .map(|(symbol, style, _)| (symbol, style)) |
9e0c209e SL |
1184 | } |
1185 | ||
1a4d82fc JJ |
1186 | /// Non-fatally assert that `tts` is empty. Note that this function |
1187 | /// returns even when `tts` is non-empty, macros that *need* to stop | |
1188 | /// compilation should call | |
1189 | /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be | |
1190 | /// done as rarely as possible). | |
dfeec247 | 1191 | pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str) { |
9346a6ac | 1192 | if !tts.is_empty() { |
c34b1796 | 1193 | cx.span_err(sp, &format!("{} takes no arguments", name)); |
223e47cc LB |
1194 | } |
1195 | } | |
1196 | ||
ba9703b0 XL |
1197 | /// Parse an expression. On error, emit it, advancing to `Eof`, and return `None`. |
1198 | pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> { | |
1199 | match p.parse_expr() { | |
1200 | Ok(e) => return Some(e), | |
ee023bcb FG |
1201 | Err(mut err) => { |
1202 | err.emit(); | |
1203 | } | |
ba9703b0 XL |
1204 | } |
1205 | while p.token != token::Eof { | |
1206 | p.bump(); | |
1207 | } | |
1208 | None | |
1209 | } | |
1210 | ||
0531ce1d | 1211 | /// Interpreting `tts` as a comma-separated sequence of expressions, |
9fa01778 | 1212 | /// expect exactly one string literal, or emit an error and return `None`. |
dfeec247 XL |
1213 | pub fn get_single_str_from_tts( |
1214 | cx: &mut ExtCtxt<'_>, | |
1215 | sp: Span, | |
1216 | tts: TokenStream, | |
1217 | name: &str, | |
1218 | ) -> Option<String> { | |
1a4d82fc JJ |
1219 | let mut p = cx.new_parser_from_tts(tts); |
1220 | if p.token == token::Eof { | |
c34b1796 | 1221 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
dfeec247 | 1222 | return None; |
1a4d82fc | 1223 | } |
ba9703b0 | 1224 | let ret = parse_expr(&mut p)?; |
0531ce1d XL |
1225 | let _ = p.eat(&token::Comma); |
1226 | ||
1a4d82fc | 1227 | if p.token != token::Eof { |
c34b1796 | 1228 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
1a4d82fc | 1229 | } |
dfeec247 | 1230 | expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s.to_string()) |
223e47cc LB |
1231 | } |
1232 | ||
ba9703b0 XL |
1233 | /// Extracts comma-separated expressions from `tts`. |
1234 | /// On error, emit it, and return `None`. | |
dfeec247 XL |
1235 | pub fn get_exprs_from_tts( |
1236 | cx: &mut ExtCtxt<'_>, | |
1237 | sp: Span, | |
1238 | tts: TokenStream, | |
1239 | ) -> Option<Vec<P<ast::Expr>>> { | |
1a4d82fc JJ |
1240 | let mut p = cx.new_parser_from_tts(tts); |
1241 | let mut es = Vec::new(); | |
1242 | while p.token != token::Eof { | |
ba9703b0 | 1243 | let expr = parse_expr(&mut p)?; |
e1599b0c XL |
1244 | |
1245 | // Perform eager expansion on the expression. | |
1246 | // We want to be able to handle e.g., `concat!("foo", "bar")`. | |
1247 | let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); | |
1248 | ||
9fa01778 | 1249 | es.push(expr); |
9cc50fc6 | 1250 | if p.eat(&token::Comma) { |
1a4d82fc JJ |
1251 | continue; |
1252 | } | |
1253 | if p.token != token::Eof { | |
1254 | cx.span_err(sp, "expected token: `,`"); | |
1255 | return None; | |
223e47cc | 1256 | } |
223e47cc | 1257 | } |
1a4d82fc | 1258 | Some(es) |
223e47cc | 1259 | } |
6a06907d | 1260 | |
136023e0 XL |
1261 | pub fn parse_macro_name_and_helper_attrs( |
1262 | diag: &rustc_errors::Handler, | |
1263 | attr: &Attribute, | |
1264 | descr: &str, | |
1265 | ) -> Option<(Symbol, Vec<Symbol>)> { | |
1266 | // Once we've located the `#[proc_macro_derive]` attribute, verify | |
1267 | // that it's of the form `#[proc_macro_derive(Foo)]` or | |
1268 | // `#[proc_macro_derive(Foo, attributes(A, ..))]` | |
ee023bcb FG |
1269 | let Some(list) = attr.meta_item_list() else { |
1270 | return None; | |
136023e0 XL |
1271 | }; |
1272 | if list.len() != 1 && list.len() != 2 { | |
1273 | diag.span_err(attr.span, "attribute must have either one or two arguments"); | |
1274 | return None; | |
1275 | } | |
ee023bcb FG |
1276 | let Some(trait_attr) = list[0].meta_item() else { |
1277 | diag.span_err(list[0].span(), "not a meta item"); | |
1278 | return None; | |
136023e0 XL |
1279 | }; |
1280 | let trait_ident = match trait_attr.ident() { | |
1281 | Some(trait_ident) if trait_attr.is_word() => trait_ident, | |
1282 | _ => { | |
1283 | diag.span_err(trait_attr.span, "must only be one word"); | |
1284 | return None; | |
1285 | } | |
1286 | }; | |
1287 | ||
1288 | if !trait_ident.name.can_be_raw() { | |
1289 | diag.span_err( | |
1290 | trait_attr.span, | |
1291 | &format!("`{}` cannot be a name of {} macro", trait_ident, descr), | |
1292 | ); | |
1293 | } | |
1294 | ||
1295 | let attributes_attr = list.get(1); | |
1296 | let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { | |
1297 | if !attr.has_name(sym::attributes) { | |
ee023bcb | 1298 | diag.span_err(attr.span(), "second argument must be `attributes`"); |
136023e0 XL |
1299 | } |
1300 | attr.meta_item_list() | |
1301 | .unwrap_or_else(|| { | |
1302 | diag.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`"); | |
1303 | &[] | |
1304 | }) | |
1305 | .iter() | |
1306 | .filter_map(|attr| { | |
ee023bcb FG |
1307 | let Some(attr) = attr.meta_item() else { |
1308 | diag.span_err(attr.span(), "not a meta item"); | |
1309 | return None; | |
136023e0 XL |
1310 | }; |
1311 | ||
1312 | let ident = match attr.ident() { | |
1313 | Some(ident) if attr.is_word() => ident, | |
1314 | _ => { | |
1315 | diag.span_err(attr.span, "must only be one word"); | |
1316 | return None; | |
1317 | } | |
1318 | }; | |
1319 | if !ident.name.can_be_raw() { | |
1320 | diag.span_err( | |
1321 | attr.span, | |
1322 | &format!("`{}` cannot be a name of derive helper attribute", ident), | |
1323 | ); | |
1324 | } | |
1325 | ||
1326 | Some(ident.name) | |
1327 | }) | |
1328 | .collect() | |
1329 | } else { | |
1330 | Vec::new() | |
1331 | }; | |
1332 | ||
1333 | Some((trait_ident.name, proc_attrs)) | |
1334 | } | |
1335 | ||
6a06907d XL |
1336 | /// This nonterminal looks like some specific enums from |
1337 | /// `proc-macro-hack` and `procedural-masquerade` crates. | |
1338 | /// We need to maintain some special pretty-printing behavior for them due to incorrect | |
1339 | /// asserts in old versions of those crates and their wide use in the ecosystem. | |
1340 | /// See issue #73345 for more details. | |
1341 | /// FIXME(#73933): Remove this eventually. | |
1342 | pub(crate) fn pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool { | |
1343 | let item = match nt { | |
1344 | Nonterminal::NtItem(item) => item, | |
1345 | Nonterminal::NtStmt(stmt) => match &stmt.kind { | |
1346 | ast::StmtKind::Item(item) => item, | |
1347 | _ => return false, | |
1348 | }, | |
1349 | _ => return false, | |
1350 | }; | |
1351 | ||
1352 | let name = item.ident.name; | |
1353 | if name == sym::ProceduralMasqueradeDummyType { | |
1354 | if let ast::ItemKind::Enum(enum_def, _) = &item.kind { | |
1355 | if let [variant] = &*enum_def.variants { | |
1356 | if variant.ident.name == sym::Input { | |
1357 | sess.buffer_lint_with_diagnostic( | |
1358 | &PROC_MACRO_BACK_COMPAT, | |
1359 | item.ident.span, | |
1360 | ast::CRATE_NODE_ID, | |
1361 | "using `procedural-masquerade` crate", | |
1362 | BuiltinLintDiagnostics::ProcMacroBackCompat( | |
1363 | "The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. \ | |
1364 | Versions of this crate below 0.1.7 will eventually stop compiling.".to_string()) | |
1365 | ); | |
1366 | return true; | |
1367 | } | |
1368 | } | |
1369 | } | |
1370 | } | |
1371 | false | |
1372 | } |