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