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
+ use syntax:: tokenstream:: DelimSpan ;
21
22
use syntax:: sess:: ParseSess ;
22
23
use syntax:: util:: map_in_place:: MapInPlace ;
24
+ use syntax_pos:: Span ;
23
25
use syntax_pos:: symbol:: sym;
24
26
25
27
use smallvec:: SmallVec ;
@@ -72,6 +74,11 @@ macro_rules! configure {
72
74
}
73
75
}
74
76
77
+ const CFG_ATTR_GRAMMAR_HELP : & str = "#[cfg_attr(condition, attribute, other_attribute, ...)]" ;
78
+ const CFG_ATTR_NOTE_REF : & str = "for more information, visit \
79
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
80
+ #the-cfg_attr-attribute>";
81
+
75
82
impl < ' a > StripUnconfigured < ' a > {
76
83
pub fn configure < T : HasAttrs > ( & mut self , mut node : T ) -> Option < T > {
77
84
self . process_cfg_attrs ( & mut node) ;
@@ -97,34 +104,14 @@ impl<'a> StripUnconfigured<'a> {
97
104
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
98
105
/// is in the original source file. Gives a compiler error if the syntax of
99
106
/// the attribute is incorrect.
100
- fn process_cfg_attr ( & mut self , attr : ast :: Attribute ) -> Vec < ast :: Attribute > {
107
+ fn process_cfg_attr ( & mut self , attr : Attribute ) -> Vec < Attribute > {
101
108
if !attr. has_name ( sym:: cfg_attr) {
102
109
return vec ! [ attr] ;
103
110
}
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
111
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
- }
112
+ let ( cfg_predicate, expanded_attrs) = match self . parse_cfg_attr ( & attr) {
113
+ None => return vec ! [ ] ,
114
+ Some ( r) => r,
128
115
} ;
129
116
130
117
// Lint on zero attributes in source.
@@ -135,24 +122,72 @@ impl<'a> StripUnconfigured<'a> {
135
122
// At this point we know the attribute is considered used.
136
123
attr:: mark_used ( & attr) ;
137
124
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
- ) ) )
125
+ if !attr:: cfg_matches ( & cfg_predicate, self . sess , self . features ) {
126
+ return vec ! [ ] ;
127
+ }
128
+
129
+ // We call `process_cfg_attr` recursively in case there's a
130
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
131
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
132
+ expanded_attrs
133
+ . into_iter ( )
134
+ . flat_map ( |( item, span) | {
135
+ let attr = attr:: mk_attr_from_item ( attr. style , item, span) ;
136
+ self . process_cfg_attr ( attr)
137
+ } )
148
138
. collect ( )
149
- } else {
150
- vec ! [ ]
139
+ }
140
+
141
+ fn parse_cfg_attr ( & self , attr : & Attribute ) -> Option < ( MetaItem , Vec < ( AttrItem , Span ) > ) > {
142
+ match & attr. get_normal_item ( ) . args {
143
+ ast:: MacArgs :: Delimited ( dspan, delim, tts) if !tts. is_empty ( ) => {
144
+ if let ast:: MacDelimiter :: Brace | ast:: MacDelimiter :: Bracket = delim {
145
+ self . error_malformed_cfg_attr_wrong_delim ( * dspan) ;
146
+ }
147
+ match parse_in ( self . sess , tts. clone ( ) , "`cfg_attr` input" , |p| p. parse_cfg_attr ( ) ) {
148
+ Ok ( r) => return Some ( r) ,
149
+ Err ( mut e) => e
150
+ . help ( & format ! ( "the valid syntax is `{}`" , CFG_ATTR_GRAMMAR_HELP ) )
151
+ . note ( CFG_ATTR_NOTE_REF )
152
+ . emit ( ) ,
153
+ }
154
+ }
155
+ _ => self . error_malformed_cfg_attr_missing ( attr. span ) ,
151
156
}
157
+ None
158
+ }
159
+
160
+ fn error_malformed_cfg_attr_wrong_delim ( & self , dspan : DelimSpan ) {
161
+ self . sess
162
+ . span_diagnostic
163
+ . struct_span_err ( dspan. entire ( ) , "wrong `cfg_attr` delimiters" )
164
+ . multipart_suggestion (
165
+ "the delimiters should be `(` and `)`" ,
166
+ vec ! [
167
+ ( dspan. open, "(" . to_string( ) ) ,
168
+ ( dspan. close, ")" . to_string( ) ) ,
169
+ ] ,
170
+ Applicability :: MachineApplicable ,
171
+ )
172
+ . emit ( ) ;
173
+ }
174
+
175
+ fn error_malformed_cfg_attr_missing ( & self , span : Span ) {
176
+ self . sess
177
+ . span_diagnostic
178
+ . struct_span_err ( span, "malformed `cfg_attr` attribute input" )
179
+ . span_suggestion (
180
+ span,
181
+ "missing condition and attribute" ,
182
+ CFG_ATTR_GRAMMAR_HELP . to_string ( ) ,
183
+ Applicability :: HasPlaceholders ,
184
+ )
185
+ . note ( CFG_ATTR_NOTE_REF )
186
+ . emit ( ) ;
152
187
}
153
188
154
189
/// Determines if a node with the given attributes should be included in this configuration.
155
- pub fn in_cfg ( & self , attrs : & [ ast :: Attribute ] ) -> bool {
190
+ pub fn in_cfg ( & self , attrs : & [ Attribute ] ) -> bool {
156
191
attrs. iter ( ) . all ( |attr| {
157
192
if !is_cfg ( attr) {
158
193
return true ;
@@ -199,15 +234,15 @@ impl<'a> StripUnconfigured<'a> {
199
234
}
200
235
201
236
/// Visit attributes on expression and statements (but not attributes on items in blocks).
202
- fn visit_expr_attrs ( & mut self , attrs : & [ ast :: Attribute ] ) {
237
+ fn visit_expr_attrs ( & mut self , attrs : & [ Attribute ] ) {
203
238
// flag the offending attributes
204
239
for attr in attrs. iter ( ) {
205
240
self . maybe_emit_expr_attr_err ( attr) ;
206
241
}
207
242
}
208
243
209
244
/// If attributes are not allowed on expressions, emit an error for `attr`
210
- pub fn maybe_emit_expr_attr_err ( & self , attr : & ast :: Attribute ) {
245
+ pub fn maybe_emit_expr_attr_err ( & self , attr : & Attribute ) {
211
246
if !self . features . map ( |features| features. stmt_expr_attributes ) . unwrap_or ( true ) {
212
247
let mut err = feature_err ( self . sess ,
213
248
sym:: stmt_expr_attributes,
@@ -350,7 +385,7 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
350
385
}
351
386
}
352
387
353
- fn is_cfg ( attr : & ast :: Attribute ) -> bool {
388
+ fn is_cfg ( attr : & Attribute ) -> bool {
354
389
attr. check_name ( sym:: cfg)
355
390
}
356
391
@@ -359,8 +394,8 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
359
394
pub fn process_configure_mod (
360
395
sess : & ParseSess ,
361
396
cfg_mods : bool ,
362
- attrs : & [ ast :: Attribute ] ,
363
- ) -> ( bool , Vec < ast :: Attribute > ) {
397
+ attrs : & [ Attribute ] ,
398
+ ) -> ( bool , Vec < Attribute > ) {
364
399
// Don't perform gated feature checking.
365
400
let mut strip_unconfigured = StripUnconfigured { sess, features : None } ;
366
401
let mut attrs = attrs. to_owned ( ) ;
0 commit comments