@@ -321,6 +321,95 @@ pub macro debug_assert_matches($($arg:tt)*) {
321
321
}
322
322
}
323
323
324
+ /// A macro for defining `#[cfg]` match-like statements.
325
+ ///
326
+ /// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
327
+ /// `#[cfg]` cases, emitting the implementation which matches first.
328
+ ///
329
+ /// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
330
+ /// without having to rewrite each clause multiple times.
331
+ ///
332
+ /// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when
333
+ /// all previous declarations do not evaluate to true.
334
+ ///
335
+ /// # Example
336
+ ///
337
+ /// ```
338
+ /// #![feature(cfg_match)]
339
+ ///
340
+ /// cfg_match! {
341
+ /// cfg(unix) => {
342
+ /// fn foo() { /* unix specific functionality */ }
343
+ /// }
344
+ /// cfg(target_pointer_width = "32") => {
345
+ /// fn foo() { /* non-unix, 32-bit functionality */ }
346
+ /// }
347
+ /// _ => {
348
+ /// fn foo() { /* fallback implementation */ }
349
+ /// }
350
+ /// }
351
+ /// ```
352
+ #[ macro_export]
353
+ #[ unstable( feature = "cfg_match" , issue = "115585" ) ]
354
+ #[ rustc_diagnostic_item = "cfg_match" ]
355
+ macro_rules! cfg_match {
356
+ // with a final wildcard
357
+ (
358
+ $( cfg( $initial_meta: meta) => { $( $initial_tokens: item) * } ) +
359
+ _ => { $( $extra_tokens: item) * }
360
+ ) => {
361
+ cfg_match! {
362
+ @__items ( ) ;
363
+ $( ( ( $initial_meta) ( $( $initial_tokens) * ) ) , ) +
364
+ ( ( ) ( $( $extra_tokens) * ) ) ,
365
+ }
366
+ } ;
367
+
368
+ // without a final wildcard
369
+ (
370
+ $( cfg( $extra_meta: meta) => { $( $extra_tokens: item) * } ) *
371
+ ) => {
372
+ cfg_match! {
373
+ @__items ( ) ;
374
+ $( ( ( $extra_meta) ( $( $extra_tokens) * ) ) , ) *
375
+ }
376
+ } ;
377
+
378
+ // Internal and recursive macro to emit all the items
379
+ //
380
+ // Collects all the previous cfgs in a list at the beginning, so they can be
381
+ // negated. After the semicolon is all the remaining items.
382
+ ( @__items ( $( $_: meta, ) * ) ; ) => { } ;
383
+ (
384
+ @__items ( $( $no: meta, ) * ) ;
385
+ ( ( $( $yes: meta) ?) ( $( $tokens: item) * ) ) ,
386
+ $( $rest: tt, ) *
387
+ ) => {
388
+ // Emit all items within one block, applying an appropriate #[cfg]. The
389
+ // #[cfg] will require all `$yes` matchers specified and must also negate
390
+ // all previous matchers.
391
+ #[ cfg( all(
392
+ $( $yes, ) ?
393
+ not( any( $( $no) ,* ) )
394
+ ) ) ]
395
+ cfg_match! { @__identity $( $tokens) * }
396
+
397
+ // Recurse to emit all other items in `$rest`, and when we do so add all
398
+ // our `$yes` matchers to the list of `$no` matchers as future emissions
399
+ // will have to negate everything we just matched as well.
400
+ cfg_match! {
401
+ @__items ( $( $no, ) * $( $yes, ) ?) ;
402
+ $( $rest, ) *
403
+ }
404
+ } ;
405
+
406
+ // Internal macro to make __apply work out right for different match types,
407
+ // because of how macros match/expand stuff.
408
+ ( @__identity $( $tokens: item) * ) => {
409
+ $( $tokens) *
410
+ } ;
411
+ }
412
+
324
413
/// Returns whether the given expression matches any of the given patterns.
325
414
///
326
415
/// Like in a `match` expression, the pattern can be optionally followed by `if`
0 commit comments