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