@@ -124,8 +124,13 @@ pub fn parse_cfgspecs(
124
124
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
125
125
pub fn parse_check_cfg ( handler : & EarlyErrorHandler , specs : Vec < String > ) -> CheckCfg {
126
126
rustc_span:: create_default_session_if_not_set_then ( move |_| {
127
- let mut check_cfg = CheckCfg :: default ( ) ;
127
+ // If any --check-cfg is passed then exhaustive_values and exhaustive_names
128
+ // are enabled by default.
129
+ let exhaustive_names = !specs. is_empty ( ) ;
130
+ let exhaustive_values = !specs. is_empty ( ) ;
131
+ let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg :: default ( ) } ;
128
132
133
+ let mut old_syntax = None ;
129
134
for s in specs {
130
135
let sess = ParseSess :: with_silent_emitter ( Some ( format ! (
131
136
"this error occurred on the command line: `--check-cfg={s}`"
@@ -141,18 +146,21 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
141
146
} ;
142
147
}
143
148
144
- let expected_error = || {
145
- error ! (
146
- "expected `names(name1, name2, ... nameN)` or \
147
- `values(name, \" value1\" , \" value2\" , ... \" valueN\" )`"
148
- )
149
- } ;
149
+ let expected_error =
150
+ || error ! ( "expected `cfg(name, values(\" value1\" , \" value2\" , ... \" valueN\" ))`" ) ;
150
151
151
152
match maybe_new_parser_from_source_str ( & sess, filename, s. to_string ( ) ) {
152
153
Ok ( mut parser) => match parser. parse_meta_item ( ) {
153
154
Ok ( meta_item) if parser. token == token:: Eof => {
154
155
if let Some ( args) = meta_item. meta_item_list ( ) {
155
156
if meta_item. has_name ( sym:: names) {
157
+ // defaults are flipped for the old syntax
158
+ if old_syntax == None {
159
+ check_cfg. exhaustive_names = false ;
160
+ check_cfg. exhaustive_values = false ;
161
+ }
162
+ old_syntax = Some ( true ) ;
163
+
156
164
check_cfg. exhaustive_names = true ;
157
165
for arg in args {
158
166
if arg. is_word ( ) && arg. ident ( ) . is_some ( ) {
@@ -166,6 +174,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
166
174
}
167
175
}
168
176
} else if meta_item. has_name ( sym:: values) {
177
+ // defaults are flipped for the old syntax
178
+ if old_syntax == None {
179
+ check_cfg. exhaustive_names = false ;
180
+ check_cfg. exhaustive_values = false ;
181
+ }
182
+ old_syntax = Some ( true ) ;
183
+
169
184
if let Some ( ( name, values) ) = args. split_first ( ) {
170
185
if name. is_word ( ) && name. ident ( ) . is_some ( ) {
171
186
let ident = name. ident ( ) . expect ( "multi-segment cfg key" ) ;
@@ -215,6 +230,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
215
230
} else {
216
231
expected_error ( ) ;
217
232
}
233
+ } else if meta_item. has_name ( sym:: cfg) {
234
+ old_syntax = Some ( false ) ;
235
+
236
+ let mut names = Vec :: new ( ) ;
237
+ let mut values: FxHashSet < _ > = Default :: default ( ) ;
238
+
239
+ let mut any_specified = false ;
240
+ let mut values_specified = false ;
241
+ let mut values_any_specified = false ;
242
+
243
+ for arg in args {
244
+ if arg. is_word ( ) && let Some ( ident) = arg. ident ( ) {
245
+ if values_specified {
246
+ error ! ( "`cfg()` names cannot be after values" ) ;
247
+ }
248
+ names. push ( ident) ;
249
+ } else if arg. has_name ( sym:: any)
250
+ && let Some ( args) = arg. meta_item_list ( )
251
+ {
252
+ if any_specified {
253
+ error ! ( "`any()` cannot be specified multiple times" ) ;
254
+ }
255
+ any_specified = true ;
256
+ if !args. is_empty ( ) {
257
+ error ! ( "`any()` must be empty" ) ;
258
+ }
259
+ } else if arg. has_name ( sym:: values)
260
+ && let Some ( args) = arg. meta_item_list ( )
261
+ {
262
+ if names. is_empty ( ) {
263
+ error ! (
264
+ "`values()` cannot be specified before the names"
265
+ ) ;
266
+ } else if values_specified {
267
+ error ! (
268
+ "`values()` cannot be specified multiple times"
269
+ ) ;
270
+ }
271
+ values_specified = true ;
272
+
273
+ for arg in args {
274
+ if let Some ( LitKind :: Str ( s, _) ) =
275
+ arg. lit ( ) . map ( |lit| & lit. kind )
276
+ {
277
+ values. insert ( Some ( s. to_string ( ) ) ) ;
278
+ } else if arg. has_name ( sym:: any)
279
+ && let Some ( args) = arg. meta_item_list ( )
280
+ {
281
+ if values_any_specified {
282
+ error ! (
283
+ "`any()` in `values()` cannot be specified multiple times"
284
+ ) ;
285
+ }
286
+ values_any_specified = true ;
287
+ if !args. is_empty ( ) {
288
+ error ! ( "`any()` must be empty" ) ;
289
+ }
290
+ } else {
291
+ error ! (
292
+ "`values()` arguments must be string literals or `any()`"
293
+ ) ;
294
+ }
295
+ }
296
+ } else {
297
+ error ! (
298
+ "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"
299
+ ) ;
300
+ }
301
+ }
302
+
303
+ if values. is_empty ( ) && !values_any_specified && !any_specified {
304
+ values. insert ( None ) ;
305
+ } else if !values. is_empty ( ) && values_any_specified {
306
+ error ! (
307
+ "`values()` arguments cannot specify string literals and `any()` at the same time"
308
+ ) ;
309
+ }
310
+
311
+ if any_specified {
312
+ if !names. is_empty ( )
313
+ || !values. is_empty ( )
314
+ || values_any_specified
315
+ {
316
+ error ! ( "`cfg(any())` can only be provided in isolation" ) ;
317
+ }
318
+
319
+ check_cfg. exhaustive_names = false ;
320
+ } else {
321
+ for name in names {
322
+ check_cfg
323
+ . expecteds
324
+ . entry ( name. to_string ( ) )
325
+ . and_modify ( |v| match v {
326
+ ExpectedValues :: Some ( v)
327
+ if !values_any_specified =>
328
+ {
329
+ v. extend ( values. clone ( ) )
330
+ }
331
+ ExpectedValues :: Some ( _) => * v = ExpectedValues :: Any ,
332
+ ExpectedValues :: Any => { }
333
+ } )
334
+ . or_insert_with ( || {
335
+ if values_any_specified {
336
+ ExpectedValues :: Any
337
+ } else {
338
+ ExpectedValues :: Some ( values. clone ( ) )
339
+ }
340
+ } ) ;
341
+ }
342
+ }
218
343
} else {
219
344
expected_error ( ) ;
220
345
}
0 commit comments