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