@@ -415,6 +415,66 @@ impl<'a> StripUnconfigured<'a> {
415415 . collect ( )
416416 }
417417
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+
418478 fn parse_cfg_attr ( & self , attr : & Attribute ) -> Option < ( MetaItem , Vec < ( AttrItem , Span ) > ) > {
419479 match attr. get_normal_item ( ) . args {
420480 ast:: MacArgs :: Delimited ( dspan, delim, ref tts) if !tts. is_empty ( ) => {
@@ -453,43 +513,42 @@ impl<'a> StripUnconfigured<'a> {
453513
454514 /// Determines if a node with the given attributes should be included in this configuration.
455515 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 ( ) ;
458524 return true ;
459525 }
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+ ) ;
491536 }
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+ }
493552 }
494553
495554 /// If attributes are not allowed on expressions, emit an error for `attr`
0 commit comments