Skip to content
Closed
7 changes: 4 additions & 3 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "core"
version = "0.0.0"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

Expand Down Expand Up @@ -2074,7 +2075,7 @@ name = "rand_chacha"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]

Expand All @@ -2096,7 +2097,7 @@ name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
Expand All @@ -2121,7 +2122,7 @@ name = "rand_xorshift"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
Expand Down
1 change: 1 addition & 0 deletions src/libcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ path = "../libcore/benches/lib.rs"

[dev-dependencies]
rand = "0.6"
cfg-if = "0.1"

[features]
# Make panics and failed asserts immediately abort without formatting any message
Expand Down
81 changes: 81 additions & 0 deletions src/libcore/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,87 @@ macro_rules! uninitialized_array {
});
}

/// A macro for defining `#[cfg]` if-else statements.
///
/// The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
/// preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
/// emitting the implementation which matches first.
///
/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
///
/// # Example
///
/// ```
/// # #![feature(cfg_if)]
/// cfg_if! {
/// if #[cfg(unix)] {
/// fn foo() { /* unix specific functionality */ }
/// } else if #[cfg(target_pointer_width = "32")] {
/// fn foo() { /* non-unix, 32-bit functionality */ }
/// } else {
/// fn foo() { /* fallback implementation */ }
/// }
/// }
///
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use $crate:: instead?

#[unstable(feature = "cfg_if", issue = "59442")]
macro_rules! cfg_if {
// match if/else chains with a final `else`
($(
if #[cfg($($meta:meta),*)] { $($it:item)* }
) else * else {
$($it2:item)*
}) => {
cfg_if! {
@__items
() ;
$( ( ($($meta),*) ($($it)*) ), )*
( () ($($it2)*) ),
}
};

// match if/else chains lacking a final `else`
(
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
$(
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
)*
) => {
cfg_if! {
@__items
() ;
( ($($i_met),*) ($($i_it)*) ),
$( ( ($($e_met),*) ($($e_it)*) ), )*
( () () ),
}
};

// Internal and recursive macro to emit all the items
//
// Collects all the negated cfgs in a list at the beginning and after the
// semicolon is all the remaining items
(@__items ($($not:meta,)*) ; ) => {};
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
// Emit all items within one block, applying an approprate #[cfg]. The
// #[cfg] will require all `$m` matchers specified and must also negate
// all previous matchers.
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }

// Recurse to emit all other items in `$rest`, and when we do so add all
// our `$m` matchers to the list of `$not` matchers as future emissions
// will have to negate everything we just matched as well.
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
};

// Internal macro to Apply a cfg attribute to a list of items
(@__apply $m:meta, $($it:item)*) => {
$(#[$m] $it)*
};
}

/// Built-in macros to the compiler itself.
///
/// These macros do not have any corresponding definition with a `macro_rules!`
Expand Down
52 changes: 52 additions & 0 deletions src/libcore/tests/cfg_if.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#![feature(cfg_if)]

cfg_if! {
if #[cfg(test)] {
use core::option::Option as Option2;
fn works1() -> Option2<u32> { Some(1) }
} else {
fn works1() -> Option<u32> { None }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works2() -> bool { false }
} else if #[cfg(test)] {
fn works2() -> bool { true }
} else {
fn works2() -> bool { false }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works3() -> bool { false }
} else {
fn works3() -> bool { true }
}
}

cfg_if! {
if #[cfg(test)] {
use core::option::Option as Option3;
fn works4() -> Option3<u32> { Some(1) }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works5() -> bool { false }
} else if #[cfg(test)] {
fn works5() -> bool { true }
}
}

#[test]
fn it_works() {
assert!(works1().is_some());
assert!(works2());
assert!(works3());
assert!(works4().is_some());
assert!(works5());
}
17 changes: 17 additions & 0 deletions src/libcore/tests/cfg_if_override.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! Test that overriding cfg_if with our own cfg_if macro does not break
//! anything.

macro_rules! cfg_if {
(()) => {
mod foo {
fn foo() {}
}
}
}

cfg_if!{}

#[test]
fn it_works() {
foo::foo();
}
55 changes: 55 additions & 0 deletions src/libcore/tests/cfg_if_stable_override.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! Test that using cfg_if from the cfg_if crate does not break anything.

#[macro_use(cfg_if)]
extern crate cfg_if;

cfg_if! {
if #[cfg(test)] {
use core::option::Option as Option2;
fn works1() -> Option2<u32> { Some(1) }
} else {
fn works1() -> Option<u32> { None }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works2() -> bool { false }
} else if #[cfg(test)] {
fn works2() -> bool { true }
} else {
fn works2() -> bool { false }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works3() -> bool { false }
} else {
fn works3() -> bool { true }
}
}

cfg_if! {
if #[cfg(test)] {
use core::option::Option as Option3;
fn works4() -> Option3<u32> { Some(1) }
}
}

cfg_if! {
if #[cfg(foo)] {
fn works5() -> bool { false }
} else if #[cfg(test)] {
fn works5() -> bool { true }
}
}

#[test]
fn it_works() {
assert!(works1().is_some());
assert!(works2());
assert!(works3());
assert!(works4().is_some());
assert!(works5());
}
5 changes: 5 additions & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
#![feature(bind_by_move_pattern_guards)]
#![feature(box_syntax)]
#![feature(c_variadic)]
#![feature(cfg_if)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_thread_local)]
#![feature(char_error_internals)]
Expand Down Expand Up @@ -326,6 +327,10 @@ pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::{unreachable, unimplemented, write, writeln, r#try, todo};

#[unstable(feature = "cfg_if", issue = "59442")]
pub use core::cfg_if;


#[allow(unused_imports)] // macros from `alloc` are not used on all platforms
#[macro_use]
extern crate alloc as alloc_crate;
Expand Down
36 changes: 0 additions & 36 deletions src/libstd/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,39 +943,3 @@ mod builtin {
($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ });
}
}

/// A macro for defining `#[cfg]` if-else statements.
///
/// This is similar to the `if/elif` C preprocessor macro by allowing definition
/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
/// first.
///
/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
macro_rules! cfg_if {
($(
if #[cfg($($meta:meta),*)] { $($it:item)* }
) else * else {
$($it2:item)*
}) => {
__cfg_if_items! {
() ;
$( ( ($($meta),*) ($($it)*) ), )*
( () ($($it2)*) ),
}
}
}

macro_rules! __cfg_if_items {
(($($not:meta,)*) ; ) => {};
(($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
__cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
__cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
}
}

macro_rules! __cfg_if_apply {
($m:meta, $($it:item)*) => {
$(#[$m] $it)*
}
}
15 changes: 15 additions & 0 deletions src/libstd/tests/cfg_if.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(cfg_if)]
pub use std::cfg_if;

cfg_if! {
if #[cfg(test)] {
fn foo() -> bool { true }
} else {
fn foo() -> bool { false }
}
}

#[test]
fn cfg_if_test() {
assert!(foo());
}