@@ -328,18 +328,18 @@ impl<'a> StripUnconfigured<'a> {
328
328
} ) ;
329
329
}
330
330
331
+ fn process_cfg_attr ( & self , attr : Attribute ) -> Vec < Attribute > {
332
+ if attr. has_name ( sym:: cfg_attr) { self . expand_cfg_attr ( attr, true ) } else { vec ! [ attr] }
333
+ }
334
+
331
335
/// Parse and expand a single `cfg_attr` attribute into a list of attributes
332
336
/// when the configuration predicate is true, or otherwise expand into an
333
337
/// empty list of attributes.
334
338
///
335
339
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
336
340
/// is in the original source file. Gives a compiler error if the syntax of
337
341
/// the attribute is incorrect.
338
- fn process_cfg_attr ( & self , attr : Attribute ) -> Vec < Attribute > {
339
- if !attr. has_name ( sym:: cfg_attr) {
340
- return vec ! [ attr] ;
341
- }
342
-
342
+ crate fn expand_cfg_attr ( & self , attr : Attribute , recursive : bool ) -> Vec < Attribute > {
343
343
let ( cfg_predicate, expanded_attrs) =
344
344
match rustc_parse:: parse_cfg_attr ( & attr, & self . sess . parse_sess ) {
345
345
None => return vec ! [ ] ,
@@ -348,95 +348,109 @@ impl<'a> StripUnconfigured<'a> {
348
348
349
349
// Lint on zero attributes in source.
350
350
if expanded_attrs. is_empty ( ) {
351
- return vec ! [ attr] ;
351
+ self . sess . parse_sess . buffer_lint (
352
+ rustc_lint_defs:: builtin:: UNUSED_ATTRIBUTES ,
353
+ attr. span ,
354
+ ast:: CRATE_NODE_ID ,
355
+ "`#[cfg_attr]` does not expand to any attributes" ,
356
+ ) ;
352
357
}
353
358
354
359
if !attr:: cfg_matches ( & cfg_predicate, & self . sess . parse_sess , self . features ) {
355
360
return vec ! [ ] ;
356
361
}
357
362
358
- // We call `process_cfg_attr` recursively in case there's a
359
- // `cfg_attr` inside of another `cfg_attr`. E.g.
360
- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
361
- expanded_attrs
362
- . into_iter ( )
363
- . flat_map ( |( item, span) | {
364
- let orig_tokens = attr. tokens ( ) . to_tokenstream ( ) ;
365
-
366
- // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
367
- // and producing an attribute of the form `#[attr]`. We
368
- // have captured tokens for `attr` itself, but we need to
369
- // synthesize tokens for the wrapper `#` and `[]`, which
370
- // we do below.
371
-
372
- // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
373
- // for `attr` when we expand it to `#[attr]`
374
- let mut orig_trees = orig_tokens. trees ( ) ;
375
- let pound_token = match orig_trees. next ( ) . unwrap ( ) {
376
- TokenTree :: Token ( token @ Token { kind : TokenKind :: Pound , .. } ) => token,
377
- _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
378
- } ;
379
- let pound_span = pound_token. span ;
380
-
381
- let mut trees = vec ! [ ( AttrAnnotatedTokenTree :: Token ( pound_token) , Spacing :: Alone ) ] ;
382
- if attr. style == AttrStyle :: Inner {
383
- // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
384
- let bang_token = match orig_trees. next ( ) . unwrap ( ) {
385
- TokenTree :: Token ( token @ Token { kind : TokenKind :: Not , .. } ) => token,
386
- _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
387
- } ;
388
- trees. push ( ( AttrAnnotatedTokenTree :: Token ( bang_token) , Spacing :: Alone ) ) ;
389
- }
390
- // We don't really have a good span to use for the syntheized `[]`
391
- // in `#[attr]`, so just use the span of the `#` token.
392
- let bracket_group = AttrAnnotatedTokenTree :: Delimited (
393
- DelimSpan :: from_single ( pound_span) ,
394
- DelimToken :: Bracket ,
395
- item. tokens
396
- . as_ref ( )
397
- . unwrap_or_else ( || panic ! ( "Missing tokens for {:?}" , item) )
398
- . create_token_stream ( ) ,
399
- ) ;
400
- trees. push ( ( bracket_group, Spacing :: Alone ) ) ;
401
- let tokens = Some ( LazyTokenStream :: new ( AttrAnnotatedTokenStream :: new ( trees) ) ) ;
402
- let attr = attr:: mk_attr_from_item ( item, tokens, attr. style , span) ;
403
- if attr. has_name ( sym:: crate_type) {
404
- self . sess . parse_sess . buffer_lint (
405
- rustc_lint_defs:: builtin:: DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME ,
406
- attr. span ,
407
- ast:: CRATE_NODE_ID ,
408
- "`crate_type` within an `#![cfg_attr] attribute is deprecated`" ,
409
- ) ;
410
- }
411
- if attr. has_name ( sym:: crate_name) {
412
- self . sess . parse_sess . buffer_lint (
413
- rustc_lint_defs:: builtin:: DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME ,
414
- attr. span ,
415
- ast:: CRATE_NODE_ID ,
416
- "`crate_name` within an `#![cfg_attr] attribute is deprecated`" ,
417
- ) ;
418
- }
419
- self . process_cfg_attr ( attr)
420
- } )
421
- . collect ( )
363
+ if recursive {
364
+ // We call `process_cfg_attr` recursively in case there's a
365
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
366
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
367
+ expanded_attrs
368
+ . into_iter ( )
369
+ . flat_map ( |item| self . process_cfg_attr ( self . expand_cfg_attr_item ( & attr, item) ) )
370
+ . collect ( )
371
+ } else {
372
+ expanded_attrs. into_iter ( ) . map ( |item| self . expand_cfg_attr_item ( & attr, item) ) . collect ( )
373
+ }
374
+ }
375
+
376
+ fn expand_cfg_attr_item (
377
+ & self ,
378
+ attr : & Attribute ,
379
+ ( item, item_span) : ( ast:: AttrItem , Span ) ,
380
+ ) -> Attribute {
381
+ let orig_tokens = attr. tokens ( ) . to_tokenstream ( ) ;
382
+
383
+ // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
384
+ // and producing an attribute of the form `#[attr]`. We
385
+ // have captured tokens for `attr` itself, but we need to
386
+ // synthesize tokens for the wrapper `#` and `[]`, which
387
+ // we do below.
388
+
389
+ // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
390
+ // for `attr` when we expand it to `#[attr]`
391
+ let mut orig_trees = orig_tokens. trees ( ) ;
392
+ let pound_token = match orig_trees. next ( ) . unwrap ( ) {
393
+ TokenTree :: Token ( token @ Token { kind : TokenKind :: Pound , .. } ) => token,
394
+ _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
395
+ } ;
396
+ let pound_span = pound_token. span ;
397
+
398
+ let mut trees = vec ! [ ( AttrAnnotatedTokenTree :: Token ( pound_token) , Spacing :: Alone ) ] ;
399
+ if attr. style == AttrStyle :: Inner {
400
+ // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
401
+ let bang_token = match orig_trees. next ( ) . unwrap ( ) {
402
+ TokenTree :: Token ( token @ Token { kind : TokenKind :: Not , .. } ) => token,
403
+ _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
404
+ } ;
405
+ trees. push ( ( AttrAnnotatedTokenTree :: Token ( bang_token) , Spacing :: Alone ) ) ;
406
+ }
407
+ // We don't really have a good span to use for the syntheized `[]`
408
+ // in `#[attr]`, so just use the span of the `#` token.
409
+ let bracket_group = AttrAnnotatedTokenTree :: Delimited (
410
+ DelimSpan :: from_single ( pound_span) ,
411
+ DelimToken :: Bracket ,
412
+ item. tokens
413
+ . as_ref ( )
414
+ . unwrap_or_else ( || panic ! ( "Missing tokens for {:?}" , item) )
415
+ . create_token_stream ( ) ,
416
+ ) ;
417
+ trees. push ( ( bracket_group, Spacing :: Alone ) ) ;
418
+ let tokens = Some ( LazyTokenStream :: new ( AttrAnnotatedTokenStream :: new ( trees) ) ) ;
419
+ let attr = attr:: mk_attr_from_item ( item, tokens, attr. style , item_span) ;
420
+ if attr. has_name ( sym:: crate_type) {
421
+ self . sess . parse_sess . buffer_lint (
422
+ rustc_lint_defs:: builtin:: DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME ,
423
+ attr. span ,
424
+ ast:: CRATE_NODE_ID ,
425
+ "`crate_type` within an `#![cfg_attr] attribute is deprecated`" ,
426
+ ) ;
427
+ }
428
+ if attr. has_name ( sym:: crate_name) {
429
+ self . sess . parse_sess . buffer_lint (
430
+ rustc_lint_defs:: builtin:: DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME ,
431
+ attr. span ,
432
+ ast:: CRATE_NODE_ID ,
433
+ "`crate_name` within an `#![cfg_attr] attribute is deprecated`" ,
434
+ ) ;
435
+ }
436
+ attr
422
437
}
423
438
424
439
/// Determines if a node with the given attributes should be included in this configuration.
425
440
fn in_cfg ( & self , attrs : & [ Attribute ] ) -> bool {
426
- attrs. iter ( ) . all ( |attr| {
427
- if !is_cfg ( attr) {
441
+ attrs. iter ( ) . all ( |attr| !is_cfg ( attr) || self . cfg_true ( attr) )
442
+ }
443
+
444
+ crate fn cfg_true ( & self , attr : & Attribute ) -> bool {
445
+ let meta_item = match validate_attr:: parse_meta ( & self . sess . parse_sess , attr) {
446
+ Ok ( meta_item) => meta_item,
447
+ Err ( mut err) => {
448
+ err. emit ( ) ;
428
449
return true ;
429
450
}
430
- let meta_item = match validate_attr:: parse_meta ( & self . sess . parse_sess , attr) {
431
- Ok ( meta_item) => meta_item,
432
- Err ( mut err) => {
433
- err. emit ( ) ;
434
- return true ;
435
- }
436
- } ;
437
- parse_cfg ( & meta_item, & self . sess ) . map_or ( true , |meta_item| {
438
- attr:: cfg_matches ( & meta_item, & self . sess . parse_sess , self . features )
439
- } )
451
+ } ;
452
+ parse_cfg ( & meta_item, & self . sess ) . map_or ( true , |meta_item| {
453
+ attr:: cfg_matches ( & meta_item, & self . sess . parse_sess , self . features )
440
454
} )
441
455
}
442
456
0 commit comments