@@ -321,6 +321,92 @@ pub macro debug_assert_matches($($arg:tt)*) {
321321 }
322322}
323323
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+ /// # Example
333+ ///
334+ /// ```
335+ /// #![feature(cfg_match)]
336+ ///
337+ /// cfg_match! {
338+ /// cfg(unix) => {
339+ /// fn foo() { /* unix specific functionality */ }
340+ /// }
341+ /// cfg(target_pointer_width = "32") => {
342+ /// fn foo() { /* non-unix, 32-bit functionality */ }
343+ /// }
344+ /// _ => {
345+ /// fn foo() { /* fallback implementation */ }
346+ /// }
347+ /// }
348+ /// ```
349+ #[ macro_export]
350+ #[ unstable( feature = "cfg_match" , issue = "none" ) ]
351+ #[ rustc_diagnostic_item = "cfg_match" ]
352+ macro_rules! cfg_match {
353+ // with a final wildcard
354+ (
355+ $( cfg( $initial_meta: meta) => { $( $initial_tokens: item) * } ) +
356+ _ => { $( $extra_tokens: item) * }
357+ ) => {
358+ cfg_match! {
359+ @__items ( ) ;
360+ $( ( ( $initial_meta) ( $( $initial_tokens) * ) ) , ) +
361+ ( ( ) ( $( $extra_tokens) * ) ) ,
362+ }
363+ } ;
364+
365+ // without a final wildcard
366+ (
367+ $( cfg( $extra_meta: meta) => { $( $extra_tokens: item) * } ) *
368+ ) => {
369+ cfg_match! {
370+ @__items ( ) ;
371+ $( ( ( $extra_meta) ( $( $extra_tokens) * ) ) , ) *
372+ }
373+ } ;
374+
375+ // Internal and recursive macro to emit all the items
376+ //
377+ // Collects all the previous cfgs in a list at the beginning, so they can be
378+ // negated. After the semicolon is all the remaining items.
379+ ( @__items ( $( $_: meta, ) * ) ; ) => { } ;
380+ (
381+ @__items ( $( $no: meta, ) * ) ;
382+ ( ( $( $yes: meta) ?) ( $( $tokens: item) * ) ) ,
383+ $( $rest: tt, ) *
384+ ) => {
385+ // Emit all items within one block, applying an appropriate #[cfg]. The
386+ // #[cfg] will require all `$yes` matchers specified and must also negate
387+ // all previous matchers.
388+ #[ cfg( all(
389+ $( $yes, ) ?
390+ not( any( $( $no) ,* ) )
391+ ) ) ]
392+ cfg_match! { @__identity $( $tokens) * }
393+
394+ // Recurse to emit all other items in `$rest`, and when we do so add all
395+ // our `$yes` matchers to the list of `$no` matchers as future emissions
396+ // will have to negate everything we just matched as well.
397+ cfg_match! {
398+ @__items ( $( $no, ) * $( $yes, ) ?) ;
399+ $( $rest, ) *
400+ }
401+ } ;
402+
403+ // Internal macro to make __apply work out right for different match types,
404+ // because of how macros match/expand stuff.
405+ ( @__identity $( $tokens: item) * ) => {
406+ $( $tokens) *
407+ } ;
408+ }
409+
324410/// Returns whether the given expression matches any of the given patterns.
325411///
326412/// Like in a `match` expression, the pattern can be optionally followed by `if`
0 commit comments