aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNicolas Hillegeer <nicolas@hillegeer.com>2014-06-16 10:16:26 +0200
committerNicolas Hillegeer <nicolas@hillegeer.com>2014-07-16 17:12:34 +0200
commit095b4479c039f9907ade4e7319cbb6a990a13438 (patch)
tree9118a3e338cb386996e676cb884fab8d808ffb00 /src
parent25f3cedfe60b94084a66d235e2e6a004382e1554 (diff)
downloadrneovim-095b4479c039f9907ade4e7319cbb6a990a13438.tar.gz
rneovim-095b4479c039f9907ade4e7319cbb6a990a13438.tar.bz2
rneovim-095b4479c039f9907ade4e7319cbb6a990a13438.zip
assert: add STATIC_ASSERT macro
Can be quite handy, attempt to provide fallbacks for compilers that don't support _Static_assert (which is technically a C11 feature). Suppress warnings as best we can (Clang and GCC warn that we're using a C11 feature while in C99 mode). Needs to be tested for MSVC still.
Diffstat (limited to 'src')
-rw-r--r--src/nvim/assert.h78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
new file mode 100644
index 0000000000..3a900aca65
--- /dev/null
+++ b/src/nvim/assert.h
@@ -0,0 +1,78 @@
+#ifndef NVIM_ASSERT_H
+#define NVIM_ASSERT_H
+
+// support static asserts (aka compile-time asserts)
+
+// some compilers don't properly support short-circuiting apparently, giving
+// ugly syntax errors when using things like defined(__clang__) &&
+// defined(__has_feature) && __has_feature(...). Therefore we define Clang's
+// __has_feature and __has_extension macro's before referring to them.
+#ifndef __has_feature
+ #define __has_feature(x) 0
+#endif
+
+#ifndef __has_extension
+ #define __has_extension __has_feature
+#endif
+
+/// STATIC_ASSERT(condition, message) - assert at compile time if !cond
+///
+/// example:
+/// STATIC_ASSERT(sizeof(void *) == 8, "need 64-bits mode");
+
+// define STATIC_ASSERT as C11's _Static_assert whenever either C11 mode is
+// detected or the compiler is known to support it. Note that Clang in C99
+// mode defines __has_feature(c_static_assert) as false and
+// __has_extension(c_static_assert) as true. Meaning it does support it, but
+// warns. A similar thing goes for gcc, which warns when it's not compiling
+// as C11 but does support _Static_assert since 4.6. Since we prefer the
+// clearer messages we get from _Static_assert, we suppress the warnings
+// temporarily.
+
+// the easiest case, when the mode is C11 (generic compiler) or Clang
+// advertises explicit support for c_static_assert, meaning it won't warn.
+#if __STDC_VERSION__ >= 201112L || __has_feature(c_static_assert)
+ #define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
+// if we're dealing with gcc >= 4.6 in C99 mode, we can still use
+// _Static_assert but we need to suppress warnings, this is pretty ugly.
+#elif (!defined(__clang__) && !defined(__INTEL_COMPILER)) && \
+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+ #define STATIC_ASSERT(cond, msg) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-pedantic\"") \
+ _Static_assert(cond, msg); \
+ _Pragma("GCC diagnostic pop") \
+
+// the same goes for clang in C99 mode, but we suppress a different warning
+#elif defined(__clang__) && __has_extension(c_static_assert)
+ #define STATIC_ASSERT(cond, msg) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wc11-extensions\"") \
+ _Static_assert(cond, msg); \
+ _Pragma("clang diagnostic pop") \
+
+// TODO(aktau): verify that this works, don't have MSVC on hand.
+#elif _MSC_VER >= 1600
+ #define STATIC_ASSERT(cond, msg) static_assert(cond, msg)
+
+// fallback for compilers that don't support _Static_assert or static_assert
+// not as pretty but gets the job done. Credit goes to Pádraig Brady and
+// contributors.
+#else
+ #define ASSERT_CONCAT_(a, b) a##b
+ #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+ // These can't be used after statements in c89.
+ #ifdef __COUNTER__
+ #define STATIC_ASSERT(e,m) \
+ { enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }; }
+ #else
+ // This can't be used twice on the same line so ensure if using in headers
+ // that the headers are not included twice (by wrapping in #ifndef...#endif)
+ // Note it doesn't cause an issue when used on same line of separate modules
+ // compiled with gcc -combine -fwhole-program.
+ #define STATIC_ASSERT(e,m) \
+ { enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }; }
+ #endif
+#endif
+
+#endif // NVIM_ASSERT_H