@@ -328,18 +328,18 @@ impl<'a> StripUnconfigured<'a> {
328328 } ) ;
329329 }
330330
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+
331335 /// Parse and expand a single `cfg_attr` attribute into a list of attributes
332336 /// when the configuration predicate is true, or otherwise expand into an
333337 /// empty list of attributes.
334338 ///
335339 /// Gives a compiler warning when the `cfg_attr` contains no attributes and
336340 /// is in the original source file. Gives a compiler error if the syntax of
337341 /// 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 > {
343343 let ( cfg_predicate, expanded_attrs) =
344344 match rustc_parse:: parse_cfg_attr ( & attr, & self . sess . parse_sess ) {
345345 None => return vec ! [ ] ,
@@ -348,95 +348,109 @@ impl<'a> StripUnconfigured<'a> {
348348
349349 // Lint on zero attributes in source.
350350 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+ ) ;
352357 }
353358
354359 if !attr:: cfg_matches ( & cfg_predicate, & self . sess . parse_sess , self . features ) {
355360 return vec ! [ ] ;
356361 }
357362
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
422437 }
423438
424439 /// Determines if a node with the given attributes should be included in this configuration.
425440 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 ( ) ;
428449 return true ;
429450 }
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 )
440454 } )
441455 }
442456
0 commit comments