Couchbase Lite C
Couchbase Lite C API
Loading...
Searching...
No Matches
CompilerSupport.h
Go to the documentation of this file.
1//
2// CompilerSupport.h
3//
4// Copyright 2018-Present Couchbase, Inc.
5//
6// Use of this software is governed by the Business Source License included
7// in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
8// in that file, in accordance with the Business Source License, use of this
9// software will be governed by the Apache License, Version 2.0, included in
10// the file licenses/APL2.txt.
11//
12
13#pragma once
14#ifndef _FLEECE_COMPILER_SUPPORT_H
15#define _FLEECE_COMPILER_SUPPORT_H
16
17#ifdef __APPLE__
18#include <sys/cdefs.h> // include this first to avoid conflict with our definition of __printflike
19#endif
20
21
22// The __has_xxx() macros are supported by [at least] Clang and GCC.
23// Define them to return 0 on other compilers.
24// https://clang.llvm.org/docs/AttributeReference.html
25// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
26
27#ifndef __has_attribute
28#define __has_attribute(x) 0
29#endif
30
31#ifndef __has_cpp_attribute
32#define __has_cpp_attribute(x) 0
33#endif
34
35#ifndef __has_builtin
36 #define __has_builtin(x) 0
37#endif
38
39#ifndef __has_feature
40 #define __has_feature(x) 0
41#endif
42
43#ifndef __has_extension
44 #define __has_extension(x) 0
45#endif
46
47
48// Tells the optimizer that a function's return value is never NULL.
49#if __has_attribute(returns_nonnull)
50# define RETURNS_NONNULL __attribute__((returns_nonnull))
51#else
52# define RETURNS_NONNULL
53#endif
54
55
56// NODISCARD expands to the C++17/C23 `[[nodiscard]]` attribute.
57// Use it before a function declaration when it's a mistake to ignore the function's result.
58#if (__cplusplus >= 201700L) || (__STDC_VERSION__ >= 202000)
59# define NODISCARD [[nodiscard]]
60#elif __has_attribute(warn_unused_result)
61# define NODISCARD __attribute__((warn_unused_result))
62#else
63# define NODISCARD
64#endif
65
66
67// These have no effect on behavior, but they hint to the optimizer which branch of an 'if'
68// statement to make faster.
69// Note: In C++20 the standard attributes `[[likely]]` and `[[unlikely]]` can be used instead,
70// but they're not syntactically identical.
71#if __has_builtin(__builtin_expect)
72#define _usuallyTrue(VAL) __builtin_expect(VAL, true)
73#define _usuallyFalse(VAL) __builtin_expect(VAL, false)
74#else
75#define _usuallyTrue(VAL) (VAL)
76#define _usuallyFalse(VAL) (VAL)
77#endif
78
79
80// Clang nullability annotations, for function parameters and struct fields.
81// In between FL_ASSUME_NONNULL_BEGIN and FL_ASSUME_NONNULL_END, all pointer declarations implicitly
82// disallow NULL values, unless annotated with FL_NULLABLE (which must come after the `*`.)
83// (FL_NONNULL is occasionally necessary when there are multiple levels of pointers.)
84// NOTE: Only supported in Clang, so far.
85#if __has_feature(nullability)
86# define FL_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
87# define FL_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
88# define FL_NULLABLE _Nullable
89# define FL_NONNULL _Nonnull
90# define FL_RETURNS_NONNULL __attribute__((returns_nonnull))
91#else
92# define FL_ASSUME_NONNULL_BEGIN
93# define FL_ASSUME_NONNULL_END
94# define FL_NULLABLE
95# define FL_NONNULL
96# define FL_RETURNS_NONNULL
97#endif
98
99
100// Declares that a parameter must not be NULL. The compiler can sometimes detect violations
101// of this at compile time, if the parameter value is a literal.
102// The Clang Undefined-Behavior Sanitizer will detect all violations at runtime.
103// GCC also has an attribute with this name, but it's incompatible: it can't be applied to a
104// parameter, it has to come after the function and list parameters by number. Oh well.
105// TODO: Replace this with the better nullability annotations above.
106#if defined(__clang__)
107# define NONNULL __attribute__((nonnull))
108#else
109# define NONNULL
110#endif
111
112
113// FLPURE functions are _read-only_. They cannot write to memory (in a way that's detectable),
114// and they cannot access volatile data or do I/O.
115//
116// Calling an FLPURE function twice in a row with the same arguments must return the same result.
117//
118// "Many functions have no effects except the return value, and their return value depends only on
119// the parameters and/or global variables. Such a function can be subject to common subexpression
120// elimination and loop optimization just as an arithmetic operator would be. These functions
121// should be declared with the attribute pure."
122// "The pure attribute prohibits a function from modifying the state of the program that is
123// observable by means other than inspecting the function’s return value. However, functions
124// declared with the pure attribute can safely read any non-volatile objects, and modify the value
125// of objects in a way that does not affect their return value or the observable state of the
126// program." -- GCC manual
127#if __has_attribute(__pure__)
128# define FLPURE __attribute__((__pure__))
129#else
130# define FLPURE
131#endif
132
133// FLCONST is even stricter than FLPURE. The function cannot access memory at all (except for
134// reading immutable values like constants.) The return value can only depend on the parameters.
135//
136// Calling an FLCONST function with the same arguments must _always_ return the same result.
137//
138// "Calls to functions whose return value is not affected by changes to the observable state of the
139// program and that have no observable effects on such state other than to return a value may lend
140// themselves to optimizations such as common subexpression elimination. Declaring such functions
141// with the const attribute allows GCC to avoid emitting some calls in repeated invocations of the
142// function with the same argument values."
143// "Note that a function that has pointer arguments and examines the data pointed to must not be
144// declared const if the pointed-to data might change between successive invocations of the
145// function.
146// "In general, since a function cannot distinguish data that might change from data that cannot,
147// const functions should never take pointer or, in C++, reference arguments. Likewise, a function
148// that calls a non-const function usually must not be const itself." -- GCC manual
149#if __has_attribute(__const__)
150# define FLCONST __attribute__((__const__))
151#else
152# define FLCONST
153#endif
154
155
156// STEPOVER is for trivial little glue functions that are annoying to step into in the debugger
157// on the way to the function you _do_ want to step into. Examples are RefCounted's operator->,
158// or slice constructors. Suppressing debug info for those functions means the debugger
159// will continue through them when stepping in.
160// (It probably also makes the debug-symbol file smaller.)
161#if __has_attribute(nodebug)
162 #define STEPOVER __attribute((nodebug))
163#else
164 #define STEPOVER
165#endif
166
167
168// Note: Code below adapted from libmdbx source code.
169
170// `__optimize` is used by the macros below -- you should probably not use it directly, instead
171// use `__hot` or `__cold`. It applies a specific compiler optimization level to a function,
172// e.g. __optimize("O3") or __optimize("Os"). Has no effect in an unoptimized build.
173#ifndef __optimize
174# if defined(__OPTIMIZE__)
175# if defined(__clang__) && !__has_attribute(__optimize__)
176# define __optimize(ops)
177# elif defined(__GNUC__) || __has_attribute(__optimize__)
178# define __optimize(ops) __attribute__((__optimize__(ops)))
179# else
180# define __optimize(ops)
181# endif
182# else
183# define __optimize(ops)
184# endif
185#endif /* __optimize */
186
187#if defined(__clang__)
188 #define HOTLEVEL "Ofast"
189 #define COLDLEVEL "Oz"
190#else
191 #define HOTLEVEL "O3"
192 #define COLDLEVEL "Os"
193#endif
194
195// `__hot` marks a function as being a hot-spot. Optimizes it for speed and may move it to a common
196// code section for hot functions. Has no effect in an unoptimized build.
197#ifndef __hot
198# if defined(__OPTIMIZE__)
199# if defined(__clang__) && !__has_attribute(__hot__) \
200 && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
201 /* just put frequently used functions in separate section */
202# define __hot __attribute__((__section__("text.hot"))) __optimize(HOTLEVEL)
203# elif defined(__GNUC__) || __has_attribute(__hot__)
204# define __hot __attribute__((__hot__)) __optimize(HOTLEVEL)
205# else
206# define __hot __optimize(HOTLEVEL)
207# endif
208# else
209# define __hot
210# endif
211#endif /* __hot */
212
213// `__cold` marks a function as being rarely used (e.g. error handling.) Optimizes it for size and
214// moves it to a common code section for cold functions. Has no effect in an unoptimized build.
215#ifndef __cold
216# if defined(__OPTIMIZE__)
217# if defined(__clang__) && !__has_attribute(__cold__) \
218 && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
219 /* just put infrequently used functions in separate section */
220# define __cold __attribute__((__section__("text.unlikely"))) __optimize(COLDLEVEL)
221# elif defined(__GNUC__) || __has_attribute(__cold__)
222# define __cold __attribute__((__cold__)) __optimize(COLDLEVEL)
223# else
224# define __cold __optimize(COLDLEVEL)
225# endif
226# else
227# define __cold
228# endif
229#endif /* __cold */
230
231// Declares this function takes a printf-like format string, and the subsequent args should
232// be type-checked against it.
233#ifndef __printflike
234# if __has_attribute(__format__)
235# define __printflike(fmtarg, firstvararg) \
236 __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
237# else
238# define __printflike(fmtarg, firstvararg)
239# endif
240#endif
241
242
243// Suppresses sanitizers in a function
244#ifndef _MSC_VER
245# define __no_sanitize(X) __attribute__((no_sanitize(X)))
246#else
247# define __no_sanitize(X)
248#endif
249
250
251#ifndef _MSC_VER
252 #define WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) 0
253#endif
254
255// On Windows, FLEECE_PUBLIC marks symbols as being exported from the shared library.
256// However, this is not the whole list of things that are exported. The API methods
257// are exported using a definition list, but it is not possible to correctly include
258// initialized global variables, so those need to be marked (both in the header and
259// implementation) with FLEECE_PUBLIC. See kFLNullValue below and in Fleece.cc
260// for an example.
261#if defined(_MSC_VER)
262# ifdef FLEECE_EXPORTS
263# define FLEECE_PUBLIC __declspec(dllexport)
264# else
265# define FLEECE_PUBLIC __declspec(dllimport)
266# endif
267# define FLEECE_PUBLIC_IMPL FLEECE_PUBLIC
268#else
269# define FLEECE_PUBLIC __attribute__((visibility("default")))
270# ifdef __clang__
271# define FLEECE_PUBLIC_IMPL FLEECE_PUBLIC
272# else
273# define FLEECE_PUBLIC_IMPL
274# endif
275#endif
276
277#ifdef __cplusplus
278# define FLAPI noexcept
279
280 // `LIFETIMEBOUND` helps Clang detect value lifetime errors, where one value's lifetime is tied to another and the
281 // dependent value is used after the value it depends on exits scope. For examples of usage, see slice.hh.
282 // "The `lifetimebound` attribute on a function parameter or implicit object parameter indicates that objects that are
283 // referred to by that parameter may also be referred to by the return value of the annotated function (or, for a
284 // parameter of a constructor, by the value of the constructed object)."
285 // -- https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
286# if __has_cpp_attribute(clang::lifetimebound)
287# define LIFETIMEBOUND [[clang::lifetimebound]]
288# else
289# define LIFETIMEBOUND
290# endif
291#else
292# define FLAPI
293# define LIFETIMEBOUND
294#endif
295
296// Type-checking for printf-style vararg functions:
297#ifndef __printflike
298# if __has_attribute(__format__)
299# define __printflike(fmtarg, firstvararg) __attribute__((__format__(__printf__, fmtarg, firstvararg)))
300# else
301# define __printflike(A, B)
302# endif
303#endif
304
305
306#else // _FLEECE_COMPILER_SUPPORT_H
307#warn "Compiler is not honoring #pragma once"
308#endif