9
9
// except according to those terms.
10
10
11
11
use attr:: { AttrMetaMethods , HasAttrs } ;
12
- use errors:: Handler ;
13
- use feature_gate:: GatedCfgAttr ;
12
+ use feature_gate:: { emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX , Features , get_features, GateIssue } ;
14
13
use fold:: Folder ;
15
14
use { ast, fold, attr} ;
16
15
use codemap:: { Spanned , respan} ;
17
- use parse:: token;
16
+ use parse:: { ParseSess , token} ;
18
17
use ptr:: P ;
19
18
20
19
use util:: small_vector:: SmallVector ;
21
20
22
21
/// A folder that strips out items that do not belong in the current configuration.
23
22
pub struct StripUnconfigured < ' a > {
24
- diag : CfgDiagReal < ' a , ' a > ,
25
- should_test : bool ,
26
- config : & ' a ast:: CrateConfig ,
23
+ pub config : & ' a ast:: CrateConfig ,
24
+ pub should_test : bool ,
25
+ pub sess : & ' a ParseSess ,
26
+ pub features : Option < & ' a Features > ,
27
27
}
28
28
29
29
impl < ' a > StripUnconfigured < ' a > {
30
- pub fn new ( config : & ' a ast:: CrateConfig ,
31
- should_test : bool ,
32
- diagnostic : & ' a Handler ,
33
- feature_gated_cfgs : & ' a mut Vec < GatedCfgAttr > )
34
- -> Self {
35
- StripUnconfigured {
36
- config : config,
37
- should_test : should_test,
38
- diag : CfgDiagReal { diag : diagnostic, feature_gated_cfgs : feature_gated_cfgs } ,
39
- }
40
- }
41
-
42
30
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
43
31
let node = self . process_cfg_attrs ( node) ;
44
32
if self . in_cfg ( node. attrs ( ) ) { Some ( node) } else { None }
@@ -59,20 +47,20 @@ impl<'a> StripUnconfigured<'a> {
59
47
Some ( attr_list) => attr_list,
60
48
None => {
61
49
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ;
62
- self . diag . diag . span_err ( attr. span , msg) ;
50
+ self . sess . span_diagnostic . span_err ( attr. span , msg) ;
63
51
return None ;
64
52
}
65
53
} ;
66
54
let ( cfg, mi) = match ( attr_list. len ( ) , attr_list. get ( 0 ) , attr_list. get ( 1 ) ) {
67
55
( 2 , Some ( cfg) , Some ( mi) ) => ( cfg, mi) ,
68
56
_ => {
69
57
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`" ;
70
- self . diag . diag . span_err ( attr. span , msg) ;
58
+ self . sess . span_diagnostic . span_err ( attr. span , msg) ;
71
59
return None ;
72
60
}
73
61
} ;
74
62
75
- if attr:: cfg_matches ( self . config , & cfg, & mut self . diag ) {
63
+ if attr:: cfg_matches ( self . config , & cfg, self . sess , self . features ) {
76
64
self . process_cfg_attr ( respan ( mi. span , ast:: Attribute_ {
77
65
id : attr:: mk_attr_id ( ) ,
78
66
style : attr. node . style ,
@@ -98,41 +86,55 @@ impl<'a> StripUnconfigured<'a> {
98
86
} ;
99
87
100
88
if mis. len ( ) != 1 {
101
- self . diag . emit_error ( |diagnostic| {
102
- diagnostic. span_err ( attr. span , "expected 1 cfg-pattern" ) ;
103
- } ) ;
89
+ self . sess . span_diagnostic . span_err ( attr. span , "expected 1 cfg-pattern" ) ;
104
90
return true ;
105
91
}
106
92
107
- attr:: cfg_matches ( self . config , & mis[ 0 ] , & mut self . diag )
93
+ attr:: cfg_matches ( self . config , & mis[ 0 ] , self . sess , self . features )
108
94
} )
109
95
}
110
96
111
97
// Visit attributes on expression and statements (but not attributes on items in blocks).
112
98
fn visit_stmt_or_expr_attrs ( & mut self , attrs : & [ ast:: Attribute ] ) {
113
99
// flag the offending attributes
114
100
for attr in attrs. iter ( ) {
115
- self . diag . feature_gated_cfgs . push ( GatedCfgAttr :: GatedAttr ( attr. span ) ) ;
116
- }
117
- }
118
-
119
- // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
120
- fn visit_unremovable_expr ( & mut self , expr : & ast:: Expr ) {
121
- if let Some ( attr) = expr. attrs ( ) . iter ( ) . find ( |a| is_cfg ( a) || is_test_or_bench ( a) ) {
122
- let msg = "removing an expression is not supported in this position" ;
123
- self . diag . diag . span_err ( attr. span , msg) ;
101
+ if !self . features . map ( |features| features. stmt_expr_attributes ) . unwrap_or ( true ) {
102
+ emit_feature_err ( & self . sess . span_diagnostic ,
103
+ "stmt_expr_attributes" ,
104
+ attr. span ,
105
+ GateIssue :: Language ,
106
+ EXPLAIN_STMT_ATTR_SYNTAX ) ;
107
+ }
124
108
}
125
109
}
126
110
}
127
111
128
112
// Support conditional compilation by transforming the AST, stripping out
129
113
// any items that do not belong in the current configuration
130
- pub fn strip_unconfigured_items ( diagnostic : & Handler , krate : ast:: Crate , should_test : bool ,
131
- feature_gated_cfgs : & mut Vec < GatedCfgAttr > )
132
- -> ast:: Crate
133
- {
134
- let config = & krate. config . clone ( ) ;
135
- StripUnconfigured :: new ( config, should_test, diagnostic, feature_gated_cfgs) . fold_crate ( krate)
114
+ pub fn strip_unconfigured_items ( mut krate : ast:: Crate , sess : & ParseSess , should_test : bool )
115
+ -> ( ast:: Crate , Features ) {
116
+ let features;
117
+ {
118
+ let mut strip_unconfigured = StripUnconfigured {
119
+ config : & krate. config . clone ( ) ,
120
+ should_test : should_test,
121
+ sess : sess,
122
+ features : None ,
123
+ } ;
124
+
125
+ let err_count = sess. span_diagnostic . err_count ( ) ;
126
+ let krate_attrs = strip_unconfigured. process_cfg_attrs ( krate. attrs . clone ( ) ) ;
127
+ features = get_features ( & sess. span_diagnostic , & krate_attrs) ;
128
+ if err_count < sess. span_diagnostic . err_count ( ) {
129
+ krate. attrs = krate_attrs. clone ( ) ; // Avoid reconfiguring malformed `cfg_attr`s
130
+ }
131
+
132
+ strip_unconfigured. features = Some ( & features) ;
133
+ krate = strip_unconfigured. fold_crate ( krate) ;
134
+ krate. attrs = krate_attrs;
135
+ }
136
+
137
+ ( krate, features)
136
138
}
137
139
138
140
impl < ' a > fold:: Folder for StripUnconfigured < ' a > {
@@ -188,14 +190,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
188
190
189
191
fn fold_expr ( & mut self , expr : P < ast:: Expr > ) -> P < ast:: Expr > {
190
192
self . visit_stmt_or_expr_attrs ( expr. attrs ( ) ) ;
193
+
191
194
// If an expr is valid to cfg away it will have been removed by the
192
195
// outer stmt or expression folder before descending in here.
193
196
// Anything else is always required, and thus has to error out
194
197
// in case of a cfg attr.
195
198
//
196
199
// NB: This is intentionally not part of the fold_expr() function
197
200
// in order for fold_opt_expr() to be able to avoid this check
198
- self . visit_unremovable_expr ( & expr) ;
201
+ if let Some ( attr) = expr. attrs ( ) . iter ( ) . find ( |a| is_cfg ( a) || is_test_or_bench ( a) ) {
202
+ let msg = "removing an expression is not supported in this position" ;
203
+ self . sess . span_diagnostic . span_err ( attr. span , msg) ;
204
+ }
205
+
199
206
let expr = self . process_cfg_attrs ( expr) ;
200
207
fold_expr ( self , expr)
201
208
}
@@ -273,22 +280,3 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
273
280
fn is_test_or_bench ( attr : & ast:: Attribute ) -> bool {
274
281
attr. check_name ( "test" ) || attr. check_name ( "bench" )
275
282
}
276
-
277
- pub trait CfgDiag {
278
- fn emit_error < F > ( & mut self , f : F ) where F : FnMut ( & Handler ) ;
279
- fn flag_gated < F > ( & mut self , f : F ) where F : FnMut ( & mut Vec < GatedCfgAttr > ) ;
280
- }
281
-
282
- pub struct CfgDiagReal < ' a , ' b > {
283
- pub diag : & ' a Handler ,
284
- pub feature_gated_cfgs : & ' b mut Vec < GatedCfgAttr > ,
285
- }
286
-
287
- impl < ' a , ' b > CfgDiag for CfgDiagReal < ' a , ' b > {
288
- fn emit_error < F > ( & mut self , mut f : F ) where F : FnMut ( & Handler ) {
289
- f ( self . diag )
290
- }
291
- fn flag_gated < F > ( & mut self , mut f : F ) where F : FnMut ( & mut Vec < GatedCfgAttr > ) {
292
- f ( self . feature_gated_cfgs )
293
- }
294
- }
0 commit comments