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