2 use crate::config
::StripUnconfigured
;
3 use crate::hygiene
::{ExpnData, ExpnId, ExpnKind, SyntaxContext}
;
4 use crate::mbe
::macro_rules
::annotate_err_with_kind
;
5 use crate::placeholders
::{placeholder, PlaceholderExpander}
;
6 use crate::proc_macro
::collect_derives
;
8 use rustc_ast
::ast
::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}
;
9 use rustc_ast
::ast
::{ItemKind, MacArgs, MacStmtStyle, StmtKind}
;
10 use rustc_ast
::mut_visit
::*;
11 use rustc_ast
::ptr
::P
;
13 use rustc_ast
::tokenstream
::TokenStream
;
14 use rustc_ast
::util
::map_in_place
::MapInPlace
;
15 use rustc_ast
::visit
::{self, AssocCtxt, Visitor}
;
16 use rustc_ast_pretty
::pprust
;
17 use rustc_attr
::{self as attr, is_builtin_attr, HasAttrs}
;
18 use rustc_errors
::{Applicability, FatalError, PResult}
;
19 use rustc_feature
::Features
;
20 use rustc_parse
::configure
;
21 use rustc_parse
::parser
::Parser
;
22 use rustc_parse
::validate_attr
;
23 use rustc_parse
::DirectoryOwnership
;
24 use rustc_session
::lint
::builtin
::UNUSED_DOC_COMMENTS
;
25 use rustc_session
::lint
::BuiltinLintDiagnostics
;
26 use rustc_session
::parse
::{feature_err, ParseSess}
;
27 use rustc_span
::source_map
::respan
;
28 use rustc_span
::symbol
::{sym, Symbol}
;
29 use rustc_span
::{FileName, Span, DUMMY_SP}
;
31 use smallvec
::{smallvec, SmallVec}
;
32 use std
::io
::ErrorKind
;
33 use std
::ops
::DerefMut
;
34 use std
::path
::PathBuf
;
36 use std
::{iter, mem, slice}
;
38 macro_rules
! ast_fragments
{
40 $
($Kind
:ident($AstTy
:ty
) {
42 $
(one
fn $mut_visit_ast
:ident
; fn $visit_ast
:ident
;)?
43 $
(many
fn $flat_map_ast_elt
:ident
; fn $visit_ast_elt
:ident($
($args
:tt
)*);)?
47 /// A fragment of AST that can be produced by a single macro expansion.
48 /// Can also serve as an input and intermediate result for macro expansion operations.
49 pub enum AstFragment
{
50 OptExpr(Option
<P
<ast
::Expr
>>),
54 /// "Discriminant" of an AST fragment.
55 #[derive(Copy, Clone, PartialEq, Eq)]
56 pub enum AstFragmentKind
{
61 impl AstFragmentKind
{
62 pub fn name(self) -> &'
static str {
64 AstFragmentKind
::OptExpr
=> "expression",
65 $
(AstFragmentKind
::$Kind
=> $kind_name
,)*
69 fn make_from
<'a
>(self, result
: Box
<dyn MacResult
+ 'a
>) -> Option
<AstFragment
> {
71 AstFragmentKind
::OptExpr
=>
72 result
.make_expr().map(Some
).map(AstFragment
::OptExpr
),
73 $
(AstFragmentKind
::$Kind
=> result
.$
make_ast().map(AstFragment
::$Kind
),)*
79 pub fn add_placeholders(&mut self, placeholders
: &[NodeId
]) {
80 if placeholders
.is_empty() {
84 $
($
(AstFragment
::$
Kind(ast
) => ast
.extend(placeholders
.iter().flat_map(|id
| {
85 // We are repeating through arguments with `many`, to do that we have to
86 // mention some macro variable from those arguments even if it's not used.
87 macro _repeating($flat_map_ast_elt
) {}
88 placeholder(AstFragmentKind
::$Kind
, *id
, None
).$
make_ast()
90 _
=> panic
!("unexpected AST fragment kind")
94 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
96 AstFragment
::OptExpr(expr
) => expr
,
97 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
101 $
(pub fn $
make_ast(self) -> $AstTy
{
103 AstFragment
::$
Kind(ast
) => ast
,
104 _
=> panic
!("AstFragment::make_* called on the wrong kind of fragment"),
108 pub fn mut_visit_with
<F
: MutVisitor
>(&mut self, vis
: &mut F
) {
110 AstFragment
::OptExpr(opt_expr
) => {
111 visit_clobber(opt_expr
, |opt_expr
| {
112 if let Some(expr
) = opt_expr
{
113 vis
.filter_map_expr(expr
)
119 $
($
(AstFragment
::$
Kind(ast
) => vis
.$
mut_visit_ast(ast
),)?
)*
120 $
($
(AstFragment
::$
Kind(ast
) =>
121 ast
.flat_map_in_place(|ast
| vis
.$
flat_map_ast_elt(ast
)),)?
)*
125 pub fn visit_with
<'a
, V
: Visitor
<'a
>>(&'a
self, visitor
: &mut V
) {
127 AstFragment
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
128 AstFragment
::OptExpr(None
) => {}
129 $
($
(AstFragment
::$
Kind(ref ast
) => visitor
.$
visit_ast(ast
),)?
)*
130 $
($
(AstFragment
::$
Kind(ref ast
) => for ast_elt
in &ast
[..] {
131 visitor
.$
visit_ast_elt(ast_elt
, $
($args
)*);
137 impl<'a
> MacResult
for crate::mbe
::macro_rules
::ParserAnyMacro
<'a
> {
138 $
(fn $
make_ast(self: Box
<crate::mbe
::macro_rules
::ParserAnyMacro
<'a
>>)
140 Some(self.make(AstFragmentKind
::$Kind
).$
make_ast())
147 Expr(P
<ast
::Expr
>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
148 Pat(P
<ast
::Pat
>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
149 Ty(P
<ast
::Ty
>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
150 Stmts(SmallVec
<[ast
::Stmt
; 1]>) {
151 "statement"; many
fn flat_map_stmt
; fn visit_stmt(); fn make_stmts
;
153 Items(SmallVec
<[P
<ast
::Item
>; 1]>) {
154 "item"; many
fn flat_map_item
; fn visit_item(); fn make_items
;
156 TraitItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
158 many
fn flat_map_trait_item
;
159 fn visit_assoc_item(AssocCtxt
::Trait
);
162 ImplItems(SmallVec
<[P
<ast
::AssocItem
>; 1]>) {
164 many
fn flat_map_impl_item
;
165 fn visit_assoc_item(AssocCtxt
::Impl
);
168 ForeignItems(SmallVec
<[P
<ast
::ForeignItem
>; 1]>) {
170 many
fn flat_map_foreign_item
;
171 fn visit_foreign_item();
172 fn make_foreign_items
;
174 Arms(SmallVec
<[ast
::Arm
; 1]>) {
175 "match arm"; many
fn flat_map_arm
; fn visit_arm(); fn make_arms
;
177 Fields(SmallVec
<[ast
::Field
; 1]>) {
178 "field expression"; many
fn flat_map_field
; fn visit_field(); fn make_fields
;
180 FieldPats(SmallVec
<[ast
::FieldPat
; 1]>) {
182 many
fn flat_map_field_pattern
;
183 fn visit_field_pattern();
184 fn make_field_patterns
;
186 GenericParams(SmallVec
<[ast
::GenericParam
; 1]>) {
188 many
fn flat_map_generic_param
;
189 fn visit_generic_param();
190 fn make_generic_params
;
192 Params(SmallVec
<[ast
::Param
; 1]>) {
193 "function parameter"; many
fn flat_map_param
; fn visit_param(); fn make_params
;
195 StructFields(SmallVec
<[ast
::StructField
; 1]>) {
197 many
fn flat_map_struct_field
;
198 fn visit_struct_field();
199 fn make_struct_fields
;
201 Variants(SmallVec
<[ast
::Variant
; 1]>) {
202 "variant"; many
fn flat_map_variant
; fn visit_variant(); fn make_variants
;
206 impl AstFragmentKind
{
207 fn dummy(self, span
: Span
) -> AstFragment
{
208 self.make_from(DummyResult
::any(span
)).expect("couldn't create a dummy AST fragment")
211 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(
215 let mut items
= items
.into_iter();
217 AstFragmentKind
::Arms
=> {
218 AstFragment
::Arms(items
.map(Annotatable
::expect_arm
).collect())
220 AstFragmentKind
::Fields
=> {
221 AstFragment
::Fields(items
.map(Annotatable
::expect_field
).collect())
223 AstFragmentKind
::FieldPats
=> {
224 AstFragment
::FieldPats(items
.map(Annotatable
::expect_field_pattern
).collect())
226 AstFragmentKind
::GenericParams
=> {
227 AstFragment
::GenericParams(items
.map(Annotatable
::expect_generic_param
).collect())
229 AstFragmentKind
::Params
=> {
230 AstFragment
::Params(items
.map(Annotatable
::expect_param
).collect())
232 AstFragmentKind
::StructFields
=> {
233 AstFragment
::StructFields(items
.map(Annotatable
::expect_struct_field
).collect())
235 AstFragmentKind
::Variants
=> {
236 AstFragment
::Variants(items
.map(Annotatable
::expect_variant
).collect())
238 AstFragmentKind
::Items
=> {
239 AstFragment
::Items(items
.map(Annotatable
::expect_item
).collect())
241 AstFragmentKind
::ImplItems
=> {
242 AstFragment
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect())
244 AstFragmentKind
::TraitItems
=> {
245 AstFragment
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect())
247 AstFragmentKind
::ForeignItems
=> {
248 AstFragment
::ForeignItems(items
.map(Annotatable
::expect_foreign_item
).collect())
250 AstFragmentKind
::Stmts
=> {
251 AstFragment
::Stmts(items
.map(Annotatable
::expect_stmt
).collect())
253 AstFragmentKind
::Expr
=> AstFragment
::Expr(
254 items
.next().expect("expected exactly one expression").expect_expr(),
256 AstFragmentKind
::OptExpr
=> {
257 AstFragment
::OptExpr(items
.next().map(Annotatable
::expect_expr
))
259 AstFragmentKind
::Pat
| AstFragmentKind
::Ty
=> {
260 panic
!("patterns and types aren't annotatable")
266 pub struct Invocation
{
267 pub kind
: InvocationKind
,
268 pub fragment_kind
: AstFragmentKind
,
269 pub expansion_data
: ExpansionData
,
272 pub enum InvocationKind
{
278 attr
: ast
::Attribute
,
280 // Required for resolving derive helper attributes.
282 // We temporarily report errors for attribute macros placed after derives
289 /// "Invocation" that contains all derives from an item,
290 /// broken into multiple `Derive` invocations when expanded.
291 /// FIXME: Find a way to remove it.
298 impl InvocationKind
{
299 fn placeholder_visibility(&self) -> Option
<ast
::Visibility
> {
300 // HACK: For unnamed fields placeholders should have the same visibility as the actual
301 // fields because for tuple structs/variants resolve determines visibilities of their
302 // constructor using these field visibilities before attributes on them are are expanded.
303 // The assumption is that the attribute expansion cannot change field visibilities,
304 // and it holds because only inert attributes are supported in this position.
306 InvocationKind
::Attr { item: Annotatable::StructField(field), .. }
307 | InvocationKind
::Derive { item: Annotatable::StructField(field), .. }
308 | InvocationKind
::DeriveContainer { item: Annotatable::StructField(field), .. }
309 if field
.ident
.is_none() =>
311 Some(field
.vis
.clone())
319 pub fn span(&self) -> Span
{
321 InvocationKind
::Bang { span, .. }
=> *span
,
322 InvocationKind
::Attr { attr, .. }
=> attr
.span
,
323 InvocationKind
::Derive { path, .. }
=> path
.span
,
324 InvocationKind
::DeriveContainer { item, .. }
=> item
.span(),
329 pub struct MacroExpander
<'a
, 'b
> {
330 pub cx
: &'a
mut ExtCtxt
<'b
>,
331 monotonic
: bool
, // cf. `cx.monotonic_expander()`
334 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
335 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
336 MacroExpander { cx, monotonic }
339 pub fn expand_crate(&mut self, mut krate
: ast
::Crate
) -> ast
::Crate
{
340 let mut module
= ModuleData
{
341 mod_path
: vec
![Ident
::from_str(&self.cx
.ecfg
.crate_name
)],
342 directory
: match self.cx
.source_map().span_to_unmapped_path(krate
.span
) {
343 FileName
::Real(path
) => path
,
344 other
=> PathBuf
::from(other
.to_string()),
347 module
.directory
.pop();
348 self.cx
.root_path
= module
.directory
.clone();
349 self.cx
.current_expansion
.module
= Rc
::new(module
);
351 let orig_mod_span
= krate
.module
.inner
;
353 let krate_item
= AstFragment
::Items(smallvec
![P(ast
::Item
{
356 kind
: ast
::ItemKind
::Mod(krate
.module
),
357 ident
: Ident
::invalid(),
358 id
: ast
::DUMMY_NODE_ID
,
359 vis
: respan(krate
.span
.shrink_to_lo(), ast
::VisibilityKind
::Public
),
363 match self.fully_expand_fragment(krate_item
).make_items().pop().map(P
::into_inner
) {
364 Some(ast
::Item { attrs, kind: ast::ItemKind::Mod(module), .. }
) => {
366 krate
.module
= module
;
369 // Resolution failed so we return an empty expansion
370 krate
.attrs
= vec
![];
371 krate
.module
= ast
::Mod { inner: orig_mod_span, items: vec![], inline: true }
;
373 Some(ast
::Item { span, kind, .. }
) => {
374 krate
.attrs
= vec
![];
375 krate
.module
= ast
::Mod { inner: orig_mod_span, items: vec![], inline: true }
;
379 "expected crate top-level item to be a module after macro expansion, found {} {}",
380 kind
.article(), kind
.descr()
385 self.cx
.trace_macros_diag();
389 // Recursively expand all macro invocations in this AST fragment.
390 pub fn fully_expand_fragment(&mut self, input_fragment
: AstFragment
) -> AstFragment
{
391 let orig_expansion_data
= self.cx
.current_expansion
.clone();
392 self.cx
.current_expansion
.depth
= 0;
394 // Collect all macro invocations and replace them with placeholders.
395 let (mut fragment_with_placeholders
, mut invocations
) =
396 self.collect_invocations(input_fragment
, &[]);
398 // Optimization: if we resolve all imports now,
399 // we'll be able to immediately resolve most of imported macros.
400 self.resolve_imports();
402 // Resolve paths in all invocations and produce output expanded fragments for them, but
403 // do not insert them into our input AST fragment yet, only store in `expanded_fragments`.
404 // The output fragments also go through expansion recursively until no invocations are left.
405 // Unresolved macros produce dummy outputs as a recovery measure.
406 invocations
.reverse();
407 let mut expanded_fragments
= Vec
::new();
408 let mut undetermined_invocations
= Vec
::new();
409 let (mut progress
, mut force
) = (false, !self.monotonic
);
411 let invoc
= if let Some(invoc
) = invocations
.pop() {
414 self.resolve_imports();
415 if undetermined_invocations
.is_empty() {
418 invocations
= mem
::take(&mut undetermined_invocations
);
419 force
= !mem
::replace(&mut progress
, false);
423 let eager_expansion_root
=
424 if self.monotonic { invoc.expansion_data.id }
else { orig_expansion_data.id }
;
425 let res
= match self.cx
.resolver
.resolve_macro_invocation(
427 eager_expansion_root
,
431 Err(Indeterminate
) => {
432 undetermined_invocations
.push(invoc
);
438 let ExpansionData { depth, id: expn_id, .. }
= invoc
.expansion_data
;
439 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
441 // FIXME(jseyfried): Refactor out the following logic
442 let (expanded_fragment
, new_invocations
) = match res
{
443 InvocationRes
::Single(ext
) => {
444 let fragment
= self.expand_invoc(invoc
, &ext
.kind
);
445 self.collect_invocations(fragment
, &[])
447 InvocationRes
::DeriveContainer(_exts
) => {
448 // FIXME: Consider using the derive resolutions (`_exts`) immediately,
449 // instead of enqueuing the derives to be resolved again later.
450 let (derives
, item
) = match invoc
.kind
{
451 InvocationKind
::DeriveContainer { derives, item }
=> (derives
, item
),
454 if !item
.derive_allowed() {
455 self.error_derive_forbidden_on_non_adt(&derives
, &item
);
458 let mut item
= self.fully_configure(item
);
459 item
.visit_attrs(|attrs
| attrs
.retain(|a
| !a
.has_name(sym
::derive
)));
461 let mut derive_placeholders
= Vec
::with_capacity(derives
.len());
462 invocations
.reserve(derives
.len());
463 for path
in derives
{
464 let expn_id
= ExpnId
::fresh(None
);
465 derive_placeholders
.push(NodeId
::placeholder_from_expn_id(expn_id
));
466 invocations
.push(Invocation
{
467 kind
: InvocationKind
::Derive { path, item: item.clone() }
,
468 fragment_kind
: invoc
.fragment_kind
,
469 expansion_data
: ExpansionData
{
471 ..invoc
.expansion_data
.clone()
476 invoc
.fragment_kind
.expect_from_annotatables(::std
::iter
::once(item
));
477 self.collect_invocations(fragment
, &derive_placeholders
)
481 if expanded_fragments
.len() < depth
{
482 expanded_fragments
.push(Vec
::new());
484 expanded_fragments
[depth
- 1].push((expn_id
, expanded_fragment
));
485 if !self.cx
.ecfg
.single_step
{
486 invocations
.extend(new_invocations
.into_iter().rev());
490 self.cx
.current_expansion
= orig_expansion_data
;
492 // Finally incorporate all the expanded macros into the input AST fragment.
493 let mut placeholder_expander
= PlaceholderExpander
::new(self.cx
, self.monotonic
);
494 while let Some(expanded_fragments
) = expanded_fragments
.pop() {
495 for (expn_id
, expanded_fragment
) in expanded_fragments
.into_iter().rev() {
497 .add(NodeId
::placeholder_from_expn_id(expn_id
), expanded_fragment
);
500 fragment_with_placeholders
.mut_visit_with(&mut placeholder_expander
);
501 fragment_with_placeholders
504 fn error_derive_forbidden_on_non_adt(&self, derives
: &[Path
], item
: &Annotatable
) {
505 let attr
= attr
::find_by_name(item
.attrs(), sym
::derive
);
506 let span
= attr
.map_or(item
.span(), |attr
| attr
.span
);
509 .struct_span_err(span
, "`derive` may only be applied to structs, enums and unions");
510 if let Some(ast
::Attribute { style: ast::AttrStyle::Inner, .. }
) = attr
{
511 let trait_list
= derives
.iter().map(|t
| pprust
::path_to_string(t
)).collect
::<Vec
<_
>>();
512 let suggestion
= format
!("#[derive({})]", trait_list
.join(", "));
515 "try an outer attribute",
517 // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
518 Applicability
::MaybeIncorrect
,
524 fn resolve_imports(&mut self) {
526 self.cx
.resolver
.resolve_imports();
530 /// Collects all macro invocations reachable at this time in this AST fragment, and replace
531 /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
532 /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
533 /// prepares data for resolving paths of macro invocations.
534 fn collect_invocations(
536 mut fragment
: AstFragment
,
537 extra_placeholders
: &[NodeId
],
538 ) -> (AstFragment
, Vec
<Invocation
>) {
539 // Resolve `$crate`s in the fragment for pretty-printing.
540 self.cx
.resolver
.resolve_dollar_crates();
543 let mut collector
= InvocationCollector
{
544 cfg
: StripUnconfigured
{
545 sess
: self.cx
.parse_sess
,
546 features
: self.cx
.ecfg
.features
,
549 invocations
: Vec
::new(),
550 monotonic
: self.monotonic
,
552 fragment
.mut_visit_with(&mut collector
);
553 fragment
.add_placeholders(extra_placeholders
);
554 collector
.invocations
560 .visit_ast_fragment_with_placeholders(self.cx
.current_expansion
.id
, &fragment
);
563 (fragment
, invocations
)
566 fn fully_configure(&mut self, item
: Annotatable
) -> Annotatable
{
568 StripUnconfigured { sess: self.cx.parse_sess, features: self.cx.ecfg.features }
;
569 // Since the item itself has already been configured by the InvocationCollector,
570 // we know that fold result vector will contain exactly one element
572 Annotatable
::Item(item
) => Annotatable
::Item(cfg
.flat_map_item(item
).pop().unwrap()),
573 Annotatable
::TraitItem(item
) => {
574 Annotatable
::TraitItem(cfg
.flat_map_trait_item(item
).pop().unwrap())
576 Annotatable
::ImplItem(item
) => {
577 Annotatable
::ImplItem(cfg
.flat_map_impl_item(item
).pop().unwrap())
579 Annotatable
::ForeignItem(item
) => {
580 Annotatable
::ForeignItem(cfg
.flat_map_foreign_item(item
).pop().unwrap())
582 Annotatable
::Stmt(stmt
) => {
583 Annotatable
::Stmt(stmt
.map(|stmt
| cfg
.flat_map_stmt(stmt
).pop().unwrap()))
585 Annotatable
::Expr(mut expr
) => Annotatable
::Expr({
586 cfg
.visit_expr(&mut expr
);
589 Annotatable
::Arm(arm
) => Annotatable
::Arm(cfg
.flat_map_arm(arm
).pop().unwrap()),
590 Annotatable
::Field(field
) => {
591 Annotatable
::Field(cfg
.flat_map_field(field
).pop().unwrap())
593 Annotatable
::FieldPat(fp
) => {
594 Annotatable
::FieldPat(cfg
.flat_map_field_pattern(fp
).pop().unwrap())
596 Annotatable
::GenericParam(param
) => {
597 Annotatable
::GenericParam(cfg
.flat_map_generic_param(param
).pop().unwrap())
599 Annotatable
::Param(param
) => {
600 Annotatable
::Param(cfg
.flat_map_param(param
).pop().unwrap())
602 Annotatable
::StructField(sf
) => {
603 Annotatable
::StructField(cfg
.flat_map_struct_field(sf
).pop().unwrap())
605 Annotatable
::Variant(v
) => Annotatable
::Variant(cfg
.flat_map_variant(v
).pop().unwrap()),
609 fn error_recursion_limit_reached(&mut self) {
610 let expn_data
= self.cx
.current_expansion
.id
.expn_data();
611 let suggested_limit
= self.cx
.ecfg
.recursion_limit
* 2;
615 &format
!("recursion limit reached while expanding `{}`", expn_data
.kind
.descr()),
618 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
619 suggested_limit
, self.cx
.ecfg
.crate_name
,
622 self.cx
.trace_macros_diag();
626 /// A macro's expansion does not fit in this fragment kind.
627 /// For example, a non-type macro in a type position.
628 fn error_wrong_fragment_kind(&mut self, kind
: AstFragmentKind
, mac
: &ast
::Mac
, span
: Span
) {
630 "non-{kind} macro in {kind} position: {path}",
632 path
= pprust
::path_to_string(&mac
.path
),
634 self.cx
.span_err(span
, &msg
);
635 self.cx
.trace_macros_diag();
638 fn expand_invoc(&mut self, invoc
: Invocation
, ext
: &SyntaxExtensionKind
) -> AstFragment
{
639 if self.cx
.current_expansion
.depth
> self.cx
.ecfg
.recursion_limit
{
640 self.error_recursion_limit_reached();
643 let (fragment_kind
, span
) = (invoc
.fragment_kind
, invoc
.span());
645 InvocationKind
::Bang { mac, .. }
=> match ext
{
646 SyntaxExtensionKind
::Bang(expander
) => {
647 self.gate_proc_macro_expansion_kind(span
, fragment_kind
);
648 let tok_result
= expander
.expand(self.cx
, span
, mac
.args
.inner_tokens());
649 self.parse_ast_fragment(tok_result
, fragment_kind
, &mac
.path
, span
)
651 SyntaxExtensionKind
::LegacyBang(expander
) => {
652 let prev
= self.cx
.current_expansion
.prior_type_ascription
;
653 self.cx
.current_expansion
.prior_type_ascription
= mac
.prior_type_ascription
;
654 let tok_result
= expander
.expand(self.cx
, span
, mac
.args
.inner_tokens());
655 let result
= if let Some(result
) = fragment_kind
.make_from(tok_result
) {
658 self.error_wrong_fragment_kind(fragment_kind
, &mac
, span
);
659 fragment_kind
.dummy(span
)
661 self.cx
.current_expansion
.prior_type_ascription
= prev
;
666 InvocationKind
::Attr { attr, mut item, .. }
=> match ext
{
667 SyntaxExtensionKind
::Attr(expander
) => {
668 self.gate_proc_macro_input(&item
);
669 self.gate_proc_macro_attr_item(span
, &item
);
670 let tokens
= item
.into_tokens();
671 let attr_item
= attr
.unwrap_normal_item();
672 if let MacArgs
::Eq(..) = attr_item
.args
{
673 self.cx
.span_err(span
, "key-value macro attributes are not supported");
676 expander
.expand(self.cx
, span
, attr_item
.args
.inner_tokens(), tokens
);
677 self.parse_ast_fragment(tok_result
, fragment_kind
, &attr_item
.path
, span
)
679 SyntaxExtensionKind
::LegacyAttr(expander
) => {
680 match validate_attr
::parse_meta(self.cx
.parse_sess
, &attr
) {
682 let item
= expander
.expand(self.cx
, span
, &meta
, item
);
683 fragment_kind
.expect_from_annotatables(item
)
687 fragment_kind
.dummy(span
)
691 SyntaxExtensionKind
::NonMacroAttr { mark_used }
=> {
692 attr
::mark_known(&attr
);
694 attr
::mark_used(&attr
);
696 item
.visit_attrs(|attrs
| attrs
.push(attr
));
697 fragment_kind
.expect_from_annotatables(iter
::once(item
))
701 InvocationKind
::Derive { path, item }
=> match ext
{
702 SyntaxExtensionKind
::Derive(expander
)
703 | SyntaxExtensionKind
::LegacyDerive(expander
) => {
704 if !item
.derive_allowed() {
705 return fragment_kind
.dummy(span
);
707 if let SyntaxExtensionKind
::Derive(..) = ext
{
708 self.gate_proc_macro_input(&item
);
710 let meta
= ast
::MetaItem { kind: ast::MetaItemKind::Word, span, path }
;
711 let items
= expander
.expand(self.cx
, span
, &meta
, item
);
712 fragment_kind
.expect_from_annotatables(items
)
716 InvocationKind
::DeriveContainer { .. }
=> unreachable
!(),
720 fn gate_proc_macro_attr_item(&self, span
: Span
, item
: &Annotatable
) {
721 let kind
= match item
{
723 | Annotatable
::TraitItem(_
)
724 | Annotatable
::ImplItem(_
)
725 | Annotatable
::ForeignItem(_
) => return,
726 Annotatable
::Stmt(_
) => "statements",
727 Annotatable
::Expr(_
) => "expressions",
729 | Annotatable
::Field(..)
730 | Annotatable
::FieldPat(..)
731 | Annotatable
::GenericParam(..)
732 | Annotatable
::Param(..)
733 | Annotatable
::StructField(..)
734 | Annotatable
::Variant(..) => panic
!("unexpected annotatable"),
736 if self.cx
.ecfg
.proc_macro_hygiene() {
741 sym
::proc_macro_hygiene
,
743 &format
!("custom attributes cannot be applied to {}", kind
),
748 fn gate_proc_macro_input(&self, annotatable
: &Annotatable
) {
749 struct GateProcMacroInput
<'a
> {
750 parse_sess
: &'a ParseSess
,
753 impl<'ast
, 'a
> Visitor
<'ast
> for GateProcMacroInput
<'a
> {
754 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
756 ast
::ItemKind
::Mod(module
) if !module
.inline
=> {
759 sym
::proc_macro_hygiene
,
761 "non-inline modules in proc macro input are unstable",
768 visit
::walk_item(self, item
);
771 fn visit_mac(&mut self, _
: &'ast ast
::Mac
) {}
774 if !self.cx
.ecfg
.proc_macro_hygiene() {
775 annotatable
.visit_with(&mut GateProcMacroInput { parse_sess: self.cx.parse_sess }
);
779 fn gate_proc_macro_expansion_kind(&self, span
: Span
, kind
: AstFragmentKind
) {
780 let kind
= match kind
{
781 AstFragmentKind
::Expr
| AstFragmentKind
::OptExpr
=> "expressions",
782 AstFragmentKind
::Pat
=> "patterns",
783 AstFragmentKind
::Stmts
=> "statements",
785 | AstFragmentKind
::Items
786 | AstFragmentKind
::TraitItems
787 | AstFragmentKind
::ImplItems
788 | AstFragmentKind
::ForeignItems
=> return,
789 AstFragmentKind
::Arms
790 | AstFragmentKind
::Fields
791 | AstFragmentKind
::FieldPats
792 | AstFragmentKind
::GenericParams
793 | AstFragmentKind
::Params
794 | AstFragmentKind
::StructFields
795 | AstFragmentKind
::Variants
=> panic
!("unexpected AST fragment kind"),
797 if self.cx
.ecfg
.proc_macro_hygiene() {
802 sym
::proc_macro_hygiene
,
804 &format
!("procedural macros cannot be expanded to {}", kind
),
809 fn parse_ast_fragment(
812 kind
: AstFragmentKind
,
816 let mut parser
= self.cx
.new_parser_from_tts(toks
);
817 match parse_ast_fragment(&mut parser
, kind
) {
819 ensure_complete_parse(&mut parser
, path
, kind
.name(), span
);
824 annotate_err_with_kind(&mut err
, kind
, span
);
826 self.cx
.trace_macros_diag();
833 pub fn parse_ast_fragment
<'a
>(
834 this
: &mut Parser
<'a
>,
835 kind
: AstFragmentKind
,
836 ) -> PResult
<'a
, AstFragment
> {
838 AstFragmentKind
::Items
=> {
839 let mut items
= SmallVec
::new();
840 while let Some(item
) = this
.parse_item()?
{
843 AstFragment
::Items(items
)
845 AstFragmentKind
::TraitItems
=> {
846 let mut items
= SmallVec
::new();
847 while let Some(item
) = this
.parse_trait_item()?
{
850 AstFragment
::TraitItems(items
)
852 AstFragmentKind
::ImplItems
=> {
853 let mut items
= SmallVec
::new();
854 while let Some(item
) = this
.parse_impl_item()?
{
857 AstFragment
::ImplItems(items
)
859 AstFragmentKind
::ForeignItems
=> {
860 let mut items
= SmallVec
::new();
861 while let Some(item
) = this
.parse_foreign_item()?
{
864 AstFragment
::ForeignItems(items
)
866 AstFragmentKind
::Stmts
=> {
867 let mut stmts
= SmallVec
::new();
868 // Won't make progress on a `}`.
869 while this
.token
!= token
::Eof
&& this
.token
!= token
::CloseDelim(token
::Brace
) {
870 if let Some(stmt
) = this
.parse_full_stmt()?
{
874 AstFragment
::Stmts(stmts
)
876 AstFragmentKind
::Expr
=> AstFragment
::Expr(this
.parse_expr()?
),
877 AstFragmentKind
::OptExpr
=> {
878 if this
.token
!= token
::Eof
{
879 AstFragment
::OptExpr(Some(this
.parse_expr()?
))
881 AstFragment
::OptExpr(None
)
884 AstFragmentKind
::Ty
=> AstFragment
::Ty(this
.parse_ty()?
),
885 AstFragmentKind
::Pat
=> AstFragment
::Pat(this
.parse_pat(None
)?
),
886 AstFragmentKind
::Arms
887 | AstFragmentKind
::Fields
888 | AstFragmentKind
::FieldPats
889 | AstFragmentKind
::GenericParams
890 | AstFragmentKind
::Params
891 | AstFragmentKind
::StructFields
892 | AstFragmentKind
::Variants
=> panic
!("unexpected AST fragment kind"),
896 pub fn ensure_complete_parse
<'a
>(
897 this
: &mut Parser
<'a
>,
902 if this
.token
!= token
::Eof
{
903 let token
= pprust
::token_to_string(&this
.token
);
904 let msg
= format
!("macro expansion ignores token `{}` and any following", token
);
905 // Avoid emitting backtrace info twice.
906 let def_site_span
= this
.token
.span
.with_ctxt(SyntaxContext
::root());
907 let mut err
= this
.struct_span_err(def_site_span
, &msg
);
908 err
.span_label(span
, "caused by the macro expansion here");
910 "the usage of `{}!` is likely invalid in {} context",
911 pprust
::path_to_string(macro_path
),
915 let semi_span
= this
.sess
.source_map().next_point(span
);
917 let semi_full_span
= semi_span
.to(this
.sess
.source_map().next_point(semi_span
));
918 match this
.sess
.source_map().span_to_snippet(semi_full_span
) {
919 Ok(ref snippet
) if &snippet
[..] != ";" && kind_name
== "expression" => {
922 "you might be missing a semicolon here",
924 Applicability
::MaybeIncorrect
,
933 struct InvocationCollector
<'a
, 'b
> {
934 cx
: &'a
mut ExtCtxt
<'b
>,
935 cfg
: StripUnconfigured
<'a
>,
936 invocations
: Vec
<Invocation
>,
940 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
941 fn collect(&mut self, fragment_kind
: AstFragmentKind
, kind
: InvocationKind
) -> AstFragment
{
942 // Expansion data for all the collected invocations is set upon their resolution,
943 // with exception of the derive container case which is not resolved and can get
944 // its expansion data immediately.
945 let expn_data
= match &kind
{
946 InvocationKind
::DeriveContainer { item, .. }
=> Some(ExpnData
{
947 parent
: self.cx
.current_expansion
.id
,
949 ExpnKind
::Macro(MacroKind
::Attr
, sym
::derive
),
951 self.cx
.parse_sess
.edition
,
956 let expn_id
= ExpnId
::fresh(expn_data
);
957 let vis
= kind
.placeholder_visibility();
958 self.invocations
.push(Invocation
{
961 expansion_data
: ExpansionData
{
963 depth
: self.cx
.current_expansion
.depth
+ 1,
964 ..self.cx
.current_expansion
.clone()
967 placeholder(fragment_kind
, NodeId
::placeholder_from_expn_id(expn_id
), vis
)
970 fn collect_bang(&mut self, mac
: ast
::Mac
, span
: Span
, kind
: AstFragmentKind
) -> AstFragment
{
971 self.collect(kind
, InvocationKind
::Bang { mac, span }
)
976 attr
: Option
<ast
::Attribute
>,
979 kind
: AstFragmentKind
,
985 Some(attr
) => InvocationKind
::Attr { attr, item, derives, after_derive }
,
986 None
=> InvocationKind
::DeriveContainer { derives, item }
,
993 attrs
: &mut Vec
<ast
::Attribute
>,
994 after_derive
: &mut bool
,
995 ) -> Option
<ast
::Attribute
> {
999 if a
.has_name(sym
::derive
) {
1000 *after_derive
= true;
1002 !attr
::is_known(a
) && !is_builtin_attr(a
)
1004 .map(|i
| attrs
.remove(i
));
1005 if let Some(attr
) = &attr
{
1006 if !self.cx
.ecfg
.custom_inner_attributes()
1007 && attr
.style
== ast
::AttrStyle
::Inner
1008 && !attr
.has_name(sym
::test
)
1011 &self.cx
.parse_sess
,
1012 sym
::custom_inner_attributes
,
1014 "non-builtin inner attributes are unstable",
1022 /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
1025 item
: &mut impl HasAttrs
,
1026 ) -> (Option
<ast
::Attribute
>, Vec
<Path
>, /* after_derive */ bool
) {
1027 let (mut attr
, mut traits
, mut after_derive
) = (None
, Vec
::new(), false);
1029 item
.visit_attrs(|mut attrs
| {
1030 attr
= self.find_attr_invoc(&mut attrs
, &mut after_derive
);
1031 traits
= collect_derives(&mut self.cx
, &mut attrs
);
1034 (attr
, traits
, after_derive
)
1037 /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
1038 /// to the unused-attributes lint (making it an error on statements and expressions
1039 /// is a breaking change)
1040 fn classify_nonitem(
1042 nonitem
: &mut impl HasAttrs
,
1043 ) -> (Option
<ast
::Attribute
>, /* after_derive */ bool
) {
1044 let (mut attr
, mut after_derive
) = (None
, false);
1046 nonitem
.visit_attrs(|mut attrs
| {
1047 attr
= self.find_attr_invoc(&mut attrs
, &mut after_derive
);
1050 (attr
, after_derive
)
1053 fn configure
<T
: HasAttrs
>(&mut self, node
: T
) -> Option
<T
> {
1054 self.cfg
.configure(node
)
1057 // Detect use of feature-gated or invalid attributes on macro invocations
1058 // since they will not be detected after macro expansion.
1059 fn check_attributes(&mut self, attrs
: &[ast
::Attribute
]) {
1060 let features
= self.cx
.ecfg
.features
.unwrap();
1061 for attr
in attrs
.iter() {
1062 rustc_ast_passes
::feature_gate
::check_attribute(attr
, self.cx
.parse_sess
, features
);
1063 validate_attr
::check_meta(self.cx
.parse_sess
, attr
);
1065 // macros are expanded before any lint passes so this warning has to be hardcoded
1066 if attr
.has_name(sym
::derive
) {
1068 .struct_span_warn(attr
.span
, "`#[derive]` does nothing on macro invocations")
1069 .note("this may become a hard error in a future release")
1073 if attr
.doc_str().is_some() {
1074 self.cx
.parse_sess
.buffer_lint_with_diagnostic(
1075 &UNUSED_DOC_COMMENTS
,
1078 "unused doc comment",
1079 BuiltinLintDiagnostics
::UnusedDocComment(attr
.span
),
1086 impl<'a
, 'b
> MutVisitor
for InvocationCollector
<'a
, 'b
> {
1087 fn visit_expr(&mut self, expr
: &mut P
<ast
::Expr
>) {
1088 self.cfg
.configure_expr(expr
);
1089 visit_clobber(expr
.deref_mut(), |mut expr
| {
1090 self.cfg
.configure_expr_kind(&mut expr
.kind
);
1092 // ignore derives so they remain unused
1093 let (attr
, after_derive
) = self.classify_nonitem(&mut expr
);
1096 // Collect the invoc regardless of whether or not attributes are permitted here
1097 // expansion will eat the attribute so it won't error later.
1098 attr
.as_ref().map(|a
| self.cfg
.maybe_emit_expr_attr_err(a
));
1100 // AstFragmentKind::Expr requires the macro to emit an expression.
1105 Annotatable
::Expr(P(expr
)),
1106 AstFragmentKind
::Expr
,
1113 if let ast
::ExprKind
::Mac(mac
) = expr
.kind
{
1114 self.check_attributes(&expr
.attrs
);
1115 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::Expr
).make_expr().into_inner()
1117 noop_visit_expr(&mut expr
, self);
1123 fn flat_map_arm(&mut self, arm
: ast
::Arm
) -> SmallVec
<[ast
::Arm
; 1]> {
1124 let mut arm
= configure
!(self, arm
);
1126 let (attr
, traits
, after_derive
) = self.classify_item(&mut arm
);
1127 if attr
.is_some() || !traits
.is_empty() {
1132 Annotatable
::Arm(arm
),
1133 AstFragmentKind
::Arms
,
1139 noop_flat_map_arm(arm
, self)
1142 fn flat_map_field(&mut self, field
: ast
::Field
) -> SmallVec
<[ast
::Field
; 1]> {
1143 let mut field
= configure
!(self, field
);
1145 let (attr
, traits
, after_derive
) = self.classify_item(&mut field
);
1146 if attr
.is_some() || !traits
.is_empty() {
1151 Annotatable
::Field(field
),
1152 AstFragmentKind
::Fields
,
1158 noop_flat_map_field(field
, self)
1161 fn flat_map_field_pattern(&mut self, fp
: ast
::FieldPat
) -> SmallVec
<[ast
::FieldPat
; 1]> {
1162 let mut fp
= configure
!(self, fp
);
1164 let (attr
, traits
, after_derive
) = self.classify_item(&mut fp
);
1165 if attr
.is_some() || !traits
.is_empty() {
1170 Annotatable
::FieldPat(fp
),
1171 AstFragmentKind
::FieldPats
,
1174 .make_field_patterns();
1177 noop_flat_map_field_pattern(fp
, self)
1180 fn flat_map_param(&mut self, p
: ast
::Param
) -> SmallVec
<[ast
::Param
; 1]> {
1181 let mut p
= configure
!(self, p
);
1183 let (attr
, traits
, after_derive
) = self.classify_item(&mut p
);
1184 if attr
.is_some() || !traits
.is_empty() {
1189 Annotatable
::Param(p
),
1190 AstFragmentKind
::Params
,
1196 noop_flat_map_param(p
, self)
1199 fn flat_map_struct_field(&mut self, sf
: ast
::StructField
) -> SmallVec
<[ast
::StructField
; 1]> {
1200 let mut sf
= configure
!(self, sf
);
1202 let (attr
, traits
, after_derive
) = self.classify_item(&mut sf
);
1203 if attr
.is_some() || !traits
.is_empty() {
1208 Annotatable
::StructField(sf
),
1209 AstFragmentKind
::StructFields
,
1212 .make_struct_fields();
1215 noop_flat_map_struct_field(sf
, self)
1218 fn flat_map_variant(&mut self, variant
: ast
::Variant
) -> SmallVec
<[ast
::Variant
; 1]> {
1219 let mut variant
= configure
!(self, variant
);
1221 let (attr
, traits
, after_derive
) = self.classify_item(&mut variant
);
1222 if attr
.is_some() || !traits
.is_empty() {
1227 Annotatable
::Variant(variant
),
1228 AstFragmentKind
::Variants
,
1234 noop_flat_map_variant(variant
, self)
1237 fn filter_map_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
1238 let expr
= configure
!(self, expr
);
1239 expr
.filter_map(|mut expr
| {
1240 self.cfg
.configure_expr_kind(&mut expr
.kind
);
1242 // Ignore derives so they remain unused.
1243 let (attr
, after_derive
) = self.classify_nonitem(&mut expr
);
1246 attr
.as_ref().map(|a
| self.cfg
.maybe_emit_expr_attr_err(a
));
1252 Annotatable
::Expr(P(expr
)),
1253 AstFragmentKind
::OptExpr
,
1257 .map(|expr
| expr
.into_inner());
1260 if let ast
::ExprKind
::Mac(mac
) = expr
.kind
{
1261 self.check_attributes(&expr
.attrs
);
1262 self.collect_bang(mac
, expr
.span
, AstFragmentKind
::OptExpr
)
1264 .map(|expr
| expr
.into_inner())
1267 noop_visit_expr(&mut expr
, self);
1274 fn visit_pat(&mut self, pat
: &mut P
<ast
::Pat
>) {
1275 self.cfg
.configure_pat(pat
);
1277 PatKind
::Mac(_
) => {}
1278 _
=> return noop_visit_pat(pat
, self),
1281 visit_clobber(pat
, |mut pat
| match mem
::replace(&mut pat
.kind
, PatKind
::Wild
) {
1282 PatKind
::Mac(mac
) => self.collect_bang(mac
, pat
.span
, AstFragmentKind
::Pat
).make_pat(),
1283 _
=> unreachable
!(),
1287 fn flat_map_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVec
<[ast
::Stmt
; 1]> {
1288 let mut stmt
= configure
!(self, stmt
);
1290 // we'll expand attributes on expressions separately
1291 if !stmt
.is_expr() {
1292 let (attr
, derives
, after_derive
) = if stmt
.is_item() {
1293 self.classify_item(&mut stmt
)
1295 // ignore derives on non-item statements so it falls through
1296 // to the unused-attributes lint
1297 let (attr
, after_derive
) = self.classify_nonitem(&mut stmt
);
1298 (attr
, vec
![], after_derive
)
1301 if attr
.is_some() || !derives
.is_empty() {
1306 Annotatable
::Stmt(P(stmt
)),
1307 AstFragmentKind
::Stmts
,
1314 if let StmtKind
::Mac(mac
) = stmt
.kind
{
1315 let (mac
, style
, attrs
) = mac
.into_inner();
1316 self.check_attributes(&attrs
);
1317 let mut placeholder
=
1318 self.collect_bang(mac
, stmt
.span
, AstFragmentKind
::Stmts
).make_stmts();
1320 // If this is a macro invocation with a semicolon, then apply that
1321 // semicolon to the final statement produced by expansion.
1322 if style
== MacStmtStyle
::Semicolon
{
1323 if let Some(stmt
) = placeholder
.pop() {
1324 placeholder
.push(stmt
.add_trailing_semicolon());
1331 // The placeholder expander gives ids to statements, so we avoid folding the id here.
1332 let ast
::Stmt { id, kind, span }
= stmt
;
1333 noop_flat_map_stmt_kind(kind
, self)
1335 .map(|kind
| ast
::Stmt { id, kind, span }
)
1339 fn visit_block(&mut self, block
: &mut P
<Block
>) {
1340 let old_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
1341 self.cx
.current_expansion
.directory_ownership
= DirectoryOwnership
::UnownedViaBlock
;
1342 noop_visit_block(block
, self);
1343 self.cx
.current_expansion
.directory_ownership
= old_directory_ownership
;
1346 fn flat_map_item(&mut self, item
: P
<ast
::Item
>) -> SmallVec
<[P
<ast
::Item
>; 1]> {
1347 let mut item
= configure
!(self, item
);
1349 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1350 if attr
.is_some() || !traits
.is_empty() {
1355 Annotatable
::Item(item
),
1356 AstFragmentKind
::Items
,
1363 ast
::ItemKind
::Mac(..) => {
1364 self.check_attributes(&item
.attrs
);
1365 item
.and_then(|item
| match item
.kind
{
1366 ItemKind
::Mac(mac
) => self
1368 AstFragmentKind
::Items
,
1369 InvocationKind
::Bang { mac, span: item.span }
,
1372 _
=> unreachable
!(),
1375 ast
::ItemKind
::Mod(ast
::Mod { inner, inline, .. }
)
1376 if item
.ident
!= Ident
::invalid() =>
1378 let orig_directory_ownership
= self.cx
.current_expansion
.directory_ownership
;
1379 let mut module
= (*self.cx
.current_expansion
.module
).clone();
1380 module
.mod_path
.push(item
.ident
);
1383 if let Some(path
) = attr
::first_attr_value_str_by_name(&item
.attrs
, sym
::path
) {
1384 self.cx
.current_expansion
.directory_ownership
=
1385 DirectoryOwnership
::Owned { relative: None }
;
1386 module
.directory
.push(&*path
.as_str());
1388 module
.directory
.push(&*item
.ident
.as_str());
1391 let path
= self.cx
.parse_sess
.source_map().span_to_unmapped_path(inner
);
1392 let mut path
= match path
{
1393 FileName
::Real(path
) => path
,
1394 other
=> PathBuf
::from(other
.to_string()),
1396 let directory_ownership
= match path
.file_name().unwrap().to_str() {
1397 Some("mod.rs") => DirectoryOwnership
::Owned { relative: None }
,
1398 Some(_
) => DirectoryOwnership
::Owned { relative: Some(item.ident) }
,
1399 None
=> DirectoryOwnership
::UnownedViaMod
,
1402 module
.directory
= path
;
1403 self.cx
.current_expansion
.directory_ownership
= directory_ownership
;
1407 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
1408 let result
= noop_flat_map_item(item
, self);
1409 self.cx
.current_expansion
.module
= orig_module
;
1410 self.cx
.current_expansion
.directory_ownership
= orig_directory_ownership
;
1414 _
=> noop_flat_map_item(item
, self),
1418 fn flat_map_trait_item(&mut self, item
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1419 let mut item
= configure
!(self, item
);
1421 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1422 if attr
.is_some() || !traits
.is_empty() {
1427 Annotatable
::TraitItem(item
),
1428 AstFragmentKind
::TraitItems
,
1431 .make_trait_items();
1435 ast
::AssocItemKind
::Macro(..) => {
1436 self.check_attributes(&item
.attrs
);
1437 item
.and_then(|item
| match item
.kind
{
1438 ast
::AssocItemKind
::Macro(mac
) => self
1439 .collect_bang(mac
, item
.span
, AstFragmentKind
::TraitItems
)
1440 .make_trait_items(),
1441 _
=> unreachable
!(),
1444 _
=> noop_flat_map_assoc_item(item
, self),
1448 fn flat_map_impl_item(&mut self, item
: P
<ast
::AssocItem
>) -> SmallVec
<[P
<ast
::AssocItem
>; 1]> {
1449 let mut item
= configure
!(self, item
);
1451 let (attr
, traits
, after_derive
) = self.classify_item(&mut item
);
1452 if attr
.is_some() || !traits
.is_empty() {
1457 Annotatable
::ImplItem(item
),
1458 AstFragmentKind
::ImplItems
,
1465 ast
::AssocItemKind
::Macro(..) => {
1466 self.check_attributes(&item
.attrs
);
1467 item
.and_then(|item
| match item
.kind
{
1468 ast
::AssocItemKind
::Macro(mac
) => self
1469 .collect_bang(mac
, item
.span
, AstFragmentKind
::ImplItems
)
1471 _
=> unreachable
!(),
1474 _
=> noop_flat_map_assoc_item(item
, self),
1478 fn visit_ty(&mut self, ty
: &mut P
<ast
::Ty
>) {
1480 ast
::TyKind
::Mac(_
) => {}
1481 _
=> return noop_visit_ty(ty
, self),
1484 visit_clobber(ty
, |mut ty
| match mem
::replace(&mut ty
.kind
, ast
::TyKind
::Err
) {
1485 ast
::TyKind
::Mac(mac
) => self.collect_bang(mac
, ty
.span
, AstFragmentKind
::Ty
).make_ty(),
1486 _
=> unreachable
!(),
1490 fn visit_foreign_mod(&mut self, foreign_mod
: &mut ast
::ForeignMod
) {
1491 self.cfg
.configure_foreign_mod(foreign_mod
);
1492 noop_visit_foreign_mod(foreign_mod
, self);
1495 fn flat_map_foreign_item(
1497 mut foreign_item
: P
<ast
::ForeignItem
>,
1498 ) -> SmallVec
<[P
<ast
::ForeignItem
>; 1]> {
1499 let (attr
, traits
, after_derive
) = self.classify_item(&mut foreign_item
);
1501 if attr
.is_some() || !traits
.is_empty() {
1506 Annotatable
::ForeignItem(foreign_item
),
1507 AstFragmentKind
::ForeignItems
,
1510 .make_foreign_items();
1513 match foreign_item
.kind
{
1514 ast
::ForeignItemKind
::Macro(..) => {
1515 self.check_attributes(&foreign_item
.attrs
);
1516 foreign_item
.and_then(|item
| match item
.kind
{
1517 ast
::ForeignItemKind
::Macro(mac
) => self
1518 .collect_bang(mac
, item
.span
, AstFragmentKind
::ForeignItems
)
1519 .make_foreign_items(),
1520 _
=> unreachable
!(),
1523 _
=> noop_flat_map_foreign_item(foreign_item
, self),
1527 fn visit_item_kind(&mut self, item
: &mut ast
::ItemKind
) {
1529 ast
::ItemKind
::MacroDef(..) => {}
1531 self.cfg
.configure_item_kind(item
);
1532 noop_visit_item_kind(item
, self);
1537 fn flat_map_generic_param(
1539 param
: ast
::GenericParam
,
1540 ) -> SmallVec
<[ast
::GenericParam
; 1]> {
1541 let mut param
= configure
!(self, param
);
1543 let (attr
, traits
, after_derive
) = self.classify_item(&mut param
);
1544 if attr
.is_some() || !traits
.is_empty() {
1549 Annotatable
::GenericParam(param
),
1550 AstFragmentKind
::GenericParams
,
1553 .make_generic_params();
1556 noop_flat_map_generic_param(param
, self)
1559 fn visit_attribute(&mut self, at
: &mut ast
::Attribute
) {
1560 // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
1561 // contents="file contents")]` attributes
1562 if !at
.check_name(sym
::doc
) {
1563 return noop_visit_attribute(at
, self);
1566 if let Some(list
) = at
.meta_item_list() {
1567 if !list
.iter().any(|it
| it
.check_name(sym
::include
)) {
1568 return noop_visit_attribute(at
, self);
1571 let mut items
= vec
![];
1573 for mut it
in list
{
1574 if !it
.check_name(sym
::include
) {
1576 noop_visit_meta_list_item(&mut it
, self);
1582 if let Some(file
) = it
.value_str() {
1583 let err_count
= self.cx
.parse_sess
.span_diagnostic
.err_count();
1584 self.check_attributes(slice
::from_ref(at
));
1585 if self.cx
.parse_sess
.span_diagnostic
.err_count() > err_count
{
1586 // avoid loading the file if they haven't enabled the feature
1587 return noop_visit_attribute(at
, self);
1590 let filename
= match self.cx
.resolve_path(&*file
.as_str(), it
.span()) {
1591 Ok(filename
) => filename
,
1598 match self.cx
.source_map().load_file(&filename
) {
1599 Ok(source_file
) => {
1600 let src
= source_file
1603 .expect("freshly loaded file should have a source");
1604 let src_interned
= Symbol
::intern(src
.as_str());
1606 let include_info
= vec
![
1607 ast
::NestedMetaItem
::MetaItem(attr
::mk_name_value_item_str(
1608 Ident
::with_dummy_span(sym
::file
),
1612 ast
::NestedMetaItem
::MetaItem(attr
::mk_name_value_item_str(
1613 Ident
::with_dummy_span(sym
::contents
),
1619 let include_ident
= Ident
::with_dummy_span(sym
::include
);
1620 let item
= attr
::mk_list_item(include_ident
, include_info
);
1621 items
.push(ast
::NestedMetaItem
::MetaItem(item
));
1625 it
.meta_item().and_then(|item
| item
.name_value_literal()).unwrap();
1627 if e
.kind() == ErrorKind
::InvalidData
{
1631 &format
!("{} wasn't a utf-8 file", filename
.display()),
1633 .span_label(lit
.span
, "contains invalid utf-8")
1636 let mut err
= self.cx
.struct_span_err(
1638 &format
!("couldn't read {}: {}", filename
.display(), e
),
1640 err
.span_label(lit
.span
, "couldn't read file");
1649 .struct_span_err(it
.span(), "expected path to external documentation");
1651 // Check if the user erroneously used `doc(include(...))` syntax.
1652 let literal
= it
.meta_item_list().and_then(|list
| {
1653 if list
.len() == 1 {
1654 list
[0].literal().map(|literal
| &literal
.kind
)
1660 let (path
, applicability
) = match &literal
{
1661 Some(LitKind
::Str(path
, ..)) => {
1662 (path
.to_string(), Applicability
::MachineApplicable
)
1664 _
=> (String
::from("<path>"), Applicability
::HasPlaceholders
),
1667 err
.span_suggestion(
1669 "provide a file path with `=`",
1670 format
!("include = \"{}\"", path
),
1678 let meta
= attr
::mk_list_item(Ident
::with_dummy_span(sym
::doc
), items
);
1679 *at
= ast
::Attribute
{
1680 kind
: ast
::AttrKind
::Normal(AttrItem
{
1682 args
: meta
.kind
.mac_args(meta
.span
),
1689 noop_visit_attribute(at
, self)
1693 fn visit_id(&mut self, id
: &mut ast
::NodeId
) {
1695 debug_assert_eq
!(*id
, ast
::DUMMY_NODE_ID
);
1696 *id
= self.cx
.resolver
.next_node_id()
1700 fn visit_fn_decl(&mut self, mut fn_decl
: &mut P
<ast
::FnDecl
>) {
1701 self.cfg
.configure_fn_decl(&mut fn_decl
);
1702 noop_visit_fn_decl(fn_decl
, self);
1706 pub struct ExpansionConfig
<'feat
> {
1707 pub crate_name
: String
,
1708 pub features
: Option
<&'feat Features
>,
1709 pub recursion_limit
: usize,
1710 pub trace_mac
: bool
,
1711 pub should_test
: bool
, // If false, strip `#[test]` nodes
1712 pub single_step
: bool
,
1713 pub keep_macs
: bool
,
1716 impl<'feat
> ExpansionConfig
<'feat
> {
1717 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
1721 recursion_limit
: 1024,
1729 fn proc_macro_hygiene(&self) -> bool
{
1730 self.features
.map_or(false, |features
| features
.proc_macro_hygiene
)
1732 fn custom_inner_attributes(&self) -> bool
{
1733 self.features
.map_or(false, |features
| features
.custom_inner_attributes
)