]> git.lizzy.rs Git - rust.git/commitdiff
Life's too short not to use cfg_if
authorgnzlbg <gonzalobg88@gmail.com>
Tue, 26 Mar 2019 15:14:32 +0000 (16:14 +0100)
committergnzlbg <gonzalobg88@gmail.com>
Tue, 26 Mar 2019 15:14:32 +0000 (16:14 +0100)
src/libcore/hint.rs
src/libcore/internal_macros.rs

index 6a6f8893bfbd67de367af2c1b219e94b1ecbcc8c..d1ccc148654ca4659b3cc7119186ba78da001e02 100644 (file)
@@ -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) }
 }
index b5c20582986b262368344a8df54b27b495c59f5d..ee6b7d3db48a6f999440d47ef39af4a1434bbfc4 100644 (file)
@@ -119,3 +119,84 @@ extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $Return
         )+
     }
 }
+
+/// 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)*
+    };
+}