about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgnzlbg <gonzalobg88@gmail.com>2019-03-26 16:14:32 +0100
committergnzlbg <gonzalobg88@gmail.com>2019-03-26 16:14:32 +0100
commit0c127e849487323a9f6be09d25c0da0aeb57314d (patch)
tree113d03d71f32979c467eb0dbdf947f8b277712f5
parent3b6b4899bf699f4098b8cdd773a474b483f23462 (diff)
downloadrust-0c127e849487323a9f6be09d25c0da0aeb57314d.tar.gz
rust-0c127e849487323a9f6be09d25c0da0aeb57314d.zip
Life's too short not to use cfg_if
-rw-r--r--src/libcore/hint.rs43
-rw-r--r--src/libcore/internal_macros.rs81
2 files changed, 101 insertions, 23 deletions
diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs
index 6a6f8893bfb..d1ccc148654 100644
--- a/src/libcore/hint.rs
+++ b/src/libcore/hint.rs
@@ -97,36 +97,33 @@ pub fn spin_loop() {
 /// elimination.
 ///
 /// This function is a no-op, and does not even read from `dummy`.
+#[inline]
 #[unstable(feature = "test", issue = "27812")]
 pub fn black_box<T>(dummy: T) -> T {
-    #[cfg(not(
-        any(
+    cfg_if! {
+        if #[cfg(any(
             target_arch = "asmjs",
             all(
                 target_arch = "wasm32",
                 target_os = "emscripten"
             )
-        )
-    ))] {
-        // we need to "use" the argument in some way LLVM can't
-        // introspect.
-        unsafe { asm!("" : : "r"(&dummy)) }
-        dummy
-    }
-    #[cfg(
-        any(
-            target_arch = "asmjs",
-            all(
-                target_arch = "wasm32",
-                target_os = "emscripten"
-            )
-        )
-    )] {
-        // asm.js and emscripten do not support inline assembly
-        unsafe {
-            let ret = crate::ptr::read_volatile(&dummy);
-            crate::mem::forget(dummy);
-            ret
+        ))] {
+            #[inline]
+            unsafe fn black_box_impl<T>(d: T) -> T {
+                // these targets do not support inline assembly
+                let ret = crate::ptr::read_volatile(&d);
+                crate::mem::forget(d);
+                ret
+            }
+        } else {
+            #[inline]
+            unsafe fn black_box_impl<T>(d: T) -> T {
+                // we need to "use" the argument in some way LLVM can't
+                // introspect.
+                asm!("" : : "r"(&d));
+                d
+            }
         }
     }
+    unsafe { black_box_impl(dummy) }
 }
diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs
index b5c20582986..ee6b7d3db48 100644
--- a/src/libcore/internal_macros.rs
+++ b/src/libcore/internal_macros.rs
@@ -119,3 +119,84 @@ macro_rules! impl_fn_for_zst {
         )+
     }
 }
+
+/// 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
+///
+/// ```
+/// #[macro_use]
+/// extern crate 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_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)*
+    };
+}