@@ -124,8 +124,13 @@ pub fn parse_cfgspecs(
124124/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
125125pub fn parse_check_cfg ( handler : & EarlyErrorHandler , specs : Vec < String > ) -> CheckCfg {
126126 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 ( ) } ;
128132
133+ let mut old_syntax = None ;
129134 for s in specs {
130135 let sess = ParseSess :: with_silent_emitter ( Some ( format ! (
131136 "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
141146 } ;
142147 }
143148
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\" ))`" ) ;
150151
151152 match maybe_new_parser_from_source_str ( & sess, filename, s. to_string ( ) ) {
152153 Ok ( mut parser) => match parser. parse_meta_item ( ) {
153154 Ok ( meta_item) if parser. token == token:: Eof => {
154155 if let Some ( args) = meta_item. meta_item_list ( ) {
155156 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+
156164 check_cfg. exhaustive_names = true ;
157165 for arg in args {
158166 if arg. is_word ( ) && arg. ident ( ) . is_some ( ) {
@@ -166,6 +174,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
166174 }
167175 }
168176 } 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+
169184 if let Some ( ( name, values) ) = args. split_first ( ) {
170185 if name. is_word ( ) && name. ident ( ) . is_some ( ) {
171186 let ident = name. ident ( ) . expect ( "multi-segment cfg key" ) ;
@@ -215,6 +230,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
215230 } else {
216231 expected_error ( ) ;
217232 }
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+ }
218343 } else {
219344 expected_error ( ) ;
220345 }
0 commit comments