]>
Commit | Line | Data |
---|---|---|
e74abb32 | 1 | use crate::base::*; |
dfeec247 | 2 | use crate::config::StripUnconfigured; |
ba9703b0 | 3 | use crate::configure; |
6a06907d | 4 | use crate::hygiene::SyntaxContext; |
e74abb32 | 5 | use crate::mbe::macro_rules::annotate_err_with_kind; |
6a06907d | 6 | use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; |
e74abb32 XL |
7 | use crate::placeholders::{placeholder, PlaceholderExpander}; |
8 | ||
6a06907d | 9 | use rustc_ast as ast; |
74b04a01 XL |
10 | use rustc_ast::mut_visit::*; |
11 | use rustc_ast::ptr::P; | |
12 | use rustc_ast::token; | |
13 | use rustc_ast::tokenstream::TokenStream; | |
74b04a01 | 14 | use rustc_ast::visit::{self, AssocCtxt, Visitor}; |
136023e0 | 15 | use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs}; |
6a06907d XL |
16 | use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; |
17 | use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; | |
74b04a01 | 18 | use rustc_ast_pretty::pprust; |
17df50a5 | 19 | use rustc_attr::is_builtin_attr; |
ba9703b0 | 20 | use rustc_data_structures::map_in_place::MapInPlace; |
3dfed10e | 21 | use rustc_data_structures::stack::ensure_sufficient_stack; |
6a06907d | 22 | use rustc_data_structures::sync::Lrc; |
cdc7bbd5 | 23 | use rustc_errors::{Applicability, FatalError, PResult}; |
60c5eb7d | 24 | use rustc_feature::Features; |
136023e0 XL |
25 | use rustc_parse::parser::{ |
26 | AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma, | |
27 | }; | |
60c5eb7d | 28 | use rustc_parse::validate_attr; |
74b04a01 XL |
29 | use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; |
30 | use rustc_session::lint::BuiltinLintDiagnostics; | |
31 | use rustc_session::parse::{feature_err, ParseSess}; | |
f9f354fc | 32 | use rustc_session::Limit; |
17df50a5 | 33 | use rustc_span::symbol::{sym, Ident}; |
136023e0 | 34 | use rustc_span::{FileName, LocalExpnId, Span}; |
9fa01778 | 35 | |
9fa01778 | 36 | use smallvec::{smallvec, SmallVec}; |
9fa01778 | 37 | use std::ops::DerefMut; |
ff7c6d11 | 38 | use std::path::PathBuf; |
dfeec247 | 39 | use std::rc::Rc; |
17df50a5 | 40 | use std::{iter, mem}; |
9e0c209e | 41 | |
8faf50e0 XL |
42 | macro_rules! ast_fragments { |
43 | ( | |
44 | $($Kind:ident($AstTy:ty) { | |
45 | $kind_name:expr; | |
9fa01778 | 46 | $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? |
74b04a01 | 47 | $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)? |
8faf50e0 XL |
48 | fn $make_ast:ident; |
49 | })* | |
50 | ) => { | |
51 | /// A fragment of AST that can be produced by a single macro expansion. | |
52 | /// Can also serve as an input and intermediate result for macro expansion operations. | |
53 | pub enum AstFragment { | |
54 | OptExpr(Option<P<ast::Expr>>), | |
55 | $($Kind($AstTy),)* | |
56 | } | |
57 | ||
58 | /// "Discriminant" of an AST fragment. | |
9e0c209e | 59 | #[derive(Copy, Clone, PartialEq, Eq)] |
8faf50e0 XL |
60 | pub enum AstFragmentKind { |
61 | OptExpr, | |
62 | $($Kind,)* | |
63 | } | |
9e0c209e | 64 | |
8faf50e0 | 65 | impl AstFragmentKind { |
9e0c209e SL |
66 | pub fn name(self) -> &'static str { |
67 | match self { | |
8faf50e0 XL |
68 | AstFragmentKind::OptExpr => "expression", |
69 | $(AstFragmentKind::$Kind => $kind_name,)* | |
9e0c209e SL |
70 | } |
71 | } | |
92a42be0 | 72 | |
8faf50e0 | 73 | fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> { |
9e0c209e | 74 | match self { |
8faf50e0 XL |
75 | AstFragmentKind::OptExpr => |
76 | result.make_expr().map(Some).map(AstFragment::OptExpr), | |
77 | $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* | |
9e0c209e SL |
78 | } |
79 | } | |
80 | } | |
1a4d82fc | 81 | |
8faf50e0 | 82 | impl AstFragment { |
e74abb32 XL |
83 | pub fn add_placeholders(&mut self, placeholders: &[NodeId]) { |
84 | if placeholders.is_empty() { | |
85 | return; | |
86 | } | |
87 | match self { | |
88 | $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| { | |
89 | // We are repeating through arguments with `many`, to do that we have to | |
90 | // mention some macro variable from those arguments even if it's not used. | |
e74abb32 XL |
91 | macro _repeating($flat_map_ast_elt) {} |
92 | placeholder(AstFragmentKind::$Kind, *id, None).$make_ast() | |
93 | })),)?)* | |
94 | _ => panic!("unexpected AST fragment kind") | |
95 | } | |
96 | } | |
97 | ||
9e0c209e SL |
98 | pub fn make_opt_expr(self) -> Option<P<ast::Expr>> { |
99 | match self { | |
8faf50e0 XL |
100 | AstFragment::OptExpr(expr) => expr, |
101 | _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), | |
9e0c209e SL |
102 | } |
103 | } | |
8faf50e0 XL |
104 | |
105 | $(pub fn $make_ast(self) -> $AstTy { | |
9e0c209e | 106 | match self { |
8faf50e0 XL |
107 | AstFragment::$Kind(ast) => ast, |
108 | _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), | |
9e0c209e | 109 | } |
8faf50e0 | 110 | })* |
9e0c209e | 111 | |
9fa01778 | 112 | pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) { |
9e0c209e | 113 | match self { |
9fa01778 XL |
114 | AstFragment::OptExpr(opt_expr) => { |
115 | visit_clobber(opt_expr, |opt_expr| { | |
116 | if let Some(expr) = opt_expr { | |
117 | vis.filter_map_expr(expr) | |
118 | } else { | |
119 | None | |
120 | } | |
121 | }); | |
122 | } | |
dc9dc135 | 123 | $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* |
8faf50e0 | 124 | $($(AstFragment::$Kind(ast) => |
dc9dc135 | 125 | ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)* |
9e0c209e SL |
126 | } |
127 | } | |
1a4d82fc | 128 | |
476ff2be | 129 | pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { |
9e0c209e | 130 | match *self { |
8faf50e0 XL |
131 | AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), |
132 | AstFragment::OptExpr(None) => {} | |
dc9dc135 | 133 | $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* |
8faf50e0 | 134 | $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { |
74b04a01 | 135 | visitor.$visit_ast_elt(ast_elt, $($args)*); |
dc9dc135 | 136 | })?)* |
9e0c209e | 137 | } |
3157f602 | 138 | } |
9e0c209e SL |
139 | } |
140 | ||
e74abb32 XL |
141 | impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> { |
142 | $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>) | |
8faf50e0 XL |
143 | -> Option<$AstTy> { |
144 | Some(self.make(AstFragmentKind::$Kind).$make_ast()) | |
9e0c209e | 145 | })* |
1a4d82fc | 146 | } |
9e0c209e | 147 | } |
3157f602 | 148 | } |
1a4d82fc | 149 | |
8faf50e0 | 150 | ast_fragments! { |
9fa01778 XL |
151 | Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; } |
152 | Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; } | |
153 | Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; } | |
0bf4aa26 | 154 | Stmts(SmallVec<[ast::Stmt; 1]>) { |
74b04a01 | 155 | "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; |
0bf4aa26 XL |
156 | } |
157 | Items(SmallVec<[P<ast::Item>; 1]>) { | |
74b04a01 | 158 | "item"; many fn flat_map_item; fn visit_item(); fn make_items; |
0bf4aa26 | 159 | } |
74b04a01 XL |
160 | TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) { |
161 | "trait item"; | |
162 | many fn flat_map_trait_item; | |
163 | fn visit_assoc_item(AssocCtxt::Trait); | |
164 | fn make_trait_items; | |
8faf50e0 | 165 | } |
74b04a01 XL |
166 | ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { |
167 | "impl item"; | |
168 | many fn flat_map_impl_item; | |
169 | fn visit_assoc_item(AssocCtxt::Impl); | |
170 | fn make_impl_items; | |
8faf50e0 | 171 | } |
74b04a01 | 172 | ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) { |
e1599b0c XL |
173 | "foreign item"; |
174 | many fn flat_map_foreign_item; | |
74b04a01 | 175 | fn visit_foreign_item(); |
e1599b0c XL |
176 | fn make_foreign_items; |
177 | } | |
178 | Arms(SmallVec<[ast::Arm; 1]>) { | |
74b04a01 | 179 | "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; |
e1599b0c | 180 | } |
6a06907d XL |
181 | Fields(SmallVec<[ast::ExprField; 1]>) { |
182 | "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; | |
e1599b0c | 183 | } |
6a06907d | 184 | FieldPats(SmallVec<[ast::PatField; 1]>) { |
e1599b0c | 185 | "field pattern"; |
6a06907d XL |
186 | many fn flat_map_pat_field; |
187 | fn visit_pat_field(); | |
188 | fn make_pat_fields; | |
e1599b0c XL |
189 | } |
190 | GenericParams(SmallVec<[ast::GenericParam; 1]>) { | |
191 | "generic parameter"; | |
192 | many fn flat_map_generic_param; | |
74b04a01 | 193 | fn visit_generic_param(); |
e1599b0c XL |
194 | fn make_generic_params; |
195 | } | |
196 | Params(SmallVec<[ast::Param; 1]>) { | |
74b04a01 | 197 | "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; |
e1599b0c | 198 | } |
6a06907d | 199 | StructFields(SmallVec<[ast::FieldDef; 1]>) { |
e1599b0c | 200 | "field"; |
6a06907d XL |
201 | many fn flat_map_field_def; |
202 | fn visit_field_def(); | |
203 | fn make_field_defs; | |
e1599b0c XL |
204 | } |
205 | Variants(SmallVec<[ast::Variant; 1]>) { | |
74b04a01 | 206 | "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; |
8faf50e0 | 207 | } |
3157f602 | 208 | } |
c1a9b12d | 209 | |
cdc7bbd5 XL |
210 | pub enum SupportsMacroExpansion { |
211 | No, | |
212 | Yes { supports_inner_attrs: bool }, | |
213 | } | |
214 | ||
8faf50e0 | 215 | impl AstFragmentKind { |
ba9703b0 | 216 | crate fn dummy(self, span: Span) -> AstFragment { |
416331ca | 217 | self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") |
9e0c209e SL |
218 | } |
219 | ||
cdc7bbd5 | 220 | pub fn supports_macro_expansion(self) -> SupportsMacroExpansion { |
fc512014 XL |
221 | match self { |
222 | AstFragmentKind::OptExpr | |
223 | | AstFragmentKind::Expr | |
fc512014 | 224 | | AstFragmentKind::Stmts |
cdc7bbd5 XL |
225 | | AstFragmentKind::Ty |
226 | | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false }, | |
227 | AstFragmentKind::Items | |
fc512014 XL |
228 | | AstFragmentKind::TraitItems |
229 | | AstFragmentKind::ImplItems | |
cdc7bbd5 XL |
230 | | AstFragmentKind::ForeignItems => { |
231 | SupportsMacroExpansion::Yes { supports_inner_attrs: true } | |
232 | } | |
fc512014 XL |
233 | AstFragmentKind::Arms |
234 | | AstFragmentKind::Fields | |
235 | | AstFragmentKind::FieldPats | |
236 | | AstFragmentKind::GenericParams | |
237 | | AstFragmentKind::Params | |
238 | | AstFragmentKind::StructFields | |
cdc7bbd5 | 239 | | AstFragmentKind::Variants => SupportsMacroExpansion::No, |
fc512014 XL |
240 | } |
241 | } | |
242 | ||
dfeec247 XL |
243 | fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>( |
244 | self, | |
245 | items: I, | |
246 | ) -> AstFragment { | |
0531ce1d | 247 | let mut items = items.into_iter(); |
9e0c209e | 248 | match self { |
dfeec247 XL |
249 | AstFragmentKind::Arms => { |
250 | AstFragment::Arms(items.map(Annotatable::expect_arm).collect()) | |
251 | } | |
252 | AstFragmentKind::Fields => { | |
6a06907d | 253 | AstFragment::Fields(items.map(Annotatable::expect_expr_field).collect()) |
dfeec247 XL |
254 | } |
255 | AstFragmentKind::FieldPats => { | |
6a06907d | 256 | AstFragment::FieldPats(items.map(Annotatable::expect_pat_field).collect()) |
dfeec247 XL |
257 | } |
258 | AstFragmentKind::GenericParams => { | |
259 | AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect()) | |
260 | } | |
261 | AstFragmentKind::Params => { | |
262 | AstFragment::Params(items.map(Annotatable::expect_param).collect()) | |
263 | } | |
264 | AstFragmentKind::StructFields => { | |
6a06907d | 265 | AstFragment::StructFields(items.map(Annotatable::expect_field_def).collect()) |
dfeec247 XL |
266 | } |
267 | AstFragmentKind::Variants => { | |
268 | AstFragment::Variants(items.map(Annotatable::expect_variant).collect()) | |
269 | } | |
270 | AstFragmentKind::Items => { | |
271 | AstFragment::Items(items.map(Annotatable::expect_item).collect()) | |
272 | } | |
273 | AstFragmentKind::ImplItems => { | |
274 | AstFragment::ImplItems(items.map(Annotatable::expect_impl_item).collect()) | |
275 | } | |
276 | AstFragmentKind::TraitItems => { | |
277 | AstFragment::TraitItems(items.map(Annotatable::expect_trait_item).collect()) | |
278 | } | |
279 | AstFragmentKind::ForeignItems => { | |
280 | AstFragment::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()) | |
281 | } | |
282 | AstFragmentKind::Stmts => { | |
283 | AstFragment::Stmts(items.map(Annotatable::expect_stmt).collect()) | |
284 | } | |
8faf50e0 | 285 | AstFragmentKind::Expr => AstFragment::Expr( |
dfeec247 | 286 | items.next().expect("expected exactly one expression").expect_expr(), |
0531ce1d | 287 | ), |
dfeec247 XL |
288 | AstFragmentKind::OptExpr => { |
289 | AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)) | |
290 | } | |
291 | AstFragmentKind::Pat | AstFragmentKind::Ty => { | |
292 | panic!("patterns and types aren't annotatable") | |
293 | } | |
9e0c209e | 294 | } |
3157f602 XL |
295 | } |
296 | } | |
297 | ||
9e0c209e SL |
298 | pub struct Invocation { |
299 | pub kind: InvocationKind, | |
e1599b0c | 300 | pub fragment_kind: AstFragmentKind, |
8bb4bdeb | 301 | pub expansion_data: ExpansionData, |
9e0c209e SL |
302 | } |
303 | ||
304 | pub enum InvocationKind { | |
305 | Bang { | |
ba9703b0 | 306 | mac: ast::MacCall, |
9e0c209e SL |
307 | span: Span, |
308 | }, | |
309 | Attr { | |
416331ca | 310 | attr: ast::Attribute, |
6a06907d XL |
311 | // Re-insertion position for inert attributes. |
312 | pos: usize, | |
8bb4bdeb | 313 | item: Annotatable, |
416331ca XL |
314 | // Required for resolving derive helper attributes. |
315 | derives: Vec<Path>, | |
8bb4bdeb XL |
316 | }, |
317 | Derive { | |
cc61c64b | 318 | path: Path, |
9e0c209e SL |
319 | item: Annotatable, |
320 | }, | |
321 | } | |
322 | ||
e74abb32 XL |
323 | impl InvocationKind { |
324 | fn placeholder_visibility(&self) -> Option<ast::Visibility> { | |
325 | // HACK: For unnamed fields placeholders should have the same visibility as the actual | |
326 | // fields because for tuple structs/variants resolve determines visibilities of their | |
327 | // constructor using these field visibilities before attributes on them are are expanded. | |
328 | // The assumption is that the attribute expansion cannot change field visibilities, | |
329 | // and it holds because only inert attributes are supported in this position. | |
330 | match self { | |
6a06907d XL |
331 | InvocationKind::Attr { item: Annotatable::FieldDef(field), .. } |
332 | | InvocationKind::Derive { item: Annotatable::FieldDef(field), .. } | |
dfeec247 XL |
333 | if field.ident.is_none() => |
334 | { | |
335 | Some(field.vis.clone()) | |
336 | } | |
e74abb32 XL |
337 | _ => None, |
338 | } | |
339 | } | |
340 | } | |
341 | ||
9e0c209e | 342 | impl Invocation { |
8faf50e0 | 343 | pub fn span(&self) -> Span { |
416331ca XL |
344 | match &self.kind { |
345 | InvocationKind::Bang { span, .. } => *span, | |
346 | InvocationKind::Attr { attr, .. } => attr.span, | |
347 | InvocationKind::Derive { path, .. } => path.span, | |
c1a9b12d | 348 | } |
5bcae85e SL |
349 | } |
350 | } | |
c1a9b12d | 351 | |
dc9dc135 | 352 | pub struct MacroExpander<'a, 'b> { |
9e0c209e | 353 | pub cx: &'a mut ExtCtxt<'b>, |
a1dfa0c6 | 354 | monotonic: bool, // cf. `cx.monotonic_expander()` |
9e0c209e SL |
355 | } |
356 | ||
357 | impl<'a, 'b> MacroExpander<'a, 'b> { | |
358 | pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { | |
dc9dc135 | 359 | MacroExpander { cx, monotonic } |
9e0c209e SL |
360 | } |
361 | ||
6a06907d XL |
362 | // FIXME: Avoid visiting the crate as a `Mod` item, |
363 | // make crate a first class expansion target instead. | |
c30ab7b3 | 364 | pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { |
17df50a5 XL |
365 | let file_path = match self.cx.source_map().span_to_filename(krate.span) { |
366 | FileName::Real(name) => name | |
367 | .into_local_path() | |
368 | .expect("attempting to resolve a file path in an external file"), | |
369 | other => PathBuf::from(other.prefer_local().to_string()), | |
c30ab7b3 | 370 | }; |
6a06907d XL |
371 | let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); |
372 | self.cx.root_path = dir_path.clone(); | |
373 | self.cx.current_expansion.module = Rc::new(ModuleData { | |
374 | mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], | |
375 | file_path_stack: vec![file_path], | |
376 | dir_path, | |
377 | }); | |
cc61c64b | 378 | |
b7449926 | 379 | let krate_item = AstFragment::Items(smallvec![P(ast::Item { |
9e0c209e SL |
380 | attrs: krate.attrs, |
381 | span: krate.span, | |
6a06907d XL |
382 | kind: ast::ItemKind::Mod( |
383 | Unsafe::No, | |
384 | ModKind::Loaded(krate.items, Inline::Yes, krate.span) | |
385 | ), | |
dc9dc135 | 386 | ident: Ident::invalid(), |
5bcae85e | 387 | id: ast::DUMMY_NODE_ID, |
1b1a35ee XL |
388 | vis: ast::Visibility { |
389 | span: krate.span.shrink_to_lo(), | |
390 | kind: ast::VisibilityKind::Public, | |
391 | tokens: None, | |
392 | }, | |
3b2f2976 | 393 | tokens: None, |
b7449926 | 394 | })]); |
9e0c209e | 395 | |
e1599b0c | 396 | match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { |
6a06907d XL |
397 | Some(ast::Item { |
398 | attrs, | |
399 | kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)), | |
400 | .. | |
401 | }) => { | |
9e0c209e | 402 | krate.attrs = attrs; |
6a06907d | 403 | krate.items = items; |
dfeec247 | 404 | } |
cc61c64b XL |
405 | None => { |
406 | // Resolution failed so we return an empty expansion | |
407 | krate.attrs = vec![]; | |
6a06907d | 408 | krate.items = vec![]; |
dfeec247 | 409 | } |
74b04a01 XL |
410 | Some(ast::Item { span, kind, .. }) => { |
411 | krate.attrs = vec![]; | |
6a06907d | 412 | krate.items = vec![]; |
74b04a01 XL |
413 | self.cx.span_err( |
414 | span, | |
415 | &format!( | |
416 | "expected crate top-level item to be a module after macro expansion, found {} {}", | |
417 | kind.article(), kind.descr() | |
418 | ), | |
419 | ); | |
cdc7bbd5 XL |
420 | // FIXME: this workaround issue #84569 |
421 | FatalError.raise(); | |
74b04a01 | 422 | } |
9e0c209e | 423 | }; |
7cac9316 | 424 | self.cx.trace_macros_diag(); |
9e0c209e | 425 | krate |
5bcae85e | 426 | } |
1a4d82fc | 427 | |
e1599b0c XL |
428 | // Recursively expand all macro invocations in this AST fragment. |
429 | pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { | |
9e0c209e | 430 | let orig_expansion_data = self.cx.current_expansion.clone(); |
fc512014 | 431 | let orig_force_mode = self.cx.force_mode; |
9e0c209e | 432 | |
8faf50e0 | 433 | // Collect all macro invocations and replace them with placeholders. |
dfeec247 XL |
434 | let (mut fragment_with_placeholders, mut invocations) = |
435 | self.collect_invocations(input_fragment, &[]); | |
8faf50e0 XL |
436 | |
437 | // Optimization: if we resolve all imports now, | |
438 | // we'll be able to immediately resolve most of imported macros. | |
476ff2be | 439 | self.resolve_imports(); |
9e0c209e | 440 | |
b7449926 | 441 | // Resolve paths in all invocations and produce output expanded fragments for them, but |
8faf50e0 XL |
442 | // do not insert them into our input AST fragment yet, only store in `expanded_fragments`. |
443 | // The output fragments also go through expansion recursively until no invocations are left. | |
444 | // Unresolved macros produce dummy outputs as a recovery measure. | |
445 | invocations.reverse(); | |
446 | let mut expanded_fragments = Vec::new(); | |
c30ab7b3 SL |
447 | let mut undetermined_invocations = Vec::new(); |
448 | let (mut progress, mut force) = (false, !self.monotonic); | |
449 | loop { | |
6a06907d | 450 | let (invoc, ext) = if let Some(invoc) = invocations.pop() { |
c30ab7b3 | 451 | invoc |
c30ab7b3 | 452 | } else { |
476ff2be | 453 | self.resolve_imports(); |
dfeec247 XL |
454 | if undetermined_invocations.is_empty() { |
455 | break; | |
456 | } | |
416331ca | 457 | invocations = mem::take(&mut undetermined_invocations); |
c30ab7b3 | 458 | force = !mem::replace(&mut progress, false); |
fc512014 XL |
459 | if force && self.monotonic { |
460 | self.cx.sess.delay_span_bug( | |
461 | invocations.last().unwrap().0.span(), | |
462 | "expansion entered force mode without producing any errors", | |
463 | ); | |
464 | } | |
dfeec247 | 465 | continue; |
c30ab7b3 SL |
466 | }; |
467 | ||
6a06907d XL |
468 | let ext = match ext { |
469 | Some(ext) => ext, | |
ba9703b0 XL |
470 | None => { |
471 | let eager_expansion_root = if self.monotonic { | |
472 | invoc.expansion_data.id | |
473 | } else { | |
474 | orig_expansion_data.id | |
475 | }; | |
476 | match self.cx.resolver.resolve_macro_invocation( | |
477 | &invoc, | |
478 | eager_expansion_root, | |
479 | force, | |
480 | ) { | |
6a06907d | 481 | Ok(ext) => ext, |
ba9703b0 XL |
482 | Err(Indeterminate) => { |
483 | // Cannot resolve, will retry this invocation later. | |
484 | undetermined_invocations.push((invoc, None)); | |
485 | continue; | |
486 | } | |
487 | } | |
c30ab7b3 SL |
488 | } |
489 | }; | |
490 | ||
416331ca | 491 | let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; |
136023e0 | 492 | let depth = depth - orig_expansion_data.depth; |
9e0c209e | 493 | self.cx.current_expansion = invoc.expansion_data.clone(); |
fc512014 | 494 | self.cx.force_mode = force; |
9e0c209e | 495 | |
fc512014 | 496 | let fragment_kind = invoc.fragment_kind; |
6a06907d XL |
497 | let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) { |
498 | ExpandResult::Ready(fragment) => { | |
cdc7bbd5 | 499 | let mut derive_invocations = Vec::new(); |
6a06907d XL |
500 | let derive_placeholders = self |
501 | .cx | |
502 | .resolver | |
503 | .take_derive_resolutions(expn_id) | |
504 | .map(|derives| { | |
cdc7bbd5 | 505 | derive_invocations.reserve(derives.len()); |
6a06907d XL |
506 | derives |
507 | .into_iter() | |
136023e0 | 508 | .map(|(path, item, _exts)| { |
6a06907d XL |
509 | // FIXME: Consider using the derive resolutions (`_exts`) |
510 | // instead of enqueuing the derives to be resolved again later. | |
136023e0 | 511 | let expn_id = LocalExpnId::fresh_empty(); |
cdc7bbd5 | 512 | derive_invocations.push(( |
6a06907d | 513 | Invocation { |
136023e0 | 514 | kind: InvocationKind::Derive { path, item }, |
6a06907d XL |
515 | fragment_kind, |
516 | expansion_data: ExpansionData { | |
517 | id: expn_id, | |
518 | ..self.cx.current_expansion.clone() | |
519 | }, | |
fc512014 | 520 | }, |
6a06907d XL |
521 | None, |
522 | )); | |
523 | NodeId::placeholder_from_expn_id(expn_id) | |
524 | }) | |
525 | .collect::<Vec<_>>() | |
526 | }) | |
527 | .unwrap_or_default(); | |
ea8adc8c | 528 | |
cdc7bbd5 XL |
529 | let (fragment, collected_invocations) = |
530 | self.collect_invocations(fragment, &derive_placeholders); | |
531 | // We choose to expand any derive invocations associated with this macro invocation | |
532 | // *before* any macro invocations collected from the output fragment | |
533 | derive_invocations.extend(collected_invocations); | |
534 | (fragment, derive_invocations) | |
8bb4bdeb | 535 | } |
6a06907d XL |
536 | ExpandResult::Retry(invoc) => { |
537 | if force { | |
538 | self.cx.span_bug( | |
539 | invoc.span(), | |
540 | "expansion entered force mode but is still stuck", | |
541 | ); | |
542 | } else { | |
543 | // Cannot expand, will retry this invocation later. | |
544 | undetermined_invocations.push((invoc, Some(ext))); | |
545 | continue; | |
546 | } | |
547 | } | |
9e0c209e SL |
548 | }; |
549 | ||
ba9703b0 | 550 | progress = true; |
8faf50e0 XL |
551 | if expanded_fragments.len() < depth { |
552 | expanded_fragments.push(Vec::new()); | |
9e0c209e | 553 | } |
416331ca | 554 | expanded_fragments[depth - 1].push((expn_id, expanded_fragment)); |
ba9703b0 | 555 | invocations.extend(new_invocations.into_iter().rev()); |
9e0c209e SL |
556 | } |
557 | ||
558 | self.cx.current_expansion = orig_expansion_data; | |
fc512014 | 559 | self.cx.force_mode = orig_force_mode; |
9e0c209e | 560 | |
8faf50e0 | 561 | // Finally incorporate all the expanded macros into the input AST fragment. |
9e0c209e | 562 | let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); |
8faf50e0 | 563 | while let Some(expanded_fragments) = expanded_fragments.pop() { |
e1599b0c | 564 | for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() { |
dfeec247 XL |
565 | placeholder_expander |
566 | .add(NodeId::placeholder_from_expn_id(expn_id), expanded_fragment); | |
9e0c209e SL |
567 | } |
568 | } | |
9fa01778 XL |
569 | fragment_with_placeholders.mut_visit_with(&mut placeholder_expander); |
570 | fragment_with_placeholders | |
9e0c209e SL |
571 | } |
572 | ||
476ff2be SL |
573 | fn resolve_imports(&mut self) { |
574 | if self.monotonic { | |
476ff2be | 575 | self.cx.resolver.resolve_imports(); |
476ff2be SL |
576 | } |
577 | } | |
578 | ||
9fa01778 | 579 | /// Collects all macro invocations reachable at this time in this AST fragment, and replace |
8faf50e0 XL |
580 | /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s. |
581 | /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and | |
582 | /// prepares data for resolving paths of macro invocations. | |
dfeec247 XL |
583 | fn collect_invocations( |
584 | &mut self, | |
585 | mut fragment: AstFragment, | |
586 | extra_placeholders: &[NodeId], | |
6a06907d | 587 | ) -> (AstFragment, Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>) { |
9fa01778 | 588 | // Resolve `$crate`s in the fragment for pretty-printing. |
416331ca | 589 | self.cx.resolver.resolve_dollar_crates(); |
9fa01778 XL |
590 | |
591 | let invocations = { | |
9e0c209e | 592 | let mut collector = InvocationCollector { |
cdc7bbd5 XL |
593 | // Non-derive macro invocations cannot see the results of cfg expansion - they |
594 | // will either be removed along with the item, or invoked before the cfg/cfg_attr | |
595 | // attribute is expanded. Therefore, we don't need to configure the tokens | |
596 | // Derive macros *can* see the results of cfg-expansion - they are handled | |
597 | // specially in `fully_expand_fragment` | |
5869c6ff XL |
598 | cfg: StripUnconfigured { |
599 | sess: &self.cx.sess, | |
600 | features: self.cx.ecfg.features, | |
cdc7bbd5 | 601 | config_tokens: false, |
5869c6ff | 602 | }, |
9e0c209e SL |
603 | cx: self.cx, |
604 | invocations: Vec::new(), | |
605 | monotonic: self.monotonic, | |
606 | }; | |
9fa01778 | 607 | fragment.mut_visit_with(&mut collector); |
e74abb32 | 608 | fragment.add_placeholders(extra_placeholders); |
9fa01778 | 609 | collector.invocations |
9e0c209e | 610 | }; |
9e0c209e SL |
611 | |
612 | if self.monotonic { | |
dfeec247 XL |
613 | self.cx |
614 | .resolver | |
615 | .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment); | |
9e0c209e SL |
616 | } |
617 | ||
9fa01778 | 618 | (fragment, invocations) |
9e0c209e SL |
619 | } |
620 | ||
74b04a01 XL |
621 | fn error_recursion_limit_reached(&mut self) { |
622 | let expn_data = self.cx.current_expansion.id.expn_data(); | |
623 | let suggested_limit = self.cx.ecfg.recursion_limit * 2; | |
624 | self.cx | |
625 | .struct_span_err( | |
dfeec247 XL |
626 | expn_data.call_site, |
627 | &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), | |
74b04a01 XL |
628 | ) |
629 | .help(&format!( | |
630 | "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", | |
631 | suggested_limit, self.cx.ecfg.crate_name, | |
632 | )) | |
633 | .emit(); | |
634 | self.cx.trace_macros_diag(); | |
74b04a01 XL |
635 | } |
636 | ||
637 | /// A macro's expansion does not fit in this fragment kind. | |
638 | /// For example, a non-type macro in a type position. | |
ba9703b0 | 639 | fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) { |
74b04a01 XL |
640 | let msg = format!( |
641 | "non-{kind} macro in {kind} position: {path}", | |
642 | kind = kind.name(), | |
643 | path = pprust::path_to_string(&mac.path), | |
644 | ); | |
645 | self.cx.span_err(span, &msg); | |
646 | self.cx.trace_macros_diag(); | |
647 | } | |
648 | ||
ba9703b0 XL |
649 | fn expand_invoc( |
650 | &mut self, | |
651 | invoc: Invocation, | |
652 | ext: &SyntaxExtensionKind, | |
653 | ) -> ExpandResult<AstFragment, Invocation> { | |
654 | let recursion_limit = | |
655 | self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); | |
f9f354fc | 656 | if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) { |
ba9703b0 XL |
657 | if self.cx.reduced_recursion_limit.is_none() { |
658 | self.error_recursion_limit_reached(); | |
659 | } | |
660 | ||
661 | // Reduce the recursion limit by half each time it triggers. | |
662 | self.cx.reduced_recursion_limit = Some(recursion_limit / 2); | |
663 | ||
664 | return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span())); | |
9e0c209e | 665 | } |
cc61c64b | 666 | |
e74abb32 | 667 | let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); |
ba9703b0 | 668 | ExpandResult::Ready(match invoc.kind { |
416331ca XL |
669 | InvocationKind::Bang { mac, .. } => match ext { |
670 | SyntaxExtensionKind::Bang(expander) => { | |
ba9703b0 XL |
671 | let tok_result = match expander.expand(self.cx, span, mac.args.inner_tokens()) { |
672 | Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)), | |
673 | Ok(ts) => ts, | |
674 | }; | |
e74abb32 | 675 | self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) |
dc9dc135 | 676 | } |
416331ca XL |
677 | SyntaxExtensionKind::LegacyBang(expander) => { |
678 | let prev = self.cx.current_expansion.prior_type_ascription; | |
e1599b0c | 679 | self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription; |
60c5eb7d | 680 | let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); |
416331ca XL |
681 | let result = if let Some(result) = fragment_kind.make_from(tok_result) { |
682 | result | |
683 | } else { | |
74b04a01 | 684 | self.error_wrong_fragment_kind(fragment_kind, &mac, span); |
416331ca XL |
685 | fragment_kind.dummy(span) |
686 | }; | |
687 | self.cx.current_expansion.prior_type_ascription = prev; | |
688 | result | |
689 | } | |
dfeec247 XL |
690 | _ => unreachable!(), |
691 | }, | |
6a06907d | 692 | InvocationKind::Attr { attr, pos, mut item, derives } => match ext { |
416331ca | 693 | SyntaxExtensionKind::Attr(expander) => { |
e74abb32 | 694 | self.gate_proc_macro_input(&item); |
416331ca | 695 | self.gate_proc_macro_attr_item(span, &item); |
cdc7bbd5 XL |
696 | let mut fake_tokens = false; |
697 | if let Annotatable::Item(item_inner) = &item { | |
698 | if let ItemKind::Mod(_, mod_kind) = &item_inner.kind { | |
699 | // FIXME: Collect tokens and use them instead of generating | |
700 | // fake ones. These are unstable, so it needs to be | |
701 | // fixed prior to stabilization | |
702 | // Fake tokens when we are invoking an inner attribute, and: | |
703 | fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) && | |
704 | // We are invoking an attribute on the crate root, or an outline | |
705 | // module | |
706 | (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _))); | |
707 | } | |
708 | } | |
709 | let tokens = if fake_tokens { | |
710 | rustc_parse::fake_token_stream( | |
5869c6ff XL |
711 | &self.cx.sess.parse_sess, |
712 | &item.into_nonterminal(), | |
cdc7bbd5 XL |
713 | ) |
714 | } else { | |
715 | item.into_tokens(&self.cx.sess.parse_sess) | |
5869c6ff | 716 | }; |
74b04a01 XL |
717 | let attr_item = attr.unwrap_normal_item(); |
718 | if let MacArgs::Eq(..) = attr_item.args { | |
60c5eb7d XL |
719 | self.cx.span_err(span, "key-value macro attributes are not supported"); |
720 | } | |
ba9703b0 XL |
721 | let inner_tokens = attr_item.args.inner_tokens(); |
722 | let tok_result = match expander.expand(self.cx, span, inner_tokens, tokens) { | |
723 | Err(_) => return ExpandResult::Ready(fragment_kind.dummy(span)), | |
724 | Ok(ts) => ts, | |
725 | }; | |
74b04a01 | 726 | self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span) |
416331ca XL |
727 | } |
728 | SyntaxExtensionKind::LegacyAttr(expander) => { | |
3dfed10e | 729 | match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) { |
416331ca | 730 | Ok(meta) => { |
ba9703b0 XL |
731 | let items = match expander.expand(self.cx, span, &meta, item) { |
732 | ExpandResult::Ready(items) => items, | |
fc512014 | 733 | ExpandResult::Retry(item) => { |
ba9703b0 | 734 | // Reassemble the original invocation for retrying. |
fc512014 | 735 | return ExpandResult::Retry(Invocation { |
6a06907d | 736 | kind: InvocationKind::Attr { attr, pos, item, derives }, |
fc512014 XL |
737 | ..invoc |
738 | }); | |
ba9703b0 XL |
739 | } |
740 | }; | |
cdc7bbd5 XL |
741 | if fragment_kind == AstFragmentKind::Expr && items.is_empty() { |
742 | let msg = | |
743 | "removing an expression is not supported in this position"; | |
744 | self.cx.span_err(span, msg); | |
745 | fragment_kind.dummy(span) | |
746 | } else { | |
747 | fragment_kind.expect_from_annotatables(items) | |
748 | } | |
416331ca XL |
749 | } |
750 | Err(mut err) => { | |
751 | err.emit(); | |
752 | fragment_kind.dummy(span) | |
753 | } | |
754 | } | |
755 | } | |
756 | SyntaxExtensionKind::NonMacroAttr { mark_used } => { | |
3dfed10e | 757 | self.cx.sess.mark_attr_known(&attr); |
416331ca | 758 | if *mark_used { |
3dfed10e | 759 | self.cx.sess.mark_attr_used(&attr); |
416331ca | 760 | } |
6a06907d | 761 | item.visit_attrs(|attrs| attrs.insert(pos, attr)); |
416331ca XL |
762 | fragment_kind.expect_from_annotatables(iter::once(item)) |
763 | } | |
dfeec247 XL |
764 | _ => unreachable!(), |
765 | }, | |
416331ca | 766 | InvocationKind::Derive { path, item } => match ext { |
dfeec247 XL |
767 | SyntaxExtensionKind::Derive(expander) |
768 | | SyntaxExtensionKind::LegacyDerive(expander) => { | |
e74abb32 XL |
769 | if let SyntaxExtensionKind::Derive(..) = ext { |
770 | self.gate_proc_macro_input(&item); | |
771 | } | |
772 | let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; | |
ba9703b0 XL |
773 | let items = match expander.expand(self.cx, span, &meta, item) { |
774 | ExpandResult::Ready(items) => items, | |
fc512014 | 775 | ExpandResult::Retry(item) => { |
ba9703b0 | 776 | // Reassemble the original invocation for retrying. |
fc512014 XL |
777 | return ExpandResult::Retry(Invocation { |
778 | kind: InvocationKind::Derive { path: meta.path, item }, | |
779 | ..invoc | |
780 | }); | |
ba9703b0 XL |
781 | } |
782 | }; | |
416331ca XL |
783 | fragment_kind.expect_from_annotatables(items) |
784 | } | |
dfeec247 XL |
785 | _ => unreachable!(), |
786 | }, | |
ba9703b0 | 787 | }) |
9e0c209e SL |
788 | } |
789 | ||
83c7162d | 790 | fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { |
e74abb32 | 791 | let kind = match item { |
dfeec247 XL |
792 | Annotatable::Item(_) |
793 | | Annotatable::TraitItem(_) | |
e74abb32 XL |
794 | | Annotatable::ImplItem(_) |
795 | | Annotatable::ForeignItem(_) => return, | |
fc512014 XL |
796 | Annotatable::Stmt(stmt) => { |
797 | // Attributes are stable on item statements, | |
798 | // but unstable on all other kinds of statements | |
799 | if stmt.is_item() { | |
800 | return; | |
801 | } | |
802 | "statements" | |
803 | } | |
e74abb32 | 804 | Annotatable::Expr(_) => "expressions", |
e1599b0c | 805 | Annotatable::Arm(..) |
6a06907d XL |
806 | | Annotatable::ExprField(..) |
807 | | Annotatable::PatField(..) | |
e1599b0c XL |
808 | | Annotatable::GenericParam(..) |
809 | | Annotatable::Param(..) | |
6a06907d | 810 | | Annotatable::FieldDef(..) |
dfeec247 | 811 | | Annotatable::Variant(..) => panic!("unexpected annotatable"), |
83c7162d | 812 | }; |
e74abb32 | 813 | if self.cx.ecfg.proc_macro_hygiene() { |
dfeec247 | 814 | return; |
e74abb32 | 815 | } |
60c5eb7d | 816 | feature_err( |
3dfed10e | 817 | &self.cx.sess.parse_sess, |
e74abb32 | 818 | sym::proc_macro_hygiene, |
83c7162d | 819 | span, |
83c7162d | 820 | &format!("custom attributes cannot be applied to {}", kind), |
60c5eb7d XL |
821 | ) |
822 | .emit(); | |
83c7162d XL |
823 | } |
824 | ||
e74abb32 XL |
825 | fn gate_proc_macro_input(&self, annotatable: &Annotatable) { |
826 | struct GateProcMacroInput<'a> { | |
94b46f34 XL |
827 | parse_sess: &'a ParseSess, |
828 | } | |
829 | ||
e74abb32 XL |
830 | impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { |
831 | fn visit_item(&mut self, item: &'ast ast::Item) { | |
832 | match &item.kind { | |
6a06907d XL |
833 | ast::ItemKind::Mod(_, mod_kind) |
834 | if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => | |
835 | { | |
60c5eb7d | 836 | feature_err( |
e74abb32 XL |
837 | self.parse_sess, |
838 | sym::proc_macro_hygiene, | |
839 | item.span, | |
e74abb32 | 840 | "non-inline modules in proc macro input are unstable", |
60c5eb7d XL |
841 | ) |
842 | .emit(); | |
e74abb32 XL |
843 | } |
844 | _ => {} | |
94b46f34 | 845 | } |
94b46f34 | 846 | |
e74abb32 | 847 | visit::walk_item(self, item); |
94b46f34 | 848 | } |
e74abb32 XL |
849 | } |
850 | ||
851 | if !self.cx.ecfg.proc_macro_hygiene() { | |
3dfed10e XL |
852 | annotatable |
853 | .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess }); | |
94b46f34 XL |
854 | } |
855 | } | |
856 | ||
416331ca XL |
857 | fn parse_ast_fragment( |
858 | &mut self, | |
859 | toks: TokenStream, | |
860 | kind: AstFragmentKind, | |
861 | path: &Path, | |
862 | span: Span, | |
863 | ) -> AstFragment { | |
e1599b0c | 864 | let mut parser = self.cx.new_parser_from_tts(toks); |
74b04a01 | 865 | match parse_ast_fragment(&mut parser, kind) { |
8faf50e0 | 866 | Ok(fragment) => { |
e74abb32 | 867 | ensure_complete_parse(&mut parser, path, kind.name(), span); |
416331ca | 868 | fragment |
ff7c6d11 | 869 | } |
9e0c209e | 870 | Err(mut err) => { |
5869c6ff XL |
871 | if err.span.is_dummy() { |
872 | err.set_span(span); | |
873 | } | |
416331ca | 874 | annotate_err_with_kind(&mut err, kind, span); |
9cc50fc6 | 875 | err.emit(); |
ea8adc8c | 876 | self.cx.trace_macros_diag(); |
ff7c6d11 | 877 | kind.dummy(span) |
1a4d82fc | 878 | } |
ff7c6d11 | 879 | } |
9e0c209e SL |
880 | } |
881 | } | |
970d7e83 | 882 | |
e74abb32 XL |
883 | pub fn parse_ast_fragment<'a>( |
884 | this: &mut Parser<'a>, | |
885 | kind: AstFragmentKind, | |
e74abb32 XL |
886 | ) -> PResult<'a, AstFragment> { |
887 | Ok(match kind { | |
888 | AstFragmentKind::Items => { | |
889 | let mut items = SmallVec::new(); | |
5869c6ff | 890 | while let Some(item) = this.parse_item(ForceCollect::No)? { |
e74abb32 | 891 | items.push(item); |
9e0c209e | 892 | } |
e74abb32 XL |
893 | AstFragment::Items(items) |
894 | } | |
895 | AstFragmentKind::TraitItems => { | |
896 | let mut items = SmallVec::new(); | |
cdc7bbd5 | 897 | while let Some(item) = this.parse_trait_item(ForceCollect::No)? { |
74b04a01 | 898 | items.extend(item); |
9e0c209e | 899 | } |
e74abb32 XL |
900 | AstFragment::TraitItems(items) |
901 | } | |
902 | AstFragmentKind::ImplItems => { | |
903 | let mut items = SmallVec::new(); | |
cdc7bbd5 | 904 | while let Some(item) = this.parse_impl_item(ForceCollect::No)? { |
74b04a01 | 905 | items.extend(item); |
9e0c209e | 906 | } |
e74abb32 XL |
907 | AstFragment::ImplItems(items) |
908 | } | |
909 | AstFragmentKind::ForeignItems => { | |
910 | let mut items = SmallVec::new(); | |
cdc7bbd5 | 911 | while let Some(item) = this.parse_foreign_item(ForceCollect::No)? { |
74b04a01 | 912 | items.extend(item); |
83c7162d | 913 | } |
e74abb32 XL |
914 | AstFragment::ForeignItems(items) |
915 | } | |
916 | AstFragmentKind::Stmts => { | |
917 | let mut stmts = SmallVec::new(); | |
74b04a01 XL |
918 | // Won't make progress on a `}`. |
919 | while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) { | |
29967ef6 | 920 | if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? { |
e74abb32 | 921 | stmts.push(stmt); |
9e0c209e | 922 | } |
223e47cc | 923 | } |
e74abb32 XL |
924 | AstFragment::Stmts(stmts) |
925 | } | |
926 | AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?), | |
927 | AstFragmentKind::OptExpr => { | |
928 | if this.token != token::Eof { | |
929 | AstFragment::OptExpr(Some(this.parse_expr()?)) | |
930 | } else { | |
931 | AstFragment::OptExpr(None) | |
932 | } | |
dfeec247 | 933 | } |
e74abb32 | 934 | AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?), |
136023e0 XL |
935 | AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_alt( |
936 | None, | |
937 | RecoverComma::No, | |
938 | RecoverColon::Yes, | |
939 | )?), | |
e74abb32 XL |
940 | AstFragmentKind::Arms |
941 | | AstFragmentKind::Fields | |
942 | | AstFragmentKind::FieldPats | |
943 | | AstFragmentKind::GenericParams | |
944 | | AstFragmentKind::Params | |
945 | | AstFragmentKind::StructFields | |
dfeec247 | 946 | | AstFragmentKind::Variants => panic!("unexpected AST fragment kind"), |
e74abb32 XL |
947 | }) |
948 | } | |
a1dfa0c6 | 949 | |
e74abb32 XL |
950 | pub fn ensure_complete_parse<'a>( |
951 | this: &mut Parser<'a>, | |
952 | macro_path: &Path, | |
953 | kind_name: &str, | |
954 | span: Span, | |
955 | ) { | |
956 | if this.token != token::Eof { | |
dfeec247 XL |
957 | let token = pprust::token_to_string(&this.token); |
958 | let msg = format!("macro expansion ignores token `{}` and any following", token); | |
e74abb32 XL |
959 | // Avoid emitting backtrace info twice. |
960 | let def_site_span = this.token.span.with_ctxt(SyntaxContext::root()); | |
961 | let mut err = this.struct_span_err(def_site_span, &msg); | |
962 | err.span_label(span, "caused by the macro expansion here"); | |
963 | let msg = format!( | |
964 | "the usage of `{}!` is likely invalid in {} context", | |
965 | pprust::path_to_string(macro_path), | |
966 | kind_name, | |
967 | ); | |
968 | err.note(&msg); | |
969 | let semi_span = this.sess.source_map().next_point(span); | |
970 | ||
971 | let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span)); | |
972 | match this.sess.source_map().span_to_snippet(semi_full_span) { | |
973 | Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => { | |
974 | err.span_suggestion( | |
975 | semi_span, | |
976 | "you might be missing a semicolon here", | |
977 | ";".to_owned(), | |
978 | Applicability::MaybeIncorrect, | |
979 | ); | |
a1dfa0c6 | 980 | } |
e74abb32 | 981 | _ => {} |
1a4d82fc | 982 | } |
e74abb32 | 983 | err.emit(); |
1a4d82fc | 984 | } |
1a4d82fc JJ |
985 | } |
986 | ||
dc9dc135 | 987 | struct InvocationCollector<'a, 'b> { |
9e0c209e SL |
988 | cx: &'a mut ExtCtxt<'b>, |
989 | cfg: StripUnconfigured<'a>, | |
6a06907d | 990 | invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>, |
9e0c209e SL |
991 | monotonic: bool, |
992 | } | |
223e47cc | 993 | |
9e0c209e | 994 | impl<'a, 'b> InvocationCollector<'a, 'b> { |
8faf50e0 | 995 | fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { |
136023e0 | 996 | let expn_id = LocalExpnId::fresh_empty(); |
e74abb32 | 997 | let vis = kind.placeholder_visibility(); |
ba9703b0 XL |
998 | self.invocations.push(( |
999 | Invocation { | |
1000 | kind, | |
1001 | fragment_kind, | |
1002 | expansion_data: ExpansionData { | |
1003 | id: expn_id, | |
1004 | depth: self.cx.current_expansion.depth + 1, | |
1005 | ..self.cx.current_expansion.clone() | |
1006 | }, | |
c30ab7b3 | 1007 | }, |
ba9703b0 XL |
1008 | None, |
1009 | )); | |
e74abb32 | 1010 | placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) |
1a4d82fc | 1011 | } |
223e47cc | 1012 | |
ba9703b0 XL |
1013 | fn collect_bang( |
1014 | &mut self, | |
1015 | mac: ast::MacCall, | |
1016 | span: Span, | |
1017 | kind: AstFragmentKind, | |
1018 | ) -> AstFragment { | |
416331ca | 1019 | self.collect(kind, InvocationKind::Bang { mac, span }) |
9e0c209e | 1020 | } |
85aaf69f | 1021 | |
dfeec247 XL |
1022 | fn collect_attr( |
1023 | &mut self, | |
6a06907d | 1024 | (attr, pos, derives): (ast::Attribute, usize, Vec<Path>), |
dfeec247 XL |
1025 | item: Annotatable, |
1026 | kind: AstFragmentKind, | |
dfeec247 | 1027 | ) -> AstFragment { |
6a06907d | 1028 | self.collect(kind, InvocationKind::Attr { attr, pos, item, derives }) |
b7449926 XL |
1029 | } |
1030 | ||
6a06907d XL |
1031 | /// If `item` is an attribute invocation, remove the attribute and return it together with |
1032 | /// its position and derives following it. We have to collect the derives in order to resolve | |
1033 | /// legacy derive helpers (helpers written before derives that introduce them). | |
fc512014 | 1034 | fn take_first_attr( |
dfeec247 | 1035 | &mut self, |
6a06907d XL |
1036 | item: &mut impl AstLike, |
1037 | ) -> Option<(ast::Attribute, usize, Vec<Path>)> { | |
1038 | let mut attr = None; | |
1039 | ||
1040 | item.visit_attrs(|attrs| { | |
1041 | attr = attrs | |
1042 | .iter() | |
1043 | .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)) | |
1044 | .map(|attr_pos| { | |
1045 | let attr = attrs.remove(attr_pos); | |
1046 | let following_derives = attrs[attr_pos..] | |
1047 | .iter() | |
1048 | .filter(|a| a.has_name(sym::derive)) | |
1049 | .flat_map(|a| a.meta_item_list().unwrap_or_default()) | |
1050 | .filter_map(|nested_meta| match nested_meta { | |
1051 | NestedMetaItem::MetaItem(ast::MetaItem { | |
1052 | kind: MetaItemKind::Word, | |
1053 | path, | |
1054 | .. | |
1055 | }) => Some(path), | |
1056 | _ => None, | |
1057 | }) | |
1058 | .collect(); | |
1059 | ||
1060 | (attr, attr_pos, following_derives) | |
1061 | }) | |
0531ce1d XL |
1062 | }); |
1063 | ||
6a06907d | 1064 | attr |
0531ce1d XL |
1065 | } |
1066 | ||
6a06907d | 1067 | fn configure<T: AstLike>(&mut self, node: T) -> Option<T> { |
9e0c209e | 1068 | self.cfg.configure(node) |
d9579d0f | 1069 | } |
32a655c1 SL |
1070 | |
1071 | // Detect use of feature-gated or invalid attributes on macro invocations | |
1072 | // since they will not be detected after macro expansion. | |
1073 | fn check_attributes(&mut self, attrs: &[ast::Attribute]) { | |
32a655c1 | 1074 | let features = self.cx.ecfg.features.unwrap(); |
cdc7bbd5 XL |
1075 | let mut attrs = attrs.iter().peekable(); |
1076 | let mut span: Option<Span> = None; | |
1077 | while let Some(attr) = attrs.next() { | |
3dfed10e XL |
1078 | rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); |
1079 | validate_attr::check_meta(&self.cx.sess.parse_sess, attr); | |
cdc7bbd5 XL |
1080 | |
1081 | let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; | |
1082 | span = Some(current_span); | |
1083 | ||
1084 | if attrs.peek().map_or(false, |next_attr| next_attr.doc_str().is_some()) { | |
1085 | continue; | |
1086 | } | |
1087 | ||
74b04a01 | 1088 | if attr.doc_str().is_some() { |
3dfed10e | 1089 | self.cx.sess.parse_sess.buffer_lint_with_diagnostic( |
74b04a01 | 1090 | &UNUSED_DOC_COMMENTS, |
cdc7bbd5 | 1091 | current_span, |
74b04a01 XL |
1092 | ast::CRATE_NODE_ID, |
1093 | "unused doc comment", | |
1094 | BuiltinLintDiagnostics::UnusedDocComment(attr.span), | |
1095 | ); | |
1096 | } | |
32a655c1 SL |
1097 | } |
1098 | } | |
85aaf69f SL |
1099 | } |
1100 | ||
136023e0 XL |
1101 | /// Wraps a call to `noop_visit_*` / `noop_flat_map_*` |
1102 | /// for an AST node that supports attributes | |
1103 | /// (see the `Annotatable` enum) | |
1104 | /// This method assigns a `NodeId`, and sets that `NodeId` | |
1105 | /// as our current 'lint node id'. If a macro call is found | |
1106 | /// inside this AST node, we will use this AST node's `NodeId` | |
1107 | /// to emit lints associated with that macro (allowing | |
1108 | /// `#[allow]` / `#[deny]` to be applied close to | |
1109 | /// the macro invocation). | |
1110 | /// | |
1111 | /// Do *not* call this for a macro AST node | |
1112 | /// (e.g. `ExprKind::MacCall`) - we cannot emit lints | |
1113 | /// at these AST nodes, since they are removed and | |
1114 | /// replaced with the result of macro expansion. | |
1115 | /// | |
1116 | /// All other `NodeId`s are assigned by `visit_id`. | |
1117 | /// * `self` is the 'self' parameter for the current method, | |
1118 | /// * `id` is a mutable reference to the `NodeId` field | |
1119 | /// of the current AST node. | |
1120 | /// * `closure` is a closure that executes the | |
1121 | /// `noop_visit_*` / `noop_flat_map_*` method | |
1122 | /// for the current AST node. | |
1123 | macro_rules! assign_id { | |
1124 | ($self:ident, $id:expr, $closure:expr) => {{ | |
1125 | let old_id = $self.cx.current_expansion.lint_node_id; | |
1126 | if $self.monotonic { | |
1127 | debug_assert_eq!(*$id, ast::DUMMY_NODE_ID); | |
1128 | let new_id = $self.cx.resolver.next_node_id(); | |
1129 | *$id = new_id; | |
1130 | $self.cx.current_expansion.lint_node_id = new_id; | |
1131 | } | |
1132 | let ret = ($closure)(); | |
1133 | $self.cx.current_expansion.lint_node_id = old_id; | |
1134 | ret | |
1135 | }}; | |
1136 | } | |
1137 | ||
9fa01778 XL |
1138 | impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { |
1139 | fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { | |
1140 | self.cfg.configure_expr(expr); | |
1141 | visit_clobber(expr.deref_mut(), |mut expr| { | |
6a06907d | 1142 | if let Some(attr) = self.take_first_attr(&mut expr) { |
a1dfa0c6 XL |
1143 | // Collect the invoc regardless of whether or not attributes are permitted here |
1144 | // expansion will eat the attribute so it won't error later. | |
6a06907d | 1145 | self.cfg.maybe_emit_expr_attr_err(&attr.0); |
a1dfa0c6 XL |
1146 | |
1147 | // AstFragmentKind::Expr requires the macro to emit an expression. | |
dfeec247 | 1148 | return self |
fc512014 | 1149 | .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr) |
a1dfa0c6 | 1150 | .make_expr() |
dfeec247 | 1151 | .into_inner(); |
a1dfa0c6 | 1152 | } |
0531ce1d | 1153 | |
ba9703b0 | 1154 | if let ast::ExprKind::MacCall(mac) = expr.kind { |
a1dfa0c6 | 1155 | self.check_attributes(&expr.attrs); |
dfeec247 | 1156 | self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() |
a1dfa0c6 | 1157 | } else { |
136023e0 XL |
1158 | assign_id!(self, &mut expr.id, || { |
1159 | ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); | |
1160 | }); | |
9fa01778 | 1161 | expr |
a1dfa0c6 | 1162 | } |
9fa01778 | 1163 | }); |
c34b1796 | 1164 | } |
223e47cc | 1165 | |
136023e0 XL |
1166 | // This is needed in order to set `lint_node_id` for `let` statements |
1167 | fn visit_local(&mut self, local: &mut P<Local>) { | |
1168 | assign_id!(self, &mut local.id, || noop_visit_local(local, self)); | |
1169 | } | |
1170 | ||
e1599b0c XL |
1171 | fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { |
1172 | let mut arm = configure!(self, arm); | |
1173 | ||
fc512014 | 1174 | if let Some(attr) = self.take_first_attr(&mut arm) { |
dfeec247 | 1175 | return self |
fc512014 | 1176 | .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms) |
dfeec247 | 1177 | .make_arms(); |
e1599b0c XL |
1178 | } |
1179 | ||
136023e0 | 1180 | assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self)) |
e1599b0c XL |
1181 | } |
1182 | ||
6a06907d | 1183 | fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { |
e1599b0c XL |
1184 | let mut field = configure!(self, field); |
1185 | ||
fc512014 | 1186 | if let Some(attr) = self.take_first_attr(&mut field) { |
dfeec247 | 1187 | return self |
6a06907d XL |
1188 | .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields) |
1189 | .make_expr_fields(); | |
e1599b0c XL |
1190 | } |
1191 | ||
136023e0 | 1192 | assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self)) |
e1599b0c XL |
1193 | } |
1194 | ||
6a06907d | 1195 | fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { |
e1599b0c XL |
1196 | let mut fp = configure!(self, fp); |
1197 | ||
fc512014 | 1198 | if let Some(attr) = self.take_first_attr(&mut fp) { |
dfeec247 | 1199 | return self |
6a06907d XL |
1200 | .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats) |
1201 | .make_pat_fields(); | |
e1599b0c XL |
1202 | } |
1203 | ||
136023e0 | 1204 | assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self)) |
e1599b0c XL |
1205 | } |
1206 | ||
1207 | fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { | |
1208 | let mut p = configure!(self, p); | |
1209 | ||
fc512014 | 1210 | if let Some(attr) = self.take_first_attr(&mut p) { |
dfeec247 | 1211 | return self |
fc512014 | 1212 | .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params) |
dfeec247 | 1213 | .make_params(); |
e1599b0c XL |
1214 | } |
1215 | ||
136023e0 | 1216 | assign_id!(self, &mut p.id, || noop_flat_map_param(p, self)) |
e1599b0c XL |
1217 | } |
1218 | ||
6a06907d | 1219 | fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { |
e1599b0c XL |
1220 | let mut sf = configure!(self, sf); |
1221 | ||
fc512014 | 1222 | if let Some(attr) = self.take_first_attr(&mut sf) { |
dfeec247 | 1223 | return self |
6a06907d XL |
1224 | .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields) |
1225 | .make_field_defs(); | |
e1599b0c XL |
1226 | } |
1227 | ||
136023e0 | 1228 | assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self)) |
e1599b0c XL |
1229 | } |
1230 | ||
1231 | fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { | |
1232 | let mut variant = configure!(self, variant); | |
1233 | ||
fc512014 | 1234 | if let Some(attr) = self.take_first_attr(&mut variant) { |
dfeec247 | 1235 | return self |
fc512014 | 1236 | .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants) |
dfeec247 | 1237 | .make_variants(); |
e1599b0c XL |
1238 | } |
1239 | ||
136023e0 | 1240 | assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self)) |
e1599b0c XL |
1241 | } |
1242 | ||
9fa01778 | 1243 | fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { |
a1dfa0c6 XL |
1244 | let expr = configure!(self, expr); |
1245 | expr.filter_map(|mut expr| { | |
6a06907d XL |
1246 | if let Some(attr) = self.take_first_attr(&mut expr) { |
1247 | self.cfg.maybe_emit_expr_attr_err(&attr.0); | |
0531ce1d | 1248 | |
dfeec247 | 1249 | return self |
fc512014 | 1250 | .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) |
a1dfa0c6 | 1251 | .make_opt_expr() |
dfeec247 | 1252 | .map(|expr| expr.into_inner()); |
a1dfa0c6 | 1253 | } |
0531ce1d | 1254 | |
ba9703b0 | 1255 | if let ast::ExprKind::MacCall(mac) = expr.kind { |
a1dfa0c6 XL |
1256 | self.check_attributes(&expr.attrs); |
1257 | self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) | |
1258 | .make_opt_expr() | |
1259 | .map(|expr| expr.into_inner()) | |
1260 | } else { | |
136023e0 XL |
1261 | assign_id!(self, &mut expr.id, || { |
1262 | Some({ | |
1263 | noop_visit_expr(&mut expr, self); | |
1264 | expr | |
1265 | }) | |
dfeec247 | 1266 | }) |
a1dfa0c6 XL |
1267 | } |
1268 | }) | |
3157f602 | 1269 | } |
3157f602 | 1270 | |
9fa01778 | 1271 | fn visit_pat(&mut self, pat: &mut P<ast::Pat>) { |
e74abb32 | 1272 | match pat.kind { |
ba9703b0 | 1273 | PatKind::MacCall(_) => {} |
9fa01778 | 1274 | _ => return noop_visit_pat(pat, self), |
e9174d1e | 1275 | } |
e9174d1e | 1276 | |
dfeec247 | 1277 | visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { |
ba9703b0 XL |
1278 | PatKind::MacCall(mac) => { |
1279 | self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() | |
1280 | } | |
dfeec247 | 1281 | _ => unreachable!(), |
9fa01778 | 1282 | }); |
9e0c209e | 1283 | } |
e9174d1e | 1284 | |
9fa01778 XL |
1285 | fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { |
1286 | let mut stmt = configure!(self, stmt); | |
1a4d82fc | 1287 | |
0531ce1d XL |
1288 | // we'll expand attributes on expressions separately |
1289 | if !stmt.is_expr() { | |
6a06907d | 1290 | if let Some(attr) = self.take_first_attr(&mut stmt) { |
dfeec247 | 1291 | return self |
fc512014 | 1292 | .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts) |
dfeec247 | 1293 | .make_stmts(); |
0531ce1d | 1294 | } |
0531ce1d | 1295 | } |
9e0c209e | 1296 | |
ba9703b0 | 1297 | if let StmtKind::MacCall(mac) = stmt.kind { |
fc512014 | 1298 | let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner(); |
0531ce1d | 1299 | self.check_attributes(&attrs); |
dfeec247 XL |
1300 | let mut placeholder = |
1301 | self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); | |
0531ce1d XL |
1302 | |
1303 | // If this is a macro invocation with a semicolon, then apply that | |
1304 | // semicolon to the final statement produced by expansion. | |
1305 | if style == MacStmtStyle::Semicolon { | |
1306 | if let Some(stmt) = placeholder.pop() { | |
1307 | placeholder.push(stmt.add_trailing_semicolon()); | |
1308 | } | |
9e0c209e | 1309 | } |
0531ce1d XL |
1310 | |
1311 | return placeholder; | |
5bcae85e | 1312 | } |
9e0c209e | 1313 | |
0531ce1d | 1314 | // The placeholder expander gives ids to statements, so we avoid folding the id here. |
136023e0 XL |
1315 | // We don't use `assign_id!` - it will be called when we visit statement's contents |
1316 | // (e.g. an expression, item, or local) | |
fc512014 | 1317 | let ast::Stmt { id, kind, span } = stmt; |
dfeec247 XL |
1318 | noop_flat_map_stmt_kind(kind, self) |
1319 | .into_iter() | |
fc512014 | 1320 | .map(|kind| ast::Stmt { id, kind, span }) |
dfeec247 | 1321 | .collect() |
1a4d82fc | 1322 | } |
3157f602 | 1323 | |
9fa01778 | 1324 | fn visit_block(&mut self, block: &mut P<Block>) { |
6a06907d XL |
1325 | let orig_dir_ownership = mem::replace( |
1326 | &mut self.cx.current_expansion.dir_ownership, | |
1327 | DirOwnership::UnownedViaBlock, | |
1328 | ); | |
9fa01778 | 1329 | noop_visit_block(block, self); |
6a06907d | 1330 | self.cx.current_expansion.dir_ownership = orig_dir_ownership; |
3157f602 XL |
1331 | } |
1332 | ||
9fa01778 XL |
1333 | fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { |
1334 | let mut item = configure!(self, item); | |
9e0c209e | 1335 | |
fc512014 | 1336 | if let Some(attr) = self.take_first_attr(&mut item) { |
dfeec247 | 1337 | return self |
fc512014 | 1338 | .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items) |
dfeec247 | 1339 | .make_items(); |
3157f602 XL |
1340 | } |
1341 | ||
ba9703b0 XL |
1342 | let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. |
1343 | let ident = item.ident; | |
1344 | let span = item.span; | |
1345 | ||
e74abb32 | 1346 | match item.kind { |
ba9703b0 XL |
1347 | ast::ItemKind::MacCall(..) => { |
1348 | item.attrs = attrs; | |
32a655c1 | 1349 | self.check_attributes(&item.attrs); |
e74abb32 | 1350 | item.and_then(|item| match item.kind { |
29967ef6 XL |
1351 | ItemKind::MacCall(mac) => { |
1352 | self.collect_bang(mac, span, AstFragmentKind::Items).make_items() | |
1353 | } | |
9e0c209e SL |
1354 | _ => unreachable!(), |
1355 | }) | |
3157f602 | 1356 | } |
6a06907d XL |
1357 | ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => { |
1358 | let (file_path, dir_path, dir_ownership) = match mod_kind { | |
1359 | ModKind::Loaded(_, inline, _) => { | |
1360 | // Inline `mod foo { ... }`, but we still need to push directories. | |
1361 | let (dir_path, dir_ownership) = mod_dir_path( | |
1362 | &self.cx.sess, | |
1363 | ident, | |
1364 | &attrs, | |
1365 | &self.cx.current_expansion.module, | |
1366 | self.cx.current_expansion.dir_ownership, | |
1367 | *inline, | |
1368 | ); | |
1369 | item.attrs = attrs; | |
1370 | (None, dir_path, dir_ownership) | |
ba9703b0 | 1371 | } |
6a06907d XL |
1372 | ModKind::Unloaded => { |
1373 | // We have an outline `mod foo;` so we need to parse the file. | |
1374 | let old_attrs_len = attrs.len(); | |
1375 | let ParsedExternalMod { | |
1376 | mut items, | |
1377 | inner_span, | |
1378 | file_path, | |
1379 | dir_path, | |
1380 | dir_ownership, | |
1381 | } = parse_external_mod( | |
1382 | &self.cx.sess, | |
1383 | ident, | |
1384 | span, | |
1385 | &self.cx.current_expansion.module, | |
1386 | self.cx.current_expansion.dir_ownership, | |
1387 | &mut attrs, | |
1388 | ); | |
1389 | ||
1390 | if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { | |
1391 | (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); | |
1392 | } | |
ba9703b0 | 1393 | |
6a06907d XL |
1394 | *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); |
1395 | item.attrs = attrs; | |
1396 | if item.attrs.len() > old_attrs_len { | |
1397 | // If we loaded an out-of-line module and added some inner attributes, | |
1398 | // then we need to re-configure it and re-collect attributes for | |
1399 | // resolution and expansion. | |
1400 | item = configure!(self, item); | |
1401 | ||
1402 | if let Some(attr) = self.take_first_attr(&mut item) { | |
1403 | return self | |
1404 | .collect_attr( | |
1405 | attr, | |
1406 | Annotatable::Item(item), | |
1407 | AstFragmentKind::Items, | |
1408 | ) | |
1409 | .make_items(); | |
ba9703b0 | 1410 | } |
ba9703b0 | 1411 | } |
6a06907d XL |
1412 | (Some(file_path), dir_path, dir_ownership) |
1413 | } | |
ba9703b0 | 1414 | }; |
3157f602 | 1415 | |
ba9703b0 | 1416 | // Set the module info before we flat map. |
6a06907d | 1417 | let mut module = self.cx.current_expansion.module.with_dir_path(dir_path); |
ba9703b0 | 1418 | module.mod_path.push(ident); |
6a06907d XL |
1419 | if let Some(file_path) = file_path { |
1420 | module.file_path_stack.push(file_path); | |
1421 | } | |
1422 | ||
9e0c209e SL |
1423 | let orig_module = |
1424 | mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); | |
6a06907d XL |
1425 | let orig_dir_ownership = |
1426 | mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); | |
ba9703b0 | 1427 | |
136023e0 | 1428 | let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)); |
ba9703b0 XL |
1429 | |
1430 | // Restore the module info. | |
6a06907d | 1431 | self.cx.current_expansion.dir_ownership = orig_dir_ownership; |
9e0c209e | 1432 | self.cx.current_expansion.module = orig_module; |
6a06907d | 1433 | |
7cac9316 | 1434 | result |
9e0c209e | 1435 | } |
ba9703b0 XL |
1436 | _ => { |
1437 | item.attrs = attrs; | |
136023e0 XL |
1438 | // The crate root is special - don't assign an ID to it. |
1439 | if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) { | |
1440 | assign_id!(self, &mut item.id, || noop_flat_map_item(item, self)) | |
1441 | } else { | |
1442 | noop_flat_map_item(item, self) | |
1443 | } | |
ba9703b0 | 1444 | } |
9e0c209e | 1445 | } |
1a4d82fc JJ |
1446 | } |
1447 | ||
74b04a01 | 1448 | fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { |
9fa01778 | 1449 | let mut item = configure!(self, item); |
1a4d82fc | 1450 | |
fc512014 | 1451 | if let Some(attr) = self.take_first_attr(&mut item) { |
dfeec247 | 1452 | return self |
fc512014 | 1453 | .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems) |
dfeec247 | 1454 | .make_trait_items(); |
9e0c209e SL |
1455 | } |
1456 | ||
e74abb32 | 1457 | match item.kind { |
ba9703b0 | 1458 | ast::AssocItemKind::MacCall(..) => { |
74b04a01 XL |
1459 | self.check_attributes(&item.attrs); |
1460 | item.and_then(|item| match item.kind { | |
ba9703b0 | 1461 | ast::AssocItemKind::MacCall(mac) => self |
74b04a01 XL |
1462 | .collect_bang(mac, item.span, AstFragmentKind::TraitItems) |
1463 | .make_trait_items(), | |
1464 | _ => unreachable!(), | |
1465 | }) | |
54a0048b | 1466 | } |
136023e0 XL |
1467 | _ => { |
1468 | assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) | |
1469 | } | |
54a0048b | 1470 | } |
1a4d82fc JJ |
1471 | } |
1472 | ||
74b04a01 | 1473 | fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { |
9fa01778 | 1474 | let mut item = configure!(self, item); |
1a4d82fc | 1475 | |
fc512014 | 1476 | if let Some(attr) = self.take_first_attr(&mut item) { |
dfeec247 | 1477 | return self |
fc512014 | 1478 | .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems) |
dfeec247 | 1479 | .make_impl_items(); |
9e0c209e | 1480 | } |
1a4d82fc | 1481 | |
e74abb32 | 1482 | match item.kind { |
ba9703b0 | 1483 | ast::AssocItemKind::MacCall(..) => { |
74b04a01 XL |
1484 | self.check_attributes(&item.attrs); |
1485 | item.and_then(|item| match item.kind { | |
ba9703b0 | 1486 | ast::AssocItemKind::MacCall(mac) => self |
74b04a01 XL |
1487 | .collect_bang(mac, item.span, AstFragmentKind::ImplItems) |
1488 | .make_impl_items(), | |
1489 | _ => unreachable!(), | |
1490 | }) | |
9e0c209e | 1491 | } |
136023e0 XL |
1492 | _ => { |
1493 | assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self)) | |
1494 | } | |
9e0c209e | 1495 | } |
85aaf69f SL |
1496 | } |
1497 | ||
9fa01778 | 1498 | fn visit_ty(&mut self, ty: &mut P<ast::Ty>) { |
e74abb32 | 1499 | match ty.kind { |
ba9703b0 | 1500 | ast::TyKind::MacCall(_) => {} |
9fa01778 | 1501 | _ => return noop_visit_ty(ty, self), |
9e0c209e SL |
1502 | }; |
1503 | ||
dfeec247 | 1504 | visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { |
ba9703b0 XL |
1505 | ast::TyKind::MacCall(mac) => { |
1506 | self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() | |
1507 | } | |
dfeec247 | 1508 | _ => unreachable!(), |
9fa01778 | 1509 | }); |
1a4d82fc JJ |
1510 | } |
1511 | ||
dfeec247 XL |
1512 | fn flat_map_foreign_item( |
1513 | &mut self, | |
6a06907d | 1514 | foreign_item: P<ast::ForeignItem>, |
74b04a01 | 1515 | ) -> SmallVec<[P<ast::ForeignItem>; 1]> { |
6a06907d XL |
1516 | let mut foreign_item = configure!(self, foreign_item); |
1517 | ||
fc512014 | 1518 | if let Some(attr) = self.take_first_attr(&mut foreign_item) { |
dfeec247 XL |
1519 | return self |
1520 | .collect_attr( | |
1521 | attr, | |
74b04a01 | 1522 | Annotatable::ForeignItem(foreign_item), |
dfeec247 | 1523 | AstFragmentKind::ForeignItems, |
dfeec247 XL |
1524 | ) |
1525 | .make_foreign_items(); | |
83c7162d XL |
1526 | } |
1527 | ||
74b04a01 | 1528 | match foreign_item.kind { |
ba9703b0 | 1529 | ast::ForeignItemKind::MacCall(..) => { |
74b04a01 XL |
1530 | self.check_attributes(&foreign_item.attrs); |
1531 | foreign_item.and_then(|item| match item.kind { | |
ba9703b0 | 1532 | ast::ForeignItemKind::MacCall(mac) => self |
74b04a01 XL |
1533 | .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) |
1534 | .make_foreign_items(), | |
1535 | _ => unreachable!(), | |
1536 | }) | |
1537 | } | |
136023e0 XL |
1538 | _ => { |
1539 | assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item( | |
1540 | foreign_item, | |
1541 | self | |
1542 | )) | |
1543 | } | |
83c7162d | 1544 | } |
83c7162d XL |
1545 | } |
1546 | ||
e1599b0c XL |
1547 | fn flat_map_generic_param( |
1548 | &mut self, | |
dfeec247 XL |
1549 | param: ast::GenericParam, |
1550 | ) -> SmallVec<[ast::GenericParam; 1]> { | |
e1599b0c XL |
1551 | let mut param = configure!(self, param); |
1552 | ||
fc512014 | 1553 | if let Some(attr) = self.take_first_attr(&mut param) { |
dfeec247 XL |
1554 | return self |
1555 | .collect_attr( | |
1556 | attr, | |
dfeec247 XL |
1557 | Annotatable::GenericParam(param), |
1558 | AstFragmentKind::GenericParams, | |
dfeec247 XL |
1559 | ) |
1560 | .make_generic_params(); | |
e1599b0c XL |
1561 | } |
1562 | ||
136023e0 | 1563 | assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self)) |
83c7162d XL |
1564 | } |
1565 | ||
9fa01778 | 1566 | fn visit_id(&mut self, id: &mut ast::NodeId) { |
136023e0 XL |
1567 | // We may have already assigned a `NodeId` |
1568 | // by calling `assign_id` | |
1569 | if self.monotonic && *id == ast::DUMMY_NODE_ID { | |
1570 | *id = self.cx.resolver.next_node_id(); | |
9e0c209e | 1571 | } |
54a0048b SL |
1572 | } |
1573 | } | |
1574 | ||
85aaf69f | 1575 | pub struct ExpansionConfig<'feat> { |
1a4d82fc | 1576 | pub crate_name: String, |
85aaf69f | 1577 | pub features: Option<&'feat Features>, |
f9f354fc | 1578 | pub recursion_limit: Limit, |
d9579d0f | 1579 | pub trace_mac: bool, |
6a06907d XL |
1580 | pub should_test: bool, // If false, strip `#[test]` nodes |
1581 | pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span` | |
1b1a35ee | 1582 | pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics |
1a4d82fc JJ |
1583 | } |
1584 | ||
85aaf69f SL |
1585 | impl<'feat> ExpansionConfig<'feat> { |
1586 | pub fn default(crate_name: String) -> ExpansionConfig<'static> { | |
1a4d82fc | 1587 | ExpansionConfig { |
3b2f2976 | 1588 | crate_name, |
85aaf69f | 1589 | features: None, |
f9f354fc | 1590 | recursion_limit: Limit::new(1024), |
d9579d0f | 1591 | trace_mac: false, |
3157f602 | 1592 | should_test: false, |
f035d41b | 1593 | span_debug: false, |
1b1a35ee | 1594 | proc_macro_backtrace: false, |
1a4d82fc | 1595 | } |
970d7e83 | 1596 | } |
85aaf69f | 1597 | |
416331ca XL |
1598 | fn proc_macro_hygiene(&self) -> bool { |
1599 | self.features.map_or(false, |features| features.proc_macro_hygiene) | |
1600 | } | |
970d7e83 | 1601 | } |