@@ -73,49 +73,76 @@ impl<'a> StripUnconfigured<'a> {
7373 if self . in_cfg ( node. attrs ( ) ) { Some ( node) } else { None }
7474 }
7575
76+ /// Parse and expand all `cfg_attr` attributes into a list of attributes
77+ /// that are within each `cfg_attr` that has a true configuration predicate.
78+ ///
79+ /// Gives compiler warnigns if any `cfg_attr` does not contain any
80+ /// attributes and is in the original source code. Gives compiler errors if
81+ /// the syntax of any `cfg_attr` is incorrect.
7682 pub fn process_cfg_attrs < T : HasAttrs > ( & mut self , node : T ) -> T {
7783 node. map_attrs ( |attrs| {
78- attrs. into_iter ( ) . filter_map ( |attr| self . process_cfg_attr ( attr) ) . collect ( )
84+ attrs. into_iter ( ) . flat_map ( |attr| self . process_cfg_attr ( attr) ) . collect ( )
7985 } )
8086 }
8187
82- fn process_cfg_attr ( & mut self , attr : ast:: Attribute ) -> Option < ast:: Attribute > {
88+ /// Parse and expand a single `cfg_attr` attribute into a list of attributes
89+ /// when the configuration predicate is true, or otherwise expand into an
90+ /// empty list of attributes.
91+ ///
92+ /// Gives a compiler warning when the `cfg_attr` contains no attribtes and
93+ /// is in the original source file. Gives a compiler error if the syntax of
94+ /// the attribute is incorrect
95+ fn process_cfg_attr ( & mut self , attr : ast:: Attribute ) -> Vec < ast:: Attribute > {
8396 if !attr. check_name ( "cfg_attr" ) {
84- return Some ( attr) ;
97+ return vec ! [ attr] ;
8598 }
8699
87- let ( cfg , path , tokens , span ) = match attr. parse ( self . sess , |parser| {
100+ let ( cfg_predicate , expanded_attrs ) = match attr. parse ( self . sess , |parser| {
88101 parser. expect ( & token:: OpenDelim ( token:: Paren ) ) ?;
89- let cfg = parser. parse_meta_item ( ) ?;
102+
103+ let cfg_predicate = parser. parse_meta_item ( ) ?;
90104 parser. expect ( & token:: Comma ) ?;
91- let lo = parser. span . lo ( ) ;
92- let ( path, tokens) = parser. parse_meta_item_unrestricted ( ) ?;
93- parser. eat ( & token:: Comma ) ; // Optional trailing comma
105+
106+ // Presumably, the majority of the time there will only be one attr.
107+ let mut expanded_attrs = Vec :: with_capacity ( 1 ) ;
108+
109+ while !parser. check ( & token:: CloseDelim ( token:: Paren ) ) {
110+ let lo = parser. span . lo ( ) ;
111+ let ( path, tokens) = parser. parse_meta_item_unrestricted ( ) ?;
112+ expanded_attrs. push ( ( path, tokens, parser. prev_span . with_lo ( lo) ) ) ;
113+ parser. expect_one_of ( & [ token:: Comma ] , & [ token:: CloseDelim ( token:: Paren ) ] ) ?;
114+ }
115+
94116 parser. expect ( & token:: CloseDelim ( token:: Paren ) ) ?;
95- Ok ( ( cfg , path , tokens , parser . prev_span . with_lo ( lo ) ) )
117+ Ok ( ( cfg_predicate , expanded_attrs ) )
96118 } ) {
97119 Ok ( result) => result,
98120 Err ( mut e) => {
99121 e. emit ( ) ;
100- return None ;
122+ return Vec :: new ( ) ;
101123 }
102124 } ;
103125
104- if attr:: cfg_matches ( & cfg, self . sess , self . features ) {
105- self . process_cfg_attr ( ast:: Attribute {
126+ if attr:: cfg_matches ( & cfg_predicate, self . sess , self . features ) {
127+ // We call `process_cfg_attr` recursively in case there's a
128+ // `cfg_attr` inside of another `cfg_attr`. E.g.
129+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
130+ expanded_attrs. into_iter ( )
131+ . flat_map ( |( path, tokens, span) | self . process_cfg_attr ( ast:: Attribute {
106132 id : attr:: mk_attr_id ( ) ,
107133 style : attr. style ,
108134 path,
109135 tokens,
110136 is_sugared_doc : false ,
111137 span,
112- } )
138+ } ) )
139+ . collect ( )
113140 } else {
114- None
141+ Vec :: new ( )
115142 }
116143 }
117144
118- // Determine if a node with the given attributes should be included in this configuration.
145+ /// Determine if a node with the given attributes should be included in this configuration.
119146 pub fn in_cfg ( & mut self , attrs : & [ ast:: Attribute ] ) -> bool {
120147 attrs. iter ( ) . all ( |attr| {
121148 if !is_cfg ( attr) {
@@ -165,7 +192,7 @@ impl<'a> StripUnconfigured<'a> {
165192 } )
166193 }
167194
168- // Visit attributes on expression and statements (but not attributes on items in blocks).
195+ /// Visit attributes on expression and statements (but not attributes on items in blocks).
169196 fn visit_expr_attrs ( & mut self , attrs : & [ ast:: Attribute ] ) {
170197 // flag the offending attributes
171198 for attr in attrs. iter ( ) {
0 commit comments