@@ -13,14 +13,14 @@ use errors::Handler;
13
13
use feature_gate:: GatedCfgAttr ;
14
14
use fold:: Folder ;
15
15
use { ast, fold, attr} ;
16
- use visit;
17
16
use codemap:: { Spanned , respan} ;
18
17
use ptr:: P ;
19
18
20
19
use util:: small_vector:: SmallVector ;
21
20
22
21
pub trait CfgFolder : fold:: Folder {
23
22
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > ;
23
+ fn visit_stmt_or_expr_attrs ( & mut self , _attrs : & [ ast:: Attribute ] ) { }
24
24
fn visit_unconfigurable_expr ( & mut self , _expr : & ast:: Expr ) { }
25
25
}
26
26
@@ -31,14 +31,78 @@ pub struct StripUnconfigured<'a> {
31
31
config : & ' a ast:: CrateConfig ,
32
32
}
33
33
34
- impl < ' a > CfgFolder for StripUnconfigured < ' a > {
35
- fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
36
- if in_cfg ( self . config , node. attrs ( ) , & mut self . diag ) {
37
- Some ( node)
34
+ impl < ' a > StripUnconfigured < ' a > {
35
+ // Determine if an item should be translated in the current crate
36
+ // configuration based on the item's attributes
37
+ fn in_cfg ( & mut self , attrs : & [ ast:: Attribute ] ) -> bool {
38
+ attrs. iter ( ) . all ( |attr| {
39
+ let mis = match attr. node . value . node {
40
+ ast:: MetaItemKind :: List ( _, ref mis) if is_cfg ( & attr) => mis,
41
+ _ => return true
42
+ } ;
43
+
44
+ if mis. len ( ) != 1 {
45
+ self . diag . emit_error ( |diagnostic| {
46
+ diagnostic. span_err ( attr. span , "expected 1 cfg-pattern" ) ;
47
+ } ) ;
48
+ return true ;
49
+ }
50
+
51
+ attr:: cfg_matches ( self . config , & mis[ 0 ] , & mut self . diag )
52
+ } )
53
+ }
54
+
55
+ fn process_cfg_attrs ( & mut self , attrs : Vec < ast:: Attribute > ) -> Vec < ast:: Attribute > {
56
+ attrs. into_iter ( ) . filter_map ( |attr| self . process_cfg_attr ( attr) ) . collect ( )
57
+ }
58
+
59
+ fn process_cfg_attr ( & mut self , attr : ast:: Attribute ) -> Option < ast:: Attribute > {
60
+ if !attr. check_name ( "cfg_attr" ) {
61
+ return Some ( attr) ;
62
+ }
63
+
64
+ let attr_list = match attr. meta_item_list ( ) {
65
+ Some ( attr_list) => attr_list,
66
+ None => {
67
+ let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ;
68
+ self . diag . diag . span_err ( attr. span , msg) ;
69
+ return None ;
70
+ }
71
+ } ;
72
+ let ( cfg, mi) = match ( attr_list. len ( ) , attr_list. get ( 0 ) , attr_list. get ( 1 ) ) {
73
+ ( 2 , Some ( cfg) , Some ( mi) ) => ( cfg, mi) ,
74
+ _ => {
75
+ let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ;
76
+ self . diag . diag . span_err ( attr. span , msg) ;
77
+ return None ;
78
+ }
79
+ } ;
80
+
81
+ if attr:: cfg_matches ( self . config , & cfg, & mut self . diag ) {
82
+ Some ( respan ( mi. span , ast:: Attribute_ {
83
+ id : attr:: mk_attr_id ( ) ,
84
+ style : attr. node . style ,
85
+ value : mi. clone ( ) ,
86
+ is_sugared_doc : false ,
87
+ } ) )
38
88
} else {
39
89
None
40
90
}
41
91
}
92
+ }
93
+
94
+ impl < ' a > CfgFolder for StripUnconfigured < ' a > {
95
+ fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
96
+ let node = node. map_attrs ( |attrs| self . process_cfg_attrs ( attrs) ) ;
97
+ if self . in_cfg ( node. attrs ( ) ) { Some ( node) } else { None }
98
+ }
99
+
100
+ fn visit_stmt_or_expr_attrs ( & mut self , attrs : & [ ast:: Attribute ] ) {
101
+ // flag the offending attributes
102
+ for attr in attrs. iter ( ) {
103
+ self . diag . feature_gated_cfgs . push ( GatedCfgAttr :: GatedAttr ( attr. span ) ) ;
104
+ }
105
+ }
42
106
43
107
fn visit_unconfigurable_expr ( & mut self , expr : & ast:: Expr ) {
44
108
if let Some ( attr) = expr. attrs ( ) . iter ( ) . find ( |a| is_cfg ( a) ) {
@@ -54,11 +118,6 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
54
118
feature_gated_cfgs : & mut Vec < GatedCfgAttr > )
55
119
-> ast:: Crate
56
120
{
57
- // Need to do this check here because cfg runs before feature_gates
58
- check_for_gated_stmt_expr_attributes ( & krate, feature_gated_cfgs) ;
59
-
60
- let krate = process_cfg_attr ( diagnostic, krate, feature_gated_cfgs) ;
61
-
62
121
StripUnconfigured {
63
122
config : & krate. config . clone ( ) ,
64
123
diag : CfgDiagReal {
@@ -72,7 +131,9 @@ impl<T: CfgFolder> fold::Folder for T {
72
131
fn fold_foreign_mod ( & mut self , foreign_mod : ast:: ForeignMod ) -> ast:: ForeignMod {
73
132
ast:: ForeignMod {
74
133
abi : foreign_mod. abi ,
75
- items : foreign_mod. items . into_iter ( ) . filter_map ( |item| self . configure ( item) ) . collect ( ) ,
134
+ items : foreign_mod. items . into_iter ( ) . filter_map ( |item| {
135
+ self . configure ( item) . map ( |item| fold:: noop_fold_foreign_item ( item, self ) )
136
+ } ) . collect ( ) ,
76
137
}
77
138
}
78
139
@@ -126,6 +187,7 @@ impl<T: CfgFolder> fold::Folder for T {
126
187
}
127
188
128
189
fn fold_expr ( & mut self , expr : P < ast:: Expr > ) -> P < ast:: Expr > {
190
+ self . visit_stmt_or_expr_attrs ( expr. attrs ( ) ) ;
129
191
// If an expr is valid to cfg away it will have been removed by the
130
192
// outer stmt or expression folder before descending in here.
131
193
// Anything else is always required, and thus has to error out
@@ -142,6 +204,19 @@ impl<T: CfgFolder> fold::Folder for T {
142
204
}
143
205
144
206
fn fold_stmt ( & mut self , stmt : ast:: Stmt ) -> SmallVector < ast:: Stmt > {
207
+ let is_item = match stmt. node {
208
+ ast:: StmtKind :: Decl ( ref decl, _) => match decl. node {
209
+ ast:: DeclKind :: Item ( _) => true ,
210
+ _ => false ,
211
+ } ,
212
+ _ => false ,
213
+ } ;
214
+
215
+ // avoid calling `visit_stmt_or_expr_attrs` on items
216
+ if !is_item {
217
+ self . visit_stmt_or_expr_attrs ( stmt. attrs ( ) ) ;
218
+ }
219
+
145
220
self . configure ( stmt) . map ( |stmt| fold:: noop_fold_stmt ( stmt, self ) )
146
221
. unwrap_or ( SmallVector :: zero ( ) )
147
222
}
@@ -178,205 +253,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
178
253
attr. check_name ( "cfg" )
179
254
}
180
255
181
- // Determine if an item should be translated in the current crate
182
- // configuration based on the item's attributes
183
- fn in_cfg < T : CfgDiag > ( cfg : & [ P < ast:: MetaItem > ] ,
184
- attrs : & [ ast:: Attribute ] ,
185
- diag : & mut T ) -> bool {
186
- attrs. iter ( ) . all ( |attr| {
187
- let mis = match attr. node . value . node {
188
- ast:: MetaItemKind :: List ( _, ref mis) if is_cfg ( & attr) => mis,
189
- _ => return true
190
- } ;
191
-
192
- if mis. len ( ) != 1 {
193
- diag. emit_error ( |diagnostic| {
194
- diagnostic. span_err ( attr. span , "expected 1 cfg-pattern" ) ;
195
- } ) ;
196
- return true ;
197
- }
198
-
199
- attr:: cfg_matches ( cfg, & mis[ 0 ] , diag)
200
- } )
201
- }
202
-
203
- struct CfgAttrFolder < ' a , T > {
204
- diag : T ,
205
- config : & ' a ast:: CrateConfig ,
206
- }
207
-
208
- // Process `#[cfg_attr]`.
209
- fn process_cfg_attr ( diagnostic : & Handler , krate : ast:: Crate ,
210
- feature_gated_cfgs : & mut Vec < GatedCfgAttr > ) -> ast:: Crate {
211
- let mut fld = CfgAttrFolder {
212
- diag : CfgDiagReal {
213
- diag : diagnostic,
214
- feature_gated_cfgs : feature_gated_cfgs,
215
- } ,
216
- config : & krate. config . clone ( ) ,
217
- } ;
218
- fld. fold_crate ( krate)
219
- }
220
-
221
- impl < ' a , T : CfgDiag > fold:: Folder for CfgAttrFolder < ' a , T > {
222
- fn fold_attribute ( & mut self , attr : ast:: Attribute ) -> Option < ast:: Attribute > {
223
- if !attr. check_name ( "cfg_attr" ) {
224
- return fold:: noop_fold_attribute ( attr, self ) ;
225
- }
226
-
227
- let attr_list = match attr. meta_item_list ( ) {
228
- Some ( attr_list) => attr_list,
229
- None => {
230
- self . diag . emit_error ( |diag| {
231
- diag. span_err ( attr. span ,
232
- "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ) ;
233
- } ) ;
234
- return None ;
235
- }
236
- } ;
237
- let ( cfg, mi) = match ( attr_list. len ( ) , attr_list. get ( 0 ) , attr_list. get ( 1 ) ) {
238
- ( 2 , Some ( cfg) , Some ( mi) ) => ( cfg, mi) ,
239
- _ => {
240
- self . diag . emit_error ( |diag| {
241
- diag. span_err ( attr. span ,
242
- "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ) ;
243
- } ) ;
244
- return None ;
245
- }
246
- } ;
247
-
248
- if attr:: cfg_matches ( & self . config [ ..] , & cfg, & mut self . diag ) {
249
- Some ( respan ( mi. span , ast:: Attribute_ {
250
- id : attr:: mk_attr_id ( ) ,
251
- style : attr. node . style ,
252
- value : mi. clone ( ) ,
253
- is_sugared_doc : false ,
254
- } ) )
255
- } else {
256
- None
257
- }
258
- }
259
-
260
- // Need the ability to run pre-expansion.
261
- fn fold_mac ( & mut self , mac : ast:: Mac ) -> ast:: Mac {
262
- fold:: noop_fold_mac ( mac, self )
263
- }
264
- }
265
-
266
- fn check_for_gated_stmt_expr_attributes ( krate : & ast:: Crate ,
267
- discovered : & mut Vec < GatedCfgAttr > ) {
268
- let mut v = StmtExprAttrFeatureVisitor {
269
- config : & krate. config ,
270
- discovered : discovered,
271
- } ;
272
- visit:: walk_crate ( & mut v, krate) ;
273
- }
274
-
275
- /// To cover this feature, we need to discover all attributes
276
- /// so we need to run before cfg.
277
- struct StmtExprAttrFeatureVisitor < ' a , ' b > {
278
- config : & ' a ast:: CrateConfig ,
279
- discovered : & ' b mut Vec < GatedCfgAttr > ,
280
- }
281
-
282
- // Runs the cfg_attr and cfg folders locally in "silent" mode
283
- // to discover attribute use on stmts or expressions ahead of time
284
- impl < ' v , ' a , ' b > visit:: Visitor < ' v > for StmtExprAttrFeatureVisitor < ' a , ' b > {
285
- fn visit_stmt ( & mut self , s : & ' v ast:: Stmt ) {
286
- // check if there even are any attributes on this node
287
- let stmt_attrs = s. node . attrs ( ) ;
288
- if stmt_attrs. len ( ) > 0 {
289
- // attributes on items are fine
290
- if let ast:: StmtKind :: Decl ( ref decl, _) = s. node {
291
- if let ast:: DeclKind :: Item ( _) = decl. node {
292
- visit:: walk_stmt ( self , s) ;
293
- return ;
294
- }
295
- }
296
-
297
- // flag the offending attributes
298
- for attr in stmt_attrs {
299
- self . discovered . push ( GatedCfgAttr :: GatedAttr ( attr. span ) ) ;
300
- }
301
-
302
- // if the node does not end up being cfg-d away, walk down
303
- if node_survives_cfg ( stmt_attrs, self . config ) {
304
- visit:: walk_stmt ( self , s) ;
305
- }
306
- } else {
307
- visit:: walk_stmt ( self , s) ;
308
- }
309
- }
310
-
311
- fn visit_expr ( & mut self , ex : & ' v ast:: Expr ) {
312
- // check if there even are any attributes on this node
313
- let expr_attrs = ex. attrs ( ) ;
314
- if expr_attrs. len ( ) > 0 {
315
-
316
- // flag the offending attributes
317
- for attr in expr_attrs {
318
- self . discovered . push ( GatedCfgAttr :: GatedAttr ( attr. span ) ) ;
319
- }
320
-
321
- // if the node does not end up being cfg-d away, walk down
322
- if node_survives_cfg ( expr_attrs, self . config ) {
323
- visit:: walk_expr ( self , ex) ;
324
- }
325
- } else {
326
- visit:: walk_expr ( self , ex) ;
327
- }
328
- }
329
-
330
- fn visit_foreign_item ( & mut self , i : & ' v ast:: ForeignItem ) {
331
- if node_survives_cfg ( & i. attrs , self . config ) {
332
- visit:: walk_foreign_item ( self , i) ;
333
- }
334
- }
335
-
336
- fn visit_item ( & mut self , i : & ' v ast:: Item ) {
337
- if node_survives_cfg ( & i. attrs , self . config ) {
338
- visit:: walk_item ( self , i) ;
339
- }
340
- }
341
-
342
- fn visit_impl_item ( & mut self , ii : & ' v ast:: ImplItem ) {
343
- if node_survives_cfg ( & ii. attrs , self . config ) {
344
- visit:: walk_impl_item ( self , ii) ;
345
- }
346
- }
347
-
348
- fn visit_trait_item ( & mut self , ti : & ' v ast:: TraitItem ) {
349
- if node_survives_cfg ( & ti. attrs , self . config ) {
350
- visit:: walk_trait_item ( self , ti) ;
351
- }
352
- }
353
-
354
- fn visit_struct_field ( & mut self , s : & ' v ast:: StructField ) {
355
- if node_survives_cfg ( & s. attrs , self . config ) {
356
- visit:: walk_struct_field ( self , s) ;
357
- }
358
- }
359
-
360
- fn visit_variant ( & mut self , v : & ' v ast:: Variant ,
361
- g : & ' v ast:: Generics , item_id : ast:: NodeId ) {
362
- if node_survives_cfg ( & v. node . attrs , self . config ) {
363
- visit:: walk_variant ( self , v, g, item_id) ;
364
- }
365
- }
366
-
367
- fn visit_arm ( & mut self , a : & ' v ast:: Arm ) {
368
- if node_survives_cfg ( & a. attrs , self . config ) {
369
- visit:: walk_arm ( self , a) ;
370
- }
371
- }
372
-
373
- // This visitor runs pre expansion, so we need to prevent
374
- // the default panic here
375
- fn visit_mac ( & mut self , mac : & ' v ast:: Mac ) {
376
- visit:: walk_mac ( self , mac)
377
- }
378
- }
379
-
380
256
pub trait CfgDiag {
381
257
fn emit_error < F > ( & mut self , f : F ) where F : FnMut ( & Handler ) ;
382
258
fn flag_gated < F > ( & mut self , f : F ) where F : FnMut ( & mut Vec < GatedCfgAttr > ) ;
@@ -395,41 +271,3 @@ impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
395
271
f ( self . feature_gated_cfgs )
396
272
}
397
273
}
398
-
399
- struct CfgDiagSilent {
400
- error : bool ,
401
- }
402
-
403
- impl CfgDiag for CfgDiagSilent {
404
- fn emit_error < F > ( & mut self , _: F ) where F : FnMut ( & Handler ) {
405
- self . error = true ;
406
- }
407
- fn flag_gated < F > ( & mut self , _: F ) where F : FnMut ( & mut Vec < GatedCfgAttr > ) { }
408
- }
409
-
410
- fn node_survives_cfg ( attrs : & [ ast:: Attribute ] ,
411
- config : & ast:: CrateConfig ) -> bool {
412
- let mut survives_cfg = true ;
413
-
414
- for attr in attrs {
415
- let mut fld = CfgAttrFolder {
416
- diag : CfgDiagSilent { error : false } ,
417
- config : config,
418
- } ;
419
- let attr = fld. fold_attribute ( attr. clone ( ) ) ;
420
-
421
- // In case of error we can just return true,
422
- // since the actual cfg folders will end compilation anyway.
423
-
424
- if fld. diag . error { return true ; }
425
-
426
- survives_cfg &= attr. map ( |attr| {
427
- let mut diag = CfgDiagSilent { error : false } ;
428
- let r = in_cfg ( config, & [ attr] , & mut diag) ;
429
- if diag. error { return true ; }
430
- r
431
- } ) . unwrap_or ( true )
432
- }
433
-
434
- survives_cfg
435
- }
0 commit comments