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