88//!
99//! [#64197]: https://github.com/rust-lang/rust/issues/64197
1010
11- use crate :: validate_attr;
11+ use crate :: { parse_in , validate_attr} ;
1212use rustc_feature:: Features ;
1313use rustc_errors:: Applicability ;
1414use syntax:: attr:: HasAttrs ;
1515use syntax:: feature_gate:: { feature_err, get_features} ;
1616use syntax:: attr;
17- use syntax:: ast;
17+ use syntax:: ast:: { self , Attribute , AttrItem , MetaItem } ;
1818use syntax:: edition:: Edition ;
1919use syntax:: mut_visit:: * ;
2020use syntax:: ptr:: P ;
2121use syntax:: sess:: ParseSess ;
2222use syntax:: util:: map_in_place:: MapInPlace ;
23+ use syntax_pos:: Span ;
2324use syntax_pos:: symbol:: sym;
2425
2526use smallvec:: SmallVec ;
@@ -72,6 +73,11 @@ macro_rules! configure {
7273 }
7374}
7475
76+ const CFG_ATTR_GRAMMAR_HELP : & str = "#[cfg_attr(condition, attribute, other_attribute, ...)]" ;
77+ const CFG_ATTR_NOTE_REF : & str = "for more information, visit \
78+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
79+ #the-cfg_attr-attribute>";
80+
7581impl < ' a > StripUnconfigured < ' a > {
7682 pub fn configure < T : HasAttrs > ( & mut self , mut node : T ) -> Option < T > {
7783 self . process_cfg_attrs ( & mut node) ;
@@ -97,34 +103,14 @@ impl<'a> StripUnconfigured<'a> {
97103 /// Gives a compiler warning when the `cfg_attr` contains no attributes and
98104 /// is in the original source file. Gives a compiler error if the syntax of
99105 /// the attribute is incorrect.
100- fn process_cfg_attr ( & mut self , attr : ast :: Attribute ) -> Vec < ast :: Attribute > {
106+ fn process_cfg_attr ( & mut self , attr : Attribute ) -> Vec < Attribute > {
101107 if !attr. has_name ( sym:: cfg_attr) {
102108 return vec ! [ attr] ;
103109 }
104- if let ast:: MacArgs :: Empty = attr. get_normal_item ( ) . args {
105- self . sess . span_diagnostic
106- . struct_span_err (
107- attr. span ,
108- "malformed `cfg_attr` attribute input" ,
109- ) . span_suggestion (
110- attr. span ,
111- "missing condition and attribute" ,
112- "#[cfg_attr(condition, attribute, other_attribute, ...)]" . to_owned ( ) ,
113- Applicability :: HasPlaceholders ,
114- ) . note ( "for more information, visit \
115- <https://doc.rust-lang.org/reference/conditional-compilation.html\
116- #the-cfg_attr-attribute>")
117- . emit ( ) ;
118- return vec ! [ ] ;
119- }
120110
121- let res = crate :: parse_in_attr ( self . sess , & attr, |p| p. parse_cfg_attr ( ) ) ;
122- let ( cfg_predicate, expanded_attrs) = match res {
123- Ok ( result) => result,
124- Err ( mut e) => {
125- e. emit ( ) ;
126- return vec ! [ ] ;
127- }
111+ let ( cfg_predicate, expanded_attrs) = match self . parse_cfg_attr ( & attr) {
112+ None => return vec ! [ ] ,
113+ Some ( r) => r,
128114 } ;
129115
130116 // Lint on zero attributes in source.
@@ -135,24 +121,56 @@ impl<'a> StripUnconfigured<'a> {
135121 // At this point we know the attribute is considered used.
136122 attr:: mark_used ( & attr) ;
137123
138- if attr:: cfg_matches ( & cfg_predicate, self . sess , self . features ) {
139- // We call `process_cfg_attr` recursively in case there's a
140- // `cfg_attr` inside of another `cfg_attr`. E.g.
141- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
142- expanded_attrs. into_iter ( )
143- . flat_map ( |( item, span) | self . process_cfg_attr ( attr:: mk_attr_from_item (
144- attr. style ,
145- item,
146- span,
147- ) ) )
124+ if !attr:: cfg_matches ( & cfg_predicate, self . sess , self . features ) {
125+ return vec ! [ ] ;
126+ }
127+
128+ // We call `process_cfg_attr` recursively in case there's a
129+ // `cfg_attr` inside of another `cfg_attr`. E.g.
130+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
131+ expanded_attrs
132+ . into_iter ( )
133+ . flat_map ( |( item, span) | {
134+ let attr = attr:: mk_attr_from_item ( attr. style , item, span) ;
135+ self . process_cfg_attr ( attr)
136+ } )
148137 . collect ( )
149- } else {
150- vec ! [ ]
138+ }
139+
140+ fn parse_cfg_attr ( & self , attr : & Attribute ) -> Option < ( MetaItem , Vec < ( AttrItem , Span ) > ) > {
141+ match attr. get_normal_item ( ) . args {
142+ ast:: MacArgs :: Delimited ( dspan, delim, ref tts) if !tts. is_empty ( ) => {
143+ let msg = "wrong `cfg_attr` delimiters" ;
144+ validate_attr:: check_meta_bad_delim ( self . sess , dspan, delim, msg) ;
145+ match parse_in ( self . sess , tts. clone ( ) , "`cfg_attr` input" , |p| p. parse_cfg_attr ( ) ) {
146+ Ok ( r) => return Some ( r) ,
147+ Err ( mut e) => e
148+ . help ( & format ! ( "the valid syntax is `{}`" , CFG_ATTR_GRAMMAR_HELP ) )
149+ . note ( CFG_ATTR_NOTE_REF )
150+ . emit ( ) ,
151+ }
152+ }
153+ _ => self . error_malformed_cfg_attr_missing ( attr. span ) ,
151154 }
155+ None
156+ }
157+
158+ fn error_malformed_cfg_attr_missing ( & self , span : Span ) {
159+ self . sess
160+ . span_diagnostic
161+ . struct_span_err ( span, "malformed `cfg_attr` attribute input" )
162+ . span_suggestion (
163+ span,
164+ "missing condition and attribute" ,
165+ CFG_ATTR_GRAMMAR_HELP . to_string ( ) ,
166+ Applicability :: HasPlaceholders ,
167+ )
168+ . note ( CFG_ATTR_NOTE_REF )
169+ . emit ( ) ;
152170 }
153171
154172 /// Determines if a node with the given attributes should be included in this configuration.
155- pub fn in_cfg ( & self , attrs : & [ ast :: Attribute ] ) -> bool {
173+ pub fn in_cfg ( & self , attrs : & [ Attribute ] ) -> bool {
156174 attrs. iter ( ) . all ( |attr| {
157175 if !is_cfg ( attr) {
158176 return true ;
@@ -199,15 +217,15 @@ impl<'a> StripUnconfigured<'a> {
199217 }
200218
201219 /// Visit attributes on expression and statements (but not attributes on items in blocks).
202- fn visit_expr_attrs ( & mut self , attrs : & [ ast :: Attribute ] ) {
220+ fn visit_expr_attrs ( & mut self , attrs : & [ Attribute ] ) {
203221 // flag the offending attributes
204222 for attr in attrs. iter ( ) {
205223 self . maybe_emit_expr_attr_err ( attr) ;
206224 }
207225 }
208226
209227 /// If attributes are not allowed on expressions, emit an error for `attr`
210- pub fn maybe_emit_expr_attr_err ( & self , attr : & ast :: Attribute ) {
228+ pub fn maybe_emit_expr_attr_err ( & self , attr : & Attribute ) {
211229 if !self . features . map ( |features| features. stmt_expr_attributes ) . unwrap_or ( true ) {
212230 let mut err = feature_err ( self . sess ,
213231 sym:: stmt_expr_attributes,
@@ -350,7 +368,7 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
350368 }
351369}
352370
353- fn is_cfg ( attr : & ast :: Attribute ) -> bool {
371+ fn is_cfg ( attr : & Attribute ) -> bool {
354372 attr. check_name ( sym:: cfg)
355373}
356374
@@ -359,8 +377,8 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
359377pub fn process_configure_mod (
360378 sess : & ParseSess ,
361379 cfg_mods : bool ,
362- attrs : & [ ast :: Attribute ] ,
363- ) -> ( bool , Vec < ast :: Attribute > ) {
380+ attrs : & [ Attribute ] ,
381+ ) -> ( bool , Vec < Attribute > ) {
364382 // Don't perform gated feature checking.
365383 let mut strip_unconfigured = StripUnconfigured { sess, features : None } ;
366384 let mut attrs = attrs. to_owned ( ) ;
0 commit comments