assert.h
Go to the documentation of this file.
1 #ifndef NVIM_ASSERT_H
2 #define NVIM_ASSERT_H
3 
4 // support static asserts (aka compile-time asserts)
5 
6 // some compilers don't properly support short-circuiting apparently, giving
7 // ugly syntax errors when using things like defined(__clang__) &&
8 // defined(__has_feature) && __has_feature(...). Therefore we define Clang's
9 // __has_feature and __has_extension macro's before referring to them.
10 #ifndef __has_feature
11 # define __has_feature(x) 0
12 #endif
13 
14 #ifndef __has_extension
15 # define __has_extension __has_feature
16 #endif
17 
30 
37 
38 // define STATIC_ASSERT as C11's _Static_assert whenever either C11 mode is
39 // detected or the compiler is known to support it. Note that Clang in C99
40 // mode defines __has_feature(c_static_assert) as false and
41 // __has_extension(c_static_assert) as true. Meaning it does support it, but
42 // warns. A similar thing goes for gcc, which warns when it's not compiling
43 // as C11 but does support _Static_assert since 4.6. Since we prefer the
44 // clearer messages we get from _Static_assert, we suppress the warnings
45 // temporarily.
46 
47 #define STATIC_ASSERT_PRAGMA_START
48 #define STATIC_ASSERT_PRAGMA_END
49 #define STATIC_ASSERT(cond, msg) \
50  do { \
51  STATIC_ASSERT_PRAGMA_START \
52  STATIC_ASSERT_STATEMENT(cond, msg); \
53  STATIC_ASSERT_PRAGMA_END \
54  } while (0)
55 
56 // the easiest case, when the mode is C11 (generic compiler) or Clang
57 // advertises explicit support for c_static_assert, meaning it won't warn.
58 #if __STDC_VERSION__ >= 201112L || __has_feature(c_static_assert)
59 # define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
60 // if we're dealing with gcc >= 4.6 in C99 mode, we can still use
61 // _Static_assert but we need to suppress warnings, this is pretty ugly.
62 #elif (!defined(__clang__) && !defined(__INTEL_COMPILER)) && \
63  (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
64 
65 # define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
66 
67 # undef STATIC_ASSERT_PRAGMA_START
68 
69 #if __GNUC__ >= 6
70 # define STATIC_ASSERT_PRAGMA_START \
71  _Pragma("GCC diagnostic push") \
72  _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
73 #else
74 # define STATIC_ASSERT_PRAGMA_START \
75  _Pragma("GCC diagnostic push") \
76  _Pragma("GCC diagnostic ignored \"-pedantic\"")
77 #endif
78 
79 # undef STATIC_ASSERT_PRAGMA_END
80 # define STATIC_ASSERT_PRAGMA_END \
81  _Pragma("GCC diagnostic pop") \
82 
83 // the same goes for clang in C99 mode, but we suppress a different warning
84 #elif defined(__clang__) && __has_extension(c_static_assert)
85 
86 # define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
87 
88 # undef STATIC_ASSERT_PRAGMA_START
89 # define STATIC_ASSERT_PRAGMA_START \
90  _Pragma("clang diagnostic push") \
91  _Pragma("clang diagnostic ignored \"-Wc11-extensions\"") \
92 
93 # undef STATIC_ASSERT_PRAGMA_END
94 # define STATIC_ASSERT_PRAGMA_END \
95  _Pragma("clang diagnostic pop") \
96 
97 // TODO(aktau): verify that this works, don't have MSVC on hand.
98 #elif _MSC_VER >= 1600
99 
100 # define STATIC_ASSERT_STATEMENT(cond, msg) static_assert(cond, msg)
101 
102 // fallback for compilers that don't support _Static_assert or static_assert
103 // not as pretty but gets the job done. Credit goes to Pádraig Brady and
104 // contributors.
105 #else
106 # define STATIC_ASSERT_STATEMENT STATIC_ASSERT_EXPR
107 #endif
108 
109 #define ASSERT_CONCAT_(a, b) a##b
110 #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
111 // These can't be used after statements in c89.
112 #ifdef __COUNTER__
113 # define STATIC_ASSERT_EXPR(e, m) \
114  ((enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }) 0)
115 #else
116 // This can't be used twice on the same line so ensure if using in headers
117 // that the headers are not included twice (by wrapping in #ifndef...#endif)
118 // Note it doesn't cause an issue when used on same line of separate modules
119 // compiled with gcc -combine -fwhole-program.
120 # define STATIC_ASSERT_EXPR(e, m) \
121  ((enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }) 0)
122 #endif
123 
136 #if HAVE_BUILTIN_ADD_OVERFLOW
137 # define STRICT_ADD(a, b, c, t) \
138  do { if (__builtin_add_overflow(a, b, c)) { abort(); } } while (0)
139 #else
140 # define STRICT_ADD(a, b, c, t) \
141  do { *(c) = (t)(a + b); } while (0)
142 #endif
143 
146 #if HAVE_BUILTIN_ADD_OVERFLOW
147 # define STRICT_SUB(a, b, c, t) \
148  do { if (__builtin_sub_overflow(a, b, c)) { abort(); } } while (0)
149 #else
150 # define STRICT_SUB(a, b, c, t) \
151  do { *(c) = (t)(a - b); } while (0)
152 #endif
153 
154 #endif // NVIM_ASSERT_H