99// except according to those terms.
1010
1111use 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 } ;
1413use fold:: Folder ;
1514use { ast, fold, attr} ;
1615use codemap:: { Spanned , respan} ;
17- use parse:: token;
16+ use parse:: { ParseSess , token} ;
1817use ptr:: P ;
1918
2019use util:: small_vector:: SmallVector ;
2120
2221/// A folder that strips out items that do not belong in the current configuration.
2322pub 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 > ,
2727}
2828
2929impl < ' 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-
4230 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
4331 let node = self . process_cfg_attrs ( node) ;
4432 if self . in_cfg ( node. attrs ( ) ) { Some ( node) } else { None }
@@ -59,20 +47,20 @@ impl<'a> StripUnconfigured<'a> {
5947 Some ( attr_list) => attr_list,
6048 None => {
6149 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) ;
6351 return None ;
6452 }
6553 } ;
6654 let ( cfg, mi) = match ( attr_list. len ( ) , attr_list. get ( 0 ) , attr_list. get ( 1 ) ) {
6755 ( 2 , Some ( cfg) , Some ( mi) ) => ( cfg, mi) ,
6856 _ => {
6957 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) ;
7159 return None ;
7260 }
7361 } ;
7462
75- if attr:: cfg_matches ( self . config , & cfg, & mut self . diag ) {
63+ if attr:: cfg_matches ( self . config , & cfg, self . sess , self . features ) {
7664 self . process_cfg_attr ( respan ( mi. span , ast:: Attribute_ {
7765 id : attr:: mk_attr_id ( ) ,
7866 style : attr. node . style ,
@@ -98,41 +86,55 @@ impl<'a> StripUnconfigured<'a> {
9886 } ;
9987
10088 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" ) ;
10490 return true ;
10591 }
10692
107- attr:: cfg_matches ( self . config , & mis[ 0 ] , & mut self . diag )
93+ attr:: cfg_matches ( self . config , & mis[ 0 ] , self . sess , self . features )
10894 } )
10995 }
11096
11197 // Visit attributes on expression and statements (but not attributes on items in blocks).
11298 fn visit_stmt_or_expr_attrs ( & mut self , attrs : & [ ast:: Attribute ] ) {
11399 // flag the offending attributes
114100 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+ }
124108 }
125109 }
126110}
127111
128112// Support conditional compilation by transforming the AST, stripping out
129113// 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)
136138}
137139
138140impl < ' a > fold:: Folder for StripUnconfigured < ' a > {
@@ -188,14 +190,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
188190
189191 fn fold_expr ( & mut self , expr : P < ast:: Expr > ) -> P < ast:: Expr > {
190192 self . visit_stmt_or_expr_attrs ( expr. attrs ( ) ) ;
193+
191194 // If an expr is valid to cfg away it will have been removed by the
192195 // outer stmt or expression folder before descending in here.
193196 // Anything else is always required, and thus has to error out
194197 // in case of a cfg attr.
195198 //
196199 // NB: This is intentionally not part of the fold_expr() function
197200 // 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+
199206 let expr = self . process_cfg_attrs ( expr) ;
200207 fold_expr ( self , expr)
201208 }
@@ -273,22 +280,3 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
273280fn is_test_or_bench ( attr : & ast:: Attribute ) -> bool {
274281 attr. check_name ( "test" ) || attr. check_name ( "bench" )
275282}
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