1
1
use crate :: util:: check_builtin_macro_attribute;
2
2
3
3
use rustc_ast as ast;
4
- use rustc_ast:: mut_visit:: MutVisitor ;
5
- use rustc_ast:: tokenstream:: CanSynthesizeMissingTokens ;
6
- use rustc_ast:: visit:: Visitor ;
7
- use rustc_ast:: { mut_visit, visit} ;
8
- use rustc_ast:: { AstLike , Attribute } ;
9
4
use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
10
- use rustc_expand:: config:: StripUnconfigured ;
11
- use rustc_expand:: configure;
12
- use rustc_parse:: parser:: ForceCollect ;
13
- use rustc_session:: utils:: FlattenNonterminals ;
14
-
15
- use rustc_ast:: ptr:: P ;
5
+ use rustc_expand:: config:: cfg_eval;
16
6
use rustc_span:: symbol:: sym;
17
7
use rustc_span:: Span ;
18
- use smallvec:: SmallVec ;
19
8
20
9
crate fn expand (
21
10
ecx : & mut ExtCtxt < ' _ > ,
@@ -26,244 +15,3 @@ crate fn expand(
26
15
check_builtin_macro_attribute ( ecx, meta_item, sym:: cfg_eval) ;
27
16
cfg_eval ( ecx, annotatable)
28
17
}
29
-
30
- crate fn cfg_eval ( ecx : & ExtCtxt < ' _ > , annotatable : Annotatable ) -> Vec < Annotatable > {
31
- let mut visitor = CfgEval {
32
- cfg : & mut StripUnconfigured {
33
- sess : ecx. sess ,
34
- features : ecx. ecfg . features ,
35
- config_tokens : true ,
36
- } ,
37
- } ;
38
- let annotatable = visitor. configure_annotatable ( annotatable) ;
39
- vec ! [ annotatable]
40
- }
41
-
42
- struct CfgEval < ' a , ' b > {
43
- cfg : & ' a mut StripUnconfigured < ' b > ,
44
- }
45
-
46
- fn flat_map_annotatable ( vis : & mut impl MutVisitor , annotatable : Annotatable ) -> Annotatable {
47
- // Since the item itself has already been configured by the InvocationCollector,
48
- // we know that fold result vector will contain exactly one element
49
- match annotatable {
50
- Annotatable :: Item ( item) => Annotatable :: Item ( vis. flat_map_item ( item) . pop ( ) . unwrap ( ) ) ,
51
- Annotatable :: TraitItem ( item) => {
52
- Annotatable :: TraitItem ( vis. flat_map_trait_item ( item) . pop ( ) . unwrap ( ) )
53
- }
54
- Annotatable :: ImplItem ( item) => {
55
- Annotatable :: ImplItem ( vis. flat_map_impl_item ( item) . pop ( ) . unwrap ( ) )
56
- }
57
- Annotatable :: ForeignItem ( item) => {
58
- Annotatable :: ForeignItem ( vis. flat_map_foreign_item ( item) . pop ( ) . unwrap ( ) )
59
- }
60
- Annotatable :: Stmt ( stmt) => {
61
- Annotatable :: Stmt ( stmt. map ( |stmt| vis. flat_map_stmt ( stmt) . pop ( ) . unwrap ( ) ) )
62
- }
63
- Annotatable :: Expr ( mut expr) => Annotatable :: Expr ( {
64
- vis. visit_expr ( & mut expr) ;
65
- expr
66
- } ) ,
67
- Annotatable :: Arm ( arm) => Annotatable :: Arm ( vis. flat_map_arm ( arm) . pop ( ) . unwrap ( ) ) ,
68
- Annotatable :: ExprField ( field) => {
69
- Annotatable :: ExprField ( vis. flat_map_expr_field ( field) . pop ( ) . unwrap ( ) )
70
- }
71
- Annotatable :: PatField ( fp) => {
72
- Annotatable :: PatField ( vis. flat_map_pat_field ( fp) . pop ( ) . unwrap ( ) )
73
- }
74
- Annotatable :: GenericParam ( param) => {
75
- Annotatable :: GenericParam ( vis. flat_map_generic_param ( param) . pop ( ) . unwrap ( ) )
76
- }
77
- Annotatable :: Param ( param) => Annotatable :: Param ( vis. flat_map_param ( param) . pop ( ) . unwrap ( ) ) ,
78
- Annotatable :: FieldDef ( sf) => {
79
- Annotatable :: FieldDef ( vis. flat_map_field_def ( sf) . pop ( ) . unwrap ( ) )
80
- }
81
- Annotatable :: Variant ( v) => Annotatable :: Variant ( vis. flat_map_variant ( v) . pop ( ) . unwrap ( ) ) ,
82
- }
83
- }
84
-
85
- struct CfgFinder {
86
- has_cfg_or_cfg_attr : bool ,
87
- }
88
-
89
- impl CfgFinder {
90
- fn has_cfg_or_cfg_attr ( annotatable : & Annotatable ) -> bool {
91
- let mut finder = CfgFinder { has_cfg_or_cfg_attr : false } ;
92
- match annotatable {
93
- Annotatable :: Item ( item) => finder. visit_item ( & item) ,
94
- Annotatable :: TraitItem ( item) => finder. visit_assoc_item ( & item, visit:: AssocCtxt :: Trait ) ,
95
- Annotatable :: ImplItem ( item) => finder. visit_assoc_item ( & item, visit:: AssocCtxt :: Impl ) ,
96
- Annotatable :: ForeignItem ( item) => finder. visit_foreign_item ( & item) ,
97
- Annotatable :: Stmt ( stmt) => finder. visit_stmt ( & stmt) ,
98
- Annotatable :: Expr ( expr) => finder. visit_expr ( & expr) ,
99
- Annotatable :: Arm ( arm) => finder. visit_arm ( & arm) ,
100
- Annotatable :: ExprField ( field) => finder. visit_expr_field ( & field) ,
101
- Annotatable :: PatField ( field) => finder. visit_pat_field ( & field) ,
102
- Annotatable :: GenericParam ( param) => finder. visit_generic_param ( & param) ,
103
- Annotatable :: Param ( param) => finder. visit_param ( & param) ,
104
- Annotatable :: FieldDef ( field) => finder. visit_field_def ( & field) ,
105
- Annotatable :: Variant ( variant) => finder. visit_variant ( & variant) ,
106
- } ;
107
- finder. has_cfg_or_cfg_attr
108
- }
109
- }
110
-
111
- impl < ' ast > visit:: Visitor < ' ast > for CfgFinder {
112
- fn visit_attribute ( & mut self , attr : & ' ast Attribute ) {
113
- // We want short-circuiting behavior, so don't use the '|=' operator.
114
- self . has_cfg_or_cfg_attr = self . has_cfg_or_cfg_attr
115
- || attr
116
- . ident ( )
117
- . map_or ( false , |ident| ident. name == sym:: cfg || ident. name == sym:: cfg_attr) ;
118
- }
119
- }
120
-
121
- impl CfgEval < ' _ , ' _ > {
122
- fn configure < T : AstLike > ( & mut self , node : T ) -> Option < T > {
123
- self . cfg . configure ( node)
124
- }
125
-
126
- pub fn configure_annotatable ( & mut self , mut annotatable : Annotatable ) -> Annotatable {
127
- // Tokenizing and re-parsing the `Annotatable` can have a significant
128
- // performance impact, so try to avoid it if possible
129
- if !CfgFinder :: has_cfg_or_cfg_attr ( & annotatable) {
130
- return annotatable;
131
- }
132
-
133
- // The majority of parsed attribute targets will never need to have early cfg-expansion
134
- // run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro inoput).
135
- // Therefore, we normally do not capture the necessary information about `#[cfg]`
136
- // and `#[cfg_attr]` attributes during parsing.
137
- //
138
- // Therefore, when we actually *do* run early cfg-expansion, we need to tokenize
139
- // and re-parse the attribute target, this time capturing information about
140
- // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
141
- // process is lossless, so this process is invisible to proc-macros.
142
-
143
- // FIXME - get rid of this clone
144
- let nt = annotatable. clone ( ) . into_nonterminal ( ) ;
145
-
146
- let mut orig_tokens = rustc_parse:: nt_to_tokenstream (
147
- & nt,
148
- & self . cfg . sess . parse_sess ,
149
- CanSynthesizeMissingTokens :: No ,
150
- ) ;
151
-
152
- // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
153
- // to `None`-delimited groups containing the corresponding tokens. This
154
- // is normally delayed until the proc-macro server actually needs to
155
- // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
156
- // so that we can handle cases like:
157
- //
158
- // ```rust
159
- // #[cfg_eval] #[cfg] $item
160
- //```
161
- //
162
- // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
163
- // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
164
- // way to do this is to do a single parse of a stream without any nonterminals.
165
- let mut flatten = FlattenNonterminals {
166
- nt_to_tokenstream : rustc_parse:: nt_to_tokenstream,
167
- parse_sess : & self . cfg . sess . parse_sess ,
168
- synthesize_tokens : CanSynthesizeMissingTokens :: No ,
169
- } ;
170
- orig_tokens = flatten. process_token_stream ( orig_tokens) ;
171
-
172
- // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
173
- // to the captured `AttrAnnotatedTokenStream` (specifically, we capture
174
- // `AttrAnnotatedTokenTree::AttributesData` for all occurences of `#[cfg]` and `#[cfg_attr]`)
175
- let mut parser =
176
- rustc_parse:: stream_to_parser ( & self . cfg . sess . parse_sess , orig_tokens, None ) ;
177
- parser. capture_cfg = true ;
178
- annotatable = match annotatable {
179
- Annotatable :: Item ( _) => {
180
- Annotatable :: Item ( parser. parse_item ( ForceCollect :: Yes ) . unwrap ( ) . unwrap ( ) )
181
- }
182
- Annotatable :: TraitItem ( _) => Annotatable :: TraitItem (
183
- parser. parse_trait_item ( ForceCollect :: Yes ) . unwrap ( ) . unwrap ( ) . unwrap ( ) ,
184
- ) ,
185
- Annotatable :: ImplItem ( _) => Annotatable :: ImplItem (
186
- parser. parse_impl_item ( ForceCollect :: Yes ) . unwrap ( ) . unwrap ( ) . unwrap ( ) ,
187
- ) ,
188
- Annotatable :: ForeignItem ( _) => Annotatable :: ForeignItem (
189
- parser. parse_foreign_item ( ForceCollect :: Yes ) . unwrap ( ) . unwrap ( ) . unwrap ( ) ,
190
- ) ,
191
- Annotatable :: Stmt ( _) => {
192
- Annotatable :: Stmt ( P ( parser. parse_stmt ( ForceCollect :: Yes ) . unwrap ( ) . unwrap ( ) ) )
193
- }
194
- Annotatable :: Expr ( _) => Annotatable :: Expr ( parser. parse_expr_force_collect ( ) . unwrap ( ) ) ,
195
- _ => unreachable ! ( ) ,
196
- } ;
197
-
198
- // Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
199
- // our attribute target will correctly the tokens as well.
200
- flat_map_annotatable ( self , annotatable)
201
- }
202
- }
203
-
204
- impl MutVisitor for CfgEval < ' _ , ' _ > {
205
- fn visit_expr ( & mut self , expr : & mut P < ast:: Expr > ) {
206
- self . cfg . configure_expr ( expr) ;
207
- mut_visit:: noop_visit_expr ( expr, self ) ;
208
- }
209
-
210
- fn filter_map_expr ( & mut self , expr : P < ast:: Expr > ) -> Option < P < ast:: Expr > > {
211
- let mut expr = configure ! ( self , expr) ;
212
- mut_visit:: noop_visit_expr ( & mut expr, self ) ;
213
- Some ( expr)
214
- }
215
-
216
- fn flat_map_generic_param (
217
- & mut self ,
218
- param : ast:: GenericParam ,
219
- ) -> SmallVec < [ ast:: GenericParam ; 1 ] > {
220
- mut_visit:: noop_flat_map_generic_param ( configure ! ( self , param) , self )
221
- }
222
-
223
- fn flat_map_stmt ( & mut self , stmt : ast:: Stmt ) -> SmallVec < [ ast:: Stmt ; 1 ] > {
224
- mut_visit:: noop_flat_map_stmt ( configure ! ( self , stmt) , self )
225
- }
226
-
227
- fn flat_map_item ( & mut self , item : P < ast:: Item > ) -> SmallVec < [ P < ast:: Item > ; 1 ] > {
228
- mut_visit:: noop_flat_map_item ( configure ! ( self , item) , self )
229
- }
230
-
231
- fn flat_map_impl_item ( & mut self , item : P < ast:: AssocItem > ) -> SmallVec < [ P < ast:: AssocItem > ; 1 ] > {
232
- mut_visit:: noop_flat_map_assoc_item ( configure ! ( self , item) , self )
233
- }
234
-
235
- fn flat_map_trait_item ( & mut self , item : P < ast:: AssocItem > ) -> SmallVec < [ P < ast:: AssocItem > ; 1 ] > {
236
- mut_visit:: noop_flat_map_assoc_item ( configure ! ( self , item) , self )
237
- }
238
-
239
- fn flat_map_foreign_item (
240
- & mut self ,
241
- foreign_item : P < ast:: ForeignItem > ,
242
- ) -> SmallVec < [ P < ast:: ForeignItem > ; 1 ] > {
243
- mut_visit:: noop_flat_map_foreign_item ( configure ! ( self , foreign_item) , self )
244
- }
245
-
246
- fn flat_map_arm ( & mut self , arm : ast:: Arm ) -> SmallVec < [ ast:: Arm ; 1 ] > {
247
- mut_visit:: noop_flat_map_arm ( configure ! ( self , arm) , self )
248
- }
249
-
250
- fn flat_map_expr_field ( & mut self , field : ast:: ExprField ) -> SmallVec < [ ast:: ExprField ; 1 ] > {
251
- mut_visit:: noop_flat_map_expr_field ( configure ! ( self , field) , self )
252
- }
253
-
254
- fn flat_map_pat_field ( & mut self , fp : ast:: PatField ) -> SmallVec < [ ast:: PatField ; 1 ] > {
255
- mut_visit:: noop_flat_map_pat_field ( configure ! ( self , fp) , self )
256
- }
257
-
258
- fn flat_map_param ( & mut self , p : ast:: Param ) -> SmallVec < [ ast:: Param ; 1 ] > {
259
- mut_visit:: noop_flat_map_param ( configure ! ( self , p) , self )
260
- }
261
-
262
- fn flat_map_field_def ( & mut self , sf : ast:: FieldDef ) -> SmallVec < [ ast:: FieldDef ; 1 ] > {
263
- mut_visit:: noop_flat_map_field_def ( configure ! ( self , sf) , self )
264
- }
265
-
266
- fn flat_map_variant ( & mut self , variant : ast:: Variant ) -> SmallVec < [ ast:: Variant ; 1 ] > {
267
- mut_visit:: noop_flat_map_variant ( configure ! ( self , variant) , self )
268
- }
269
- }
0 commit comments