Skip to content

Commit 97f2005

Browse files
committed
Add unstable cfg_if! macro to libcore
1 parent d20e000 commit 97f2005

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

src/libcore/macros.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,89 @@ macro_rules! uninitialized_array {
635635
});
636636
}
637637

638+
/// A macro for defining `#[cfg]` if-else statements.
639+
///
640+
/// The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
641+
/// preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
642+
/// emitting the implementation which matches first.
643+
///
644+
/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
645+
/// without having to rewrite each clause multiple times.
646+
///
647+
/// # Example
648+
///
649+
/// ```
650+
/// #[macro_use]
651+
/// extern crate cfg_if;
652+
///
653+
/// cfg_if! {
654+
/// if #[cfg(unix)] {
655+
/// fn foo() { /* unix specific functionality */ }
656+
/// } else if #[cfg(target_pointer_width = "32")] {
657+
/// fn foo() { /* non-unix, 32-bit functionality */ }
658+
/// } else {
659+
/// fn foo() { /* fallback implementation */ }
660+
/// }
661+
/// }
662+
///
663+
/// # fn main() {}
664+
/// ```
665+
#[macro_export(local_inner_macros)]
666+
#[unstable(feature = "cfg_if", issue = "59442")]
667+
macro_rules! cfg_if {
668+
// match if/else chains with a final `else`
669+
($(
670+
if #[cfg($($meta:meta),*)] { $($it:item)* }
671+
) else * else {
672+
$($it2:item)*
673+
}) => {
674+
cfg_if! {
675+
@__items
676+
() ;
677+
$( ( ($($meta),*) ($($it)*) ), )*
678+
( () ($($it2)*) ),
679+
}
680+
};
681+
682+
// match if/else chains lacking a final `else`
683+
(
684+
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
685+
$(
686+
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
687+
)*
688+
) => {
689+
cfg_if! {
690+
@__items
691+
() ;
692+
( ($($i_met),*) ($($i_it)*) ),
693+
$( ( ($($e_met),*) ($($e_it)*) ), )*
694+
( () () ),
695+
}
696+
};
697+
698+
// Internal and recursive macro to emit all the items
699+
//
700+
// Collects all the negated cfgs in a list at the beginning and after the
701+
// semicolon is all the remaining items
702+
(@__items ($($not:meta,)*) ; ) => {};
703+
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
704+
// Emit all items within one block, applying an approprate #[cfg]. The
705+
// #[cfg] will require all `$m` matchers specified and must also negate
706+
// all previous matchers.
707+
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
708+
709+
// Recurse to emit all other items in `$rest`, and when we do so add all
710+
// our `$m` matchers to the list of `$not` matchers as future emissions
711+
// will have to negate everything we just matched as well.
712+
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
713+
};
714+
715+
// Internal macro to Apply a cfg attribute to a list of items
716+
(@__apply $m:meta, $($it:item)*) => {
717+
$(#[$m] $it)*
718+
};
719+
}
720+
638721
/// Built-in macros to the compiler itself.
639722
///
640723
/// These macros do not have any corresponding definition with a `macro_rules!`

src/libcore/tests/cfg_if.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![feature(cfg_if)]
2+
3+
cfg_if! {
4+
if #[cfg(test)] {
5+
use core::option::Option as Option2;
6+
fn works1() -> Option2<u32> { Some(1) }
7+
} else {
8+
fn works1() -> Option<u32> { None }
9+
}
10+
}
11+
12+
cfg_if! {
13+
if #[cfg(foo)] {
14+
fn works2() -> bool { false }
15+
} else if #[cfg(test)] {
16+
fn works2() -> bool { true }
17+
} else {
18+
fn works2() -> bool { false }
19+
}
20+
}
21+
22+
cfg_if! {
23+
if #[cfg(foo)] {
24+
fn works3() -> bool { false }
25+
} else {
26+
fn works3() -> bool { true }
27+
}
28+
}
29+
30+
cfg_if! {
31+
if #[cfg(test)] {
32+
use core::option::Option as Option3;
33+
fn works4() -> Option3<u32> { Some(1) }
34+
}
35+
}
36+
37+
cfg_if! {
38+
if #[cfg(foo)] {
39+
fn works5() -> bool { false }
40+
} else if #[cfg(test)] {
41+
fn works5() -> bool { true }
42+
}
43+
}
44+
45+
#[test]
46+
fn it_works() {
47+
assert!(works1().is_some());
48+
assert!(works2());
49+
assert!(works3());
50+
assert!(works4().is_some());
51+
assert!(works5());
52+
}

0 commit comments

Comments
 (0)