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> {
275278 pub ( 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