diff options
author | Nicolas Hillegeer <nicolas@hillegeer.com> | 2014-06-16 10:16:26 +0200 |
---|---|---|
committer | Nicolas Hillegeer <nicolas@hillegeer.com> | 2014-07-16 17:12:34 +0200 |
commit | 095b4479c039f9907ade4e7319cbb6a990a13438 (patch) | |
tree | 9118a3e338cb386996e676cb884fab8d808ffb00 /src | |
parent | 25f3cedfe60b94084a66d235e2e6a004382e1554 (diff) | |
download | rneovim-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.h | 78 |
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 |