]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_builtin_macros/src/cfg_eval.rs
Rollup merge of #83654 - JohnTitor:issue-83606, r=estebank
[rust.git] / compiler / rustc_builtin_macros / src / cfg_eval.rs
1 use crate::util::check_builtin_macro_attribute;
2
3 use rustc_ast::mut_visit::{self, MutVisitor};
4 use rustc_ast::ptr::P;
5 use rustc_ast::{self as ast, AstLike};
6 use rustc_expand::base::{Annotatable, ExtCtxt};
7 use rustc_expand::config::StripUnconfigured;
8 use rustc_expand::configure;
9 use rustc_span::symbol::sym;
10 use rustc_span::Span;
11 use smallvec::SmallVec;
12
13 crate fn expand(
14     ecx: &mut ExtCtxt<'_>,
15     _span: Span,
16     meta_item: &ast::MetaItem,
17     annotatable: Annotatable,
18 ) -> Vec<Annotatable> {
19     check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
20     cfg_eval(ecx, annotatable)
21 }
22
23 crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec<Annotatable> {
24     let mut visitor = CfgEval {
25         cfg: StripUnconfigured { sess: ecx.sess, features: ecx.ecfg.features, modified: false },
26     };
27     let mut annotatable = visitor.configure_annotatable(annotatable);
28     if visitor.cfg.modified {
29         // Erase the tokens if cfg-stripping modified the item
30         // This will cause us to synthesize fake tokens
31         // when `nt_to_tokenstream` is called on this item.
32         if let Some(tokens) = annotatable.tokens_mut() {
33             *tokens = None;
34         }
35     }
36     vec![annotatable]
37 }
38
39 struct CfgEval<'a> {
40     cfg: StripUnconfigured<'a>,
41 }
42
43 impl CfgEval<'_> {
44     fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
45         self.cfg.configure(node)
46     }
47
48     fn configure_annotatable(&mut self, annotatable: Annotatable) -> Annotatable {
49         // Since the item itself has already been configured by the InvocationCollector,
50         // we know that fold result vector will contain exactly one element
51         match annotatable {
52             Annotatable::Item(item) => Annotatable::Item(self.flat_map_item(item).pop().unwrap()),
53             Annotatable::TraitItem(item) => {
54                 Annotatable::TraitItem(self.flat_map_trait_item(item).pop().unwrap())
55             }
56             Annotatable::ImplItem(item) => {
57                 Annotatable::ImplItem(self.flat_map_impl_item(item).pop().unwrap())
58             }
59             Annotatable::ForeignItem(item) => {
60                 Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
61             }
62             Annotatable::Stmt(stmt) => {
63                 Annotatable::Stmt(stmt.map(|stmt| self.flat_map_stmt(stmt).pop().unwrap()))
64             }
65             Annotatable::Expr(mut expr) => Annotatable::Expr({
66                 self.visit_expr(&mut expr);
67                 expr
68             }),
69             Annotatable::Arm(arm) => Annotatable::Arm(self.flat_map_arm(arm).pop().unwrap()),
70             Annotatable::ExprField(field) => {
71                 Annotatable::ExprField(self.flat_map_expr_field(field).pop().unwrap())
72             }
73             Annotatable::PatField(fp) => {
74                 Annotatable::PatField(self.flat_map_pat_field(fp).pop().unwrap())
75             }
76             Annotatable::GenericParam(param) => {
77                 Annotatable::GenericParam(self.flat_map_generic_param(param).pop().unwrap())
78             }
79             Annotatable::Param(param) => {
80                 Annotatable::Param(self.flat_map_param(param).pop().unwrap())
81             }
82             Annotatable::FieldDef(sf) => {
83                 Annotatable::FieldDef(self.flat_map_field_def(sf).pop().unwrap())
84             }
85             Annotatable::Variant(v) => {
86                 Annotatable::Variant(self.flat_map_variant(v).pop().unwrap())
87             }
88         }
89     }
90 }
91
92 impl MutVisitor for CfgEval<'_> {
93     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
94         self.cfg.configure_expr(expr);
95         mut_visit::noop_visit_expr(expr, self);
96     }
97
98     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
99         let mut expr = configure!(self, expr);
100         mut_visit::noop_visit_expr(&mut expr, self);
101         Some(expr)
102     }
103
104     fn flat_map_generic_param(
105         &mut self,
106         param: ast::GenericParam,
107     ) -> SmallVec<[ast::GenericParam; 1]> {
108         mut_visit::noop_flat_map_generic_param(configure!(self, param), self)
109     }
110
111     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
112         mut_visit::noop_flat_map_stmt(configure!(self, stmt), self)
113     }
114
115     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
116         mut_visit::noop_flat_map_item(configure!(self, item), self)
117     }
118
119     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
120         mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
121     }
122
123     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
124         mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
125     }
126
127     fn flat_map_foreign_item(
128         &mut self,
129         foreign_item: P<ast::ForeignItem>,
130     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
131         mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self)
132     }
133
134     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
135         mut_visit::noop_flat_map_arm(configure!(self, arm), self)
136     }
137
138     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
139         mut_visit::noop_flat_map_expr_field(configure!(self, field), self)
140     }
141
142     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
143         mut_visit::noop_flat_map_pat_field(configure!(self, fp), self)
144     }
145
146     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
147         mut_visit::noop_flat_map_param(configure!(self, p), self)
148     }
149
150     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
151         mut_visit::noop_flat_map_field_def(configure!(self, sf), self)
152     }
153
154     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
155         mut_visit::noop_flat_map_variant(configure!(self, variant), self)
156     }
157 }