11//! Conditional compilation stripping. 
22
3+ use  std:: iter; 
4+ 
35use  rustc_ast:: ptr:: P ; 
46use  rustc_ast:: token:: { Delimiter ,  Token ,  TokenKind } ; 
57use  rustc_ast:: tokenstream:: { 
68    AttrTokenStream ,  AttrTokenTree ,  LazyAttrTokenStream ,  Spacing ,  TokenTree , 
79} ; 
810use  rustc_ast:: { 
9-     self  as  ast,  AttrStyle ,  Attribute ,  HasAttrs ,  HasTokens ,  MetaItem ,  MetaItemInner ,  NodeId , 
11+     self  as  ast,  AttrKind ,  AttrStyle ,  Attribute ,  HasAttrs ,  HasTokens ,  MetaItem ,  MetaItemInner , 
12+     NodeId ,  NormalAttr , 
1013} ; 
1114use  rustc_attr_parsing as  attr; 
1215use  rustc_data_structures:: flat_map_in_place:: FlatMapInPlace ; 
@@ -275,10 +278,23 @@ impl<'a> StripUnconfigured<'a> {
275278pub ( crate )  fn  expand_cfg_attr ( & self ,  cfg_attr :  & Attribute ,  recursive :  bool )  -> Vec < Attribute >  { 
276279        validate_attr:: check_attribute_safety ( & self . sess . psess ,  AttributeSafety :: Normal ,  & cfg_attr) ; 
277280
281+         // A trace attribute left in AST in place of the original `cfg_attr` attribute. 
282+         // It can later be used by lints or other diagnostics. 
283+         let  mut  trace_attr = cfg_attr. clone ( ) ; 
284+         match  & mut  trace_attr. kind  { 
285+             AttrKind :: Normal ( normal)  => { 
286+                 let  NormalAttr  {  item,  tokens }  = & mut  * * normal; 
287+                 item. path . segments [ 0 ] . ident . name  = sym:: cfg_attr_trace; 
288+                 // This makes the trace attributes unobservable to token-based proc macros. 
289+                 * tokens = Some ( LazyAttrTokenStream :: new ( AttrTokenStream :: default ( ) ) ) ; 
290+             } 
291+             AttrKind :: DocComment ( ..)  => unreachable ! ( ) , 
292+         } 
293+ 
278294        let  Some ( ( cfg_predicate,  expanded_attrs) )  =
279295            rustc_parse:: parse_cfg_attr ( cfg_attr,  & self . sess . psess ) 
280296        else  { 
281-             return  vec ! [ ] ; 
297+             return  vec ! [ trace_attr ] ; 
282298        } ; 
283299
284300        // Lint on zero attributes in source. 
@@ -292,22 +308,21 @@ impl<'a> StripUnconfigured<'a> {
292308        } 
293309
294310        if  !attr:: cfg_matches ( & cfg_predicate,  & self . sess ,  self . lint_node_id ,  self . features )  { 
295-             return  vec ! [ ] ; 
311+             return  vec ! [ trace_attr ] ; 
296312        } 
297313
298314        if  recursive { 
299315            // We call `process_cfg_attr` recursively in case there's a 
300316            // `cfg_attr` inside of another `cfg_attr`. E.g. 
301317            //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`. 
302-             expanded_attrs
318+             let  expanded_attrs =  expanded_attrs
303319                . into_iter ( ) 
304-                 . flat_map ( |item| self . process_cfg_attr ( & self . expand_cfg_attr_item ( cfg_attr,  item) ) ) 
305-                  . collect ( ) 
320+                 . flat_map ( |item| self . process_cfg_attr ( & self . expand_cfg_attr_item ( cfg_attr,  item) ) ) ; 
321+             iter :: once ( trace_attr ) . chain ( expanded_attrs ) . collect ( ) 
306322        }  else  { 
307-             expanded_attrs
308-                 . into_iter ( ) 
309-                 . map ( |item| self . expand_cfg_attr_item ( cfg_attr,  item) ) 
310-                 . collect ( ) 
323+             let  expanded_attrs =
324+                 expanded_attrs. into_iter ( ) . map ( |item| self . expand_cfg_attr_item ( cfg_attr,  item) ) ; 
325+             iter:: once ( trace_attr) . chain ( expanded_attrs) . collect ( ) 
311326        } 
312327    } 
313328
0 commit comments