@@ -125,8 +125,13 @@ pub fn parse_cfgspecs(
125125/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
126126pub fn parse_check_cfg ( handler : & EarlyErrorHandler , specs : Vec < String > ) -> CheckCfg {
127127 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 ( ) } ;
129133
134+ let mut old_syntax = None ;
130135 for s in specs {
131136 let sess = ParseSess :: with_silent_emitter ( Some ( format ! (
132137 "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
142147 } ;
143148 }
144149
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\" ))`" ) ;
151152
152153 match maybe_new_parser_from_source_str ( & sess, filename, s. to_string ( ) ) {
153154 Ok ( mut parser) => match parser. parse_meta_item ( ) {
154155 Ok ( meta_item) if parser. token == token:: Eof => {
155156 if let Some ( args) = meta_item. meta_item_list ( ) {
156157 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+
157165 check_cfg. exhaustive_names = true ;
158166 for arg in args {
159167 if arg. is_word ( ) && arg. ident ( ) . is_some ( ) {
@@ -167,6 +175,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
167175 }
168176 }
169177 } 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+
170185 if let Some ( ( name, values) ) = args. split_first ( ) {
171186 if name. is_word ( ) && name. ident ( ) . is_some ( ) {
172187 let ident = name. ident ( ) . expect ( "multi-segment cfg key" ) ;
@@ -216,6 +231,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check
216231 } else {
217232 expected_error ( ) ;
218233 }
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+ }
219344 } else {
220345 expected_error ( ) ;
221346 }
0 commit comments