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