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