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