]> git.proxmox.com Git - mirror_frr.git/blame - lib/compiler.h
Merge pull request #4546 from donaldsharp/better_debugs
[mirror_frr.git] / lib / compiler.h
CommitLineData
de1a880c
DL
1/*
2 * Copyright (c) 2015-2017 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef _FRR_COMPILER_H
18#define _FRR_COMPILER_H
19
5e244469
RW
20#ifdef __cplusplus
21extern "C" {
22#endif
23
de1a880c
DL
24/* function attributes, use like
25 * void prototype(void) __attribute__((_CONSTRUCTOR(100)));
26 */
27#if defined(__clang__)
996c9314 28#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
de1a880c 29# define _RET_NONNULL , returns_nonnull
996c9314 30#endif
bd27ea43
DL
31#if __has_attribute(fallthrough)
32# define _FALLTHROUGH __attribute__((fallthrough));
33#endif
de1a880c 34# define _CONSTRUCTOR(x) constructor(x)
bcea0c0f 35# define _DEPRECATED(x) deprecated(x)
111a04f7
DL
36# if __has_builtin(assume)
37# define assume(x) __builtin_assume(x)
38# endif
de1a880c 39#elif defined(__GNUC__)
996c9314 40#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
de1a880c 41# define _RET_NONNULL , returns_nonnull
996c9314
LB
42#endif
43#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
de1a880c
DL
44# define _CONSTRUCTOR(x) constructor(x)
45# define _DESTRUCTOR(x) destructor(x)
46# define _ALLOC_SIZE(x) alloc_size(x)
996c9314 47#endif
bcea0c0f
DL
48#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
49# define _DEPRECATED(x) deprecated(x)
111a04f7
DL
50# define assume(x) do { if (!(x)) __builtin_unreachable(); } while (0)
51#endif
52#if __GNUC__ < 5
53# define __has_attribute(x) 0
bcea0c0f 54#endif
bd27ea43
DL
55#if __GNUC__ >= 7
56# define _FALLTHROUGH __attribute__((fallthrough));
57#endif
de1a880c
DL
58#endif
59
111a04f7
DL
60#if __has_attribute(hot)
61# define _OPTIMIZE_HOT __attribute__((hot))
62#else
63# define _OPTIMIZE_HOT
64#endif
65#if __has_attribute(optimize)
66# define _OPTIMIZE_O3 __attribute__((optimize("3")))
67#else
68# define _OPTIMIZE_O3
69#endif
70#define OPTIMIZE _OPTIMIZE_O3 _OPTIMIZE_HOT
71
8be3678a
DL
72#if !defined(__GNUC__)
73#error module code needs GCC visibility extensions
74#elif __GNUC__ < 4
75#error module code needs GCC visibility extensions
76#else
77# define DSO_PUBLIC __attribute__ ((visibility ("default")))
78# define DSO_SELF __attribute__ ((visibility ("protected")))
79# define DSO_LOCAL __attribute__ ((visibility ("hidden")))
80#endif
81
de1a880c
DL
82#ifdef __sun
83/* Solaris doesn't do constructor priorities due to linker restrictions */
996c9314
LB
84#undef _CONSTRUCTOR
85#undef _DESTRUCTOR
de1a880c
DL
86#endif
87
88/* fallback versions */
89#ifndef _RET_NONNULL
90# define _RET_NONNULL
91#endif
92#ifndef _CONSTRUCTOR
93# define _CONSTRUCTOR(x) constructor
94#endif
95#ifndef _DESTRUCTOR
96# define _DESTRUCTOR(x) destructor
97#endif
98#ifndef _ALLOC_SIZE
99# define _ALLOC_SIZE(x)
100#endif
bd27ea43
DL
101#ifndef _FALLTHROUGH
102#define _FALLTHROUGH
103#endif
bcea0c0f
DL
104#ifndef _DEPRECATED
105#define _DEPRECATED(x) deprecated
106#endif
111a04f7
DL
107#ifndef assume
108#define assume(x)
109#endif
de1a880c 110
3b18b6c0
DL
111/* pure = function does not modify memory & return value is the same if
112 * memory hasn't changed (=> allows compiler to optimize)
113 *
114 * Mostly autodetected by the compiler if function body is available (i.e.
115 * static inline functions in headers). Since that implies it should only be
116 * used in headers for non-inline functions, the "extern" is included here.
117 */
118#define ext_pure extern __attribute__((pure))
119
0d019561
DL
120/* for helper functions defined inside macros */
121#define macro_inline static inline __attribute__((unused))
122#define macro_pure static inline __attribute__((unused, pure))
123
de1a880c
DL
124/*
125 * for warnings on macros, put in the macro content like this:
126 * #define MACRO BLA CPP_WARN("MACRO has been deprecated")
127 */
128#define CPP_STR(X) #X
129
130#if defined(__ICC)
131#define CPP_NOTICE(text) _Pragma(CPP_STR(message __FILE__ ": " text))
132#define CPP_WARN(text) CPP_NOTICE(text)
133
134#elif (defined(__GNUC__) \
135 && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
136 || (defined(__clang__) \
137 && (__clang_major__ >= 4 \
138 || (__clang_major__ == 3 && __clang_minor__ >= 5)))
139#define CPP_WARN(text) _Pragma(CPP_STR(GCC warning text))
140#define CPP_NOTICE(text) _Pragma(CPP_STR(message text))
141
142#else
143#define CPP_WARN(text)
ec40eaf9 144#define CPP_NOTICE(text)
de1a880c
DL
145#endif
146
0d019561
DL
147/* MAX / MIN are not commonly defined, but useful */
148/* note: glibc sys/param.h has #define MIN(a,b) (((a)<(b))?(a):(b)) */
149#ifdef MAX
150#undef MAX
151#endif
152#define MAX(a, b) \
153 ({ \
154 typeof(a) _max_a = (a); \
155 typeof(b) _max_b = (b); \
156 _max_a > _max_b ? _max_a : _max_b; \
157 })
158#ifdef MIN
159#undef MIN
160#endif
161#define MIN(a, b) \
162 ({ \
163 typeof(a) _min_a = (a); \
164 typeof(b) _min_b = (b); \
165 _min_a < _min_b ? _min_a : _min_b; \
166 })
167
168#ifndef offsetof
169#ifdef __compiler_offsetof
170#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
171#else
172#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
173#endif
174#endif
175
a7f20d43
DL
176#ifdef container_of
177#undef container_of
178#endif
179
180#if !(defined(__cplusplus) || defined(test__cplusplus))
0d019561
DL
181/* this variant of container_of() retains 'const' on pointers without needing
182 * to be told to do so. The following will all work without warning:
183 *
184 * struct member *p;
185 * const struct member *cp;
186 *
187 * const struct cont *x = container_of(cp, struct cont, member);
188 * const struct cont *x = container_of(cp, const struct cont, member);
189 * const struct cont *x = container_of(p, struct cont, member);
190 * const struct cont *x = container_of(p, const struct cont, member);
191 * struct cont *x = container_of(p, struct cont, member);
192 *
193 * but the following will generate warnings about stripping const:
194 *
195 * struct cont *x = container_of(cp, struct cont, member);
196 * struct cont *x = container_of(cp, const struct cont, member);
197 * struct cont *x = container_of(p, const struct cont, member);
198 */
0d019561
DL
199#define container_of(ptr, type, member) \
200 (__builtin_choose_expr( \
201 __builtin_types_compatible_p(typeof(&((type *)0)->member), \
202 typeof(ptr)) \
203 || __builtin_types_compatible_p(void *, typeof(ptr)), \
204 ({ \
205 typeof(((type *)0)->member) *__mptr = (void *)(ptr); \
206 (type *)((char *)__mptr - offsetof(type, member)); \
207 }), \
208 ({ \
209 typeof(((const type *)0)->member) *__mptr = (ptr); \
210 (const type *)((const char *)__mptr - \
211 offsetof(type, member)); \
212 }) \
213 ))
a7f20d43
DL
214#else
215/* current C++ compilers don't have the builtins used above; so this version
216 * of the macro doesn't do the const check. */
217#define container_of(ptr, type, member) \
218 ({ \
219 const typeof(((type *)0)->member) *__mptr = (ptr); \
220 (type *)((char *)__mptr - offsetof(type, member)); \
221 })
222#endif
0d019561
DL
223
224#define container_of_null(ptr, type, member) \
225 ({ \
226 typeof(ptr) _tmp = (ptr); \
227 _tmp ? container_of(_tmp, type, member) : NULL; \
228 })
229
230#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
231
afb35622
DL
232/* sigh. this is so ugly, it overflows and wraps to being nice again.
233 *
234 * printfrr() supports "%Ld" for <int64_t>, whatever that is typedef'd to.
235 * However, gcc & clang think that "%Ld" is <long long>, which doesn't quite
236 * match up since int64_t is <long> on a lot of 64-bit systems.
237 *
238 * If we have _FRR_ATTRIBUTE_PRINTFRR, we loaded a compiler plugin that
239 * replaces the whole format checking bits with a custom version that
240 * understands "%Ld" (along with "%pI4" and co.), so we don't need to do
241 * anything.
242 *
243 * If we don't have that attribute... we still want -Wformat to work. So,
244 * this is the "f*ck it" approach and we just redefine int64_t to always be
245 * <long long>. This should work until such a time that <long long> is
246 * something else (e.g. 128-bit integer)... let's just guard against that
247 * with the _Static_assert below and work with the world we have right now,
248 * where <long long> is always 64-bit.
249 */
250
251/* these need to be included before any of the following, so we can
252 * "overwrite" things.
253 */
254#include <stdint.h>
255#include <inttypes.h>
256
257#ifdef _FRR_ATTRIBUTE_PRINTFRR
258#define PRINTFRR(a, b) __attribute__((printfrr(a, b)))
259
260#else /* !_FRR_ATTRIBUTE_PRINTFRR */
261#define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
262
263/* these should be typedefs, but might also be #define */
264#ifdef uint64_t
265#undef uint64_t
266#endif
267#ifdef int64_t
268#undef int64_t
269#endif
270
271/* can't overwrite the typedef, but we can replace int64_t with _int64_t */
272typedef unsigned long long _uint64_t;
273#define uint64_t _uint64_t
274typedef signed long long _int64_t;
275#define int64_t _int64_t
276
277/* if this breaks, 128-bit machines may have entered reality (or <long long>
278 * is something weird)
279 */
280#if __STDC_VERSION__ >= 201112L
281_Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8,
282 "nobody expects the spanish intquisition");
283#endif
284
285/* since we redefined int64_t, we also need to redefine PRI*64 */
286#undef PRIu64
287#undef PRId64
288#undef PRIx64
289#define PRIu64 "llu"
290#define PRId64 "lld"
291#define PRIx64 "llx"
292#endif /* !_FRR_ATTRIBUTE_PRINTFRR */
293
5e244469
RW
294#ifdef __cplusplus
295}
296#endif
297
de1a880c 298#endif /* _FRR_COMPILER_H */