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