@@ -415,6 +415,66 @@ impl<'a> StripUnconfigured<'a> {
415
415
. collect ( )
416
416
}
417
417
418
+ crate fn expand_cfg_attr ( & mut self , attr : Attribute ) -> Vec < Attribute > {
419
+ let ( cfg_predicate, expanded_attrs) = match self . parse_cfg_attr ( & attr) {
420
+ None => return vec ! [ ] ,
421
+ Some ( r) => r,
422
+ } ;
423
+
424
+ if !attr:: cfg_matches ( & cfg_predicate, & self . sess . parse_sess , self . features ) {
425
+ return vec ! [ ] ;
426
+ }
427
+
428
+ // We call `process_cfg_attr` recursively in case there's a
429
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
430
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
431
+ expanded_attrs
432
+ . into_iter ( )
433
+ . map ( |( item, span) | {
434
+ let orig_tokens = attr. tokens ( ) . to_tokenstream ( ) ;
435
+
436
+ // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
437
+ // and producing an attribute of the form `#[attr]`. We
438
+ // have captured tokens for `attr` itself, but we need to
439
+ // synthesize tokens for the wrapper `#` and `[]`, which
440
+ // we do below.
441
+
442
+ // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
443
+ // for `attr` when we expand it to `#[attr]`
444
+ let mut orig_trees = orig_tokens. trees ( ) ;
445
+ let pound_token = match orig_trees. next ( ) . unwrap ( ) {
446
+ TokenTree :: Token ( token @ Token { kind : TokenKind :: Pound , .. } ) => token,
447
+ _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
448
+ } ;
449
+ let pound_span = pound_token. span ;
450
+
451
+ let mut trees = vec ! [ ( AttrAnnotatedTokenTree :: Token ( pound_token) , Spacing :: Alone ) ] ;
452
+ if attr. style == AttrStyle :: Inner {
453
+ // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
454
+ let bang_token = match orig_trees. next ( ) . unwrap ( ) {
455
+ TokenTree :: Token ( token @ Token { kind : TokenKind :: Not , .. } ) => token,
456
+ _ => panic ! ( "Bad tokens for attribute {:?}" , attr) ,
457
+ } ;
458
+ trees. push ( ( AttrAnnotatedTokenTree :: Token ( bang_token) , Spacing :: Alone ) ) ;
459
+ }
460
+ // We don't really have a good span to use for the syntheized `[]`
461
+ // in `#[attr]`, so just use the span of the `#` token.
462
+ let bracket_group = AttrAnnotatedTokenTree :: Delimited (
463
+ DelimSpan :: from_single ( pound_span) ,
464
+ DelimToken :: Bracket ,
465
+ item. tokens
466
+ . as_ref ( )
467
+ . unwrap_or_else ( || panic ! ( "Missing tokens for {:?}" , item) )
468
+ . create_token_stream ( ) ,
469
+ ) ;
470
+ trees. push ( ( bracket_group, Spacing :: Alone ) ) ;
471
+ let tokens = Some ( LazyTokenStream :: new ( AttrAnnotatedTokenStream :: new ( trees) ) ) ;
472
+
473
+ attr:: mk_attr_from_item ( item, tokens, attr. style , span)
474
+ } )
475
+ . collect ( )
476
+ }
477
+
418
478
fn parse_cfg_attr ( & self , attr : & Attribute ) -> Option < ( MetaItem , Vec < ( AttrItem , Span ) > ) > {
419
479
match attr. get_normal_item ( ) . args {
420
480
ast:: MacArgs :: Delimited ( dspan, delim, ref tts) if !tts. is_empty ( ) => {
@@ -453,43 +513,42 @@ impl<'a> StripUnconfigured<'a> {
453
513
454
514
/// Determines if a node with the given attributes should be included in this configuration.
455
515
fn in_cfg ( & self , attrs : & [ Attribute ] ) -> bool {
456
- attrs. iter ( ) . all ( |attr| {
457
- if !is_cfg ( self . sess , attr) {
516
+ attrs. iter ( ) . all ( |attr| !is_cfg ( self . sess , attr) || self . cfg_true ( attr) )
517
+ }
518
+
519
+ crate fn cfg_true ( & self , attr : & Attribute ) -> bool {
520
+ let meta_item = match validate_attr:: parse_meta ( & self . sess . parse_sess , attr) {
521
+ Ok ( meta_item) => meta_item,
522
+ Err ( mut err) => {
523
+ err. emit ( ) ;
458
524
return true ;
459
525
}
460
- let meta_item = match validate_attr:: parse_meta ( & self . sess . parse_sess , attr) {
461
- Ok ( meta_item) => meta_item,
462
- Err ( mut err) => {
463
- err. emit ( ) ;
464
- return true ;
465
- }
466
- } ;
467
- let error = |span, msg, suggestion : & str | {
468
- let mut err = self . sess . parse_sess . span_diagnostic . struct_span_err ( span, msg) ;
469
- if !suggestion. is_empty ( ) {
470
- err. span_suggestion (
471
- span,
472
- "expected syntax is" ,
473
- suggestion. into ( ) ,
474
- Applicability :: MaybeIncorrect ,
475
- ) ;
476
- }
477
- err. emit ( ) ;
478
- true
479
- } ;
480
- let span = meta_item. span ;
481
- match meta_item. meta_item_list ( ) {
482
- None => error ( span, "`cfg` is not followed by parentheses" , "cfg(/* predicate */)" ) ,
483
- Some ( [ ] ) => error ( span, "`cfg` predicate is not specified" , "" ) ,
484
- Some ( [ _, .., l] ) => error ( l. span ( ) , "multiple `cfg` predicates are specified" , "" ) ,
485
- Some ( [ single] ) => match single. meta_item ( ) {
486
- Some ( meta_item) => {
487
- attr:: cfg_matches ( meta_item, & self . sess . parse_sess , self . features )
488
- }
489
- None => error ( single. span ( ) , "`cfg` predicate key cannot be a literal" , "" ) ,
490
- } ,
526
+ } ;
527
+ let error = |span, msg, suggestion : & str | {
528
+ let mut err = self . sess . parse_sess . span_diagnostic . struct_span_err ( span, msg) ;
529
+ if !suggestion. is_empty ( ) {
530
+ err. span_suggestion (
531
+ span,
532
+ "expected syntax is" ,
533
+ suggestion. into ( ) ,
534
+ Applicability :: MaybeIncorrect ,
535
+ ) ;
491
536
}
492
- } )
537
+ err. emit ( ) ;
538
+ true
539
+ } ;
540
+ let span = meta_item. span ;
541
+ match meta_item. meta_item_list ( ) {
542
+ None => error ( span, "`cfg` is not followed by parentheses" , "cfg(/* predicate */)" ) ,
543
+ Some ( [ ] ) => error ( span, "`cfg` predicate is not specified" , "" ) ,
544
+ Some ( [ _, .., l] ) => error ( l. span ( ) , "multiple `cfg` predicates are specified" , "" ) ,
545
+ Some ( [ single] ) => match single. meta_item ( ) {
546
+ Some ( meta_item) => {
547
+ attr:: cfg_matches ( meta_item, & self . sess . parse_sess , self . features )
548
+ }
549
+ None => error ( single. span ( ) , "`cfg` predicate key cannot be a literal" , "" ) ,
550
+ } ,
551
+ }
493
552
}
494
553
495
554
/// If attributes are not allowed on expressions, emit an error for `attr`
0 commit comments