8
8
//!
9
9
//! [#64197]: https://github.com/rust-lang/rust/issues/64197
10
10
11
- use crate :: validate_attr;
11
+ use crate :: { parse_in , validate_attr} ;
12
12
use rustc_feature:: Features ;
13
13
use rustc_errors:: Applicability ;
14
14
use syntax:: attr:: HasAttrs ;
15
15
use syntax:: feature_gate:: { feature_err, get_features} ;
16
16
use syntax:: attr;
17
- use syntax:: ast;
17
+ use syntax:: ast:: { self , Attribute , AttrItem , MetaItem } ;
18
18
use syntax:: edition:: Edition ;
19
19
use syntax:: mut_visit:: * ;
20
20
use syntax:: ptr:: P ;
21
21
use syntax:: sess:: ParseSess ;
22
22
use syntax:: util:: map_in_place:: MapInPlace ;
23
+ use syntax_pos:: Span ;
23
24
use syntax_pos:: symbol:: sym;
24
25
25
26
use smallvec:: SmallVec ;
@@ -72,6 +73,11 @@ macro_rules! configure {
72
73
}
73
74
}
74
75
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
+
75
81
impl < ' a > StripUnconfigured < ' a > {
76
82
pub fn configure < T : HasAttrs > ( & mut self , mut node : T ) -> Option < T > {
77
83
self . process_cfg_attrs ( & mut node) ;
@@ -97,34 +103,14 @@ impl<'a> StripUnconfigured<'a> {
97
103
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
98
104
/// is in the original source file. Gives a compiler error if the syntax of
99
105
/// 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 > {
101
107
if !attr. has_name ( sym:: cfg_attr) {
102
108
return vec ! [ attr] ;
103
109
}
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
- }
120
110
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,
128
114
} ;
129
115
130
116
// Lint on zero attributes in source.
@@ -135,24 +121,56 @@ impl<'a> StripUnconfigured<'a> {
135
121
// At this point we know the attribute is considered used.
136
122
attr:: mark_used ( & attr) ;
137
123
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
+ } )
148
137
. 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 ) ,
151
154
}
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 ( ) ;
152
170
}
153
171
154
172
/// 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 {
156
174
attrs. iter ( ) . all ( |attr| {
157
175
if !is_cfg ( attr) {
158
176
return true ;
@@ -199,15 +217,15 @@ impl<'a> StripUnconfigured<'a> {
199
217
}
200
218
201
219
/// 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 ] ) {
203
221
// flag the offending attributes
204
222
for attr in attrs. iter ( ) {
205
223
self . maybe_emit_expr_attr_err ( attr) ;
206
224
}
207
225
}
208
226
209
227
/// 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 ) {
211
229
if !self . features . map ( |features| features. stmt_expr_attributes ) . unwrap_or ( true ) {
212
230
let mut err = feature_err ( self . sess ,
213
231
sym:: stmt_expr_attributes,
@@ -350,7 +368,7 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
350
368
}
351
369
}
352
370
353
- fn is_cfg ( attr : & ast :: Attribute ) -> bool {
371
+ fn is_cfg ( attr : & Attribute ) -> bool {
354
372
attr. check_name ( sym:: cfg)
355
373
}
356
374
@@ -359,8 +377,8 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
359
377
pub fn process_configure_mod (
360
378
sess : & ParseSess ,
361
379
cfg_mods : bool ,
362
- attrs : & [ ast :: Attribute ] ,
363
- ) -> ( bool , Vec < ast :: Attribute > ) {
380
+ attrs : & [ Attribute ] ,
381
+ ) -> ( bool , Vec < Attribute > ) {
364
382
// Don't perform gated feature checking.
365
383
let mut strip_unconfigured = StripUnconfigured { sess, features : None } ;
366
384
let mut attrs = attrs. to_owned ( ) ;
0 commit comments