1
1
//! Conditional compilation stripping.
2
2
3
+ use std:: iter;
4
+
3
5
use rustc_ast:: ptr:: P ;
4
6
use rustc_ast:: token:: { Delimiter , Token , TokenKind } ;
5
7
use rustc_ast:: tokenstream:: {
6
8
AttrTokenStream , AttrTokenTree , LazyAttrTokenStream , Spacing , TokenTree ,
7
9
} ;
8
10
use 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 ,
10
13
} ;
11
14
use rustc_attr_parsing as attr;
12
15
use rustc_data_structures:: flat_map_in_place:: FlatMapInPlace ;
@@ -275,10 +278,23 @@ impl<'a> StripUnconfigured<'a> {
275
278
pub ( crate ) fn expand_cfg_attr ( & self , cfg_attr : & Attribute , recursive : bool ) -> Vec < Attribute > {
276
279
validate_attr:: check_attribute_safety ( & self . sess . psess , AttributeSafety :: Normal , & cfg_attr) ;
277
280
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
+
278
294
let Some ( ( cfg_predicate, expanded_attrs) ) =
279
295
rustc_parse:: parse_cfg_attr ( cfg_attr, & self . sess . psess )
280
296
else {
281
- return vec ! [ ] ;
297
+ return vec ! [ trace_attr ] ;
282
298
} ;
283
299
284
300
// Lint on zero attributes in source.
@@ -292,22 +308,21 @@ impl<'a> StripUnconfigured<'a> {
292
308
}
293
309
294
310
if !attr:: cfg_matches ( & cfg_predicate, & self . sess , self . lint_node_id , self . features ) {
295
- return vec ! [ ] ;
311
+ return vec ! [ trace_attr ] ;
296
312
}
297
313
298
314
if recursive {
299
315
// We call `process_cfg_attr` recursively in case there's a
300
316
// `cfg_attr` inside of another `cfg_attr`. E.g.
301
317
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
302
- expanded_attrs
318
+ let expanded_attrs = expanded_attrs
303
319
. 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 ( )
306
322
} 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 ( )
311
326
}
312
327
}
313
328
0 commit comments