Couchbase Lite C
Couchbase Lite C API
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// The __has_xxx() macros are supported by [at least] Clang and GCC.
18// Define them to return 0 on other compilers.
19// https://clang.llvm.org/docs/AttributeReference.html
20// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
21
22#ifndef __has_attribute
23 #define __has_attribute(x) 0
24#endif
25
26#ifndef __has_builtin
27 #define __has_builtin(x) 0
28#endif
29
30#ifndef __has_feature
31 #define __has_feature(x) 0
32#endif
33
34#ifndef __has_extension
35 #define __has_extension(x) 0
36#endif
37
38
39// Tells the optimizer that a function's return value is never NULL.
40#if __has_attribute(returns_nonnull)
41# define RETURNS_NONNULL __attribute__((returns_nonnull))
42#else
43# define RETURNS_NONNULL
44#endif
45
46// deprecated; use NODISCARD instead
47#if __has_attribute(returns_nonnull)
48# define MUST_USE_RESULT __attribute__((warn_unused_result))
49#else
50# define MUST_USE_RESULT
51#endif
52
53// NODISCARD expands to the C++17/C23 `[[nodiscard]]` attribute, or else MUST_USE_RESULT.
54// (We can't just redefine MUST_USE_RESULT as `[[nodiscard]]` unfortunately, because the former is
55// already in use in positions where `[[nodiscard]]` isn't valid, like at the end of a declaration.)
56#if (__cplusplus >= 201700L) || (__STDC_VERSION__ >= 202000)
57# define NODISCARD [[nodiscard]]
58#else
59# define NODISCARD MUST_USE_RESULT
60#endif
61
62// These have no effect on behavior, but they hint to the optimizer which branch of an 'if'
63// statement to make faster.
64#if __has_builtin(__builtin_expect)
65#define _usuallyTrue(VAL) __builtin_expect(VAL, true)
66#define _usuallyFalse(VAL) __builtin_expect(VAL, false)
67#else
68#define _usuallyTrue(VAL) (VAL)
69#define _usuallyFalse(VAL) (VAL)
70#endif
71
72
73// Nullability annotations, for function parameters and struct fields.
74// In between FL_ASSUME_NONNULL_BEGIN and FL_ASSUME_NONNULL_END, all pointer declarations implicitly
75// disallow NULL values, unless annotated with FL_NULLABLE (which must come after the `*`.)
76// (FL_NONNULL is occasionally necessary when there are multiple levels of pointers.)
77// NOTE: Only supported in Clang, so far.
78#if __has_feature(nullability)
79# define FL_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
80# define FL_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
81# define FL_NULLABLE _Nullable
82# define FL_NONNULL _Nonnull
83# define FL_RETURNS_NONNULL __attribute__((returns_nonnull))
84#else
85# define FL_ASSUME_NONNULL_BEGIN
86# define FL_ASSUME_NONNULL_END
87# define FL_NULLABLE
88# define FL_NONNULL
89# define FL_RETURNS_NONNULL
90#endif
91
92
93// Declares that a parameter must not be NULL. The compiler can sometimes detect violations
94// of this at compile time, if the parameter value is a literal.
95// The Clang Undefined-Behavior Sanitizer will detect all violations at runtime.
96// GCC also has an attribute with this name, but it's incompatible: it can't be applied to a
97// parameter, it has to come after the function and list parameters by number. Oh well.
98// TODO: Replace this with the better nullability annotations above.
99#if __has_attribute(nonnull)
100# define NONNULL __attribute__((nonnull))
101#else
102# define NONNULL
103#endif
104
105
106// FLPURE functions are _read-only_. They cannot write to memory (in a way that's detectable),
107// and they cannot access volatile data or do I/O.
108//
109// Calling an FLPURE function twice in a row with the same arguments must return the same result.
110//
111// "Many functions have no effects except the return value, and their return value depends only on
112// the parameters and/or global variables. Such a function can be subject to common subexpression
113// elimination and loop optimization just as an arithmetic operator would be. These functions
114// should be declared with the attribute pure."
115// "The pure attribute prohibits a function from modifying the state of the program that is
116// observable by means other than inspecting the function’s return value. However, functions
117// declared with the pure attribute can safely read any non-volatile objects, and modify the value
118// of objects in a way that does not affect their return value or the observable state of the
119// program." -- GCC manual
120#if __has_attribute(__pure__)
121# define FLPURE __attribute__((__pure__))
122#else
123# define FLPURE
124#endif
125
126// FLCONST is even stricter than FLPURE. The function cannot access memory at all (except for
127// reading immutable values like constants.) The return value can only depend on the parameters.
128//
129// Calling an FLCONST function with the same arguments must _always_ return the same result.
130//
131// "Calls to functions whose return value is not affected by changes to the observable state of the
132// program and that have no observable effects on such state other than to return a value may lend
133// themselves to optimizations such as common subexpression elimination. Declaring such functions
134// with the const attribute allows GCC to avoid emitting some calls in repeated invocations of the
135// function with the same argument values."
136// "Note that a function that has pointer arguments and examines the data pointed to must not be
137// declared const if the pointed-to data might change between successive invocations of the
138// function.
139// "In general, since a function cannot distinguish data that might change from data that cannot,
140// const functions should never take pointer or, in C++, reference arguments. Likewise, a function
141// that calls a non-const function usually must not be const itself." -- GCC manual
142#if __has_attribute(__const__)
143# define FLCONST __attribute__((__const__))
144#else
145# define FLCONST
146#endif
147
148
149// `constexpr14` is for uses of `constexpr` that are valid in C++14 but not earlier.
150// In constexpr functions this includes `if`, `for`, `while` statements; or multiple `return`s.
151// The macro expands to `constexpr` in C++14 or later, otherwise to nothing.
152#ifdef __cplusplus
153 #if __cplusplus >= 201400L || _MSVC_LANG >= 201400L
154 #define constexpr14 constexpr
155 #else
156 #define constexpr14
157 #endif
158#endif // __cplusplus
159
160
161// STEPOVER is for trivial little glue functions that are annoying to step into in the debugger
162// on the way to the function you _do_ want to step into. Examples are RefCounted's operator->,
163// or slice constructors. Suppressing debug info for those functions means the debugger
164// will continue through them when stepping in.
165// (It probably also makes the debug-symbol file smaller.)
166#if __has_attribute(nodebug)
167 #define STEPOVER __attribute((nodebug))
168#else
169 #define STEPOVER
170#endif
171
172
173// Note: Code below adapted from libmdbx source code.
174
175// `__optimize` is used by the macros below -- you should probably not use it directly, instead
176// use `__hot` or `__cold`. It applies a specific compiler optimization level to a function,
177// e.g. __optimize("O3") or __optimize("Os"). Has no effect in an unoptimized build.
178#ifndef __optimize
179# if defined(__OPTIMIZE__)
180# if defined(__clang__) && !__has_attribute(__optimize__)
181# define __optimize(ops)
182# elif defined(__GNUC__) || __has_attribute(__optimize__)
183# define __optimize(ops) __attribute__((__optimize__(ops)))
184# else
185# define __optimize(ops)
186# endif
187# else
188# define __optimize(ops)
189# endif
190#endif /* __optimize */
191
192#if defined(__clang__)
193 #define HOTLEVEL "Ofast"
194 #define COLDLEVEL "Oz"
195#else
196 #define HOTLEVEL "O3"
197 #define COLDLEVEL "Os"
198#endif
199
200// `__hot` marks a function as being a hot-spot. Optimizes it for speed and may move it to a common
201// code section for hot functions. Has no effect in an unoptimized build.
202#ifndef __hot
203# if defined(__OPTIMIZE__)
204# if defined(__clang__) && !__has_attribute(__hot__) \
205 && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
206 /* just put frequently used functions in separate section */
207# define __hot __attribute__((__section__("text.hot"))) __optimize(HOTLEVEL)
208# elif defined(__GNUC__) || __has_attribute(__hot__)
209# define __hot __attribute__((__hot__)) __optimize(HOTLEVEL)
210# else
211# define __hot __optimize(HOTLEVEL)
212# endif
213# else
214# define __hot
215# endif
216#endif /* __hot */
217
218// `__cold` marks a function as being rarely used (e.g. error handling.) Optimizes it for size and
219// moves it to a common code section for cold functions. Has no effect in an unoptimized build.
220#ifndef __cold
221# if defined(__OPTIMIZE__)
222# if defined(__clang__) && !__has_attribute(__cold__) \
223 && __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
224 /* just put infrequently used functions in separate section */
225# define __cold __attribute__((__section__("text.unlikely"))) __optimize(COLDLEVEL)
226# elif defined(__GNUC__) || __has_attribute(__cold__)
227# define __cold __attribute__((__cold__)) __optimize(COLDLEVEL)
228# else
229# define __cold __optimize(COLDLEVEL)
230# endif
231# else
232# define __cold
233# endif
234#endif /* __cold */
235
236
237#ifndef _MSC_VER
238 #define WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) 0
239#endif
240
241// On Windows, FLEECE_PUBLIC marks symbols as being exported from the shared library.
242// However, this is not the whole list of things that are exported. The API methods
243// are exported using a definition list, but it is not possible to correctly include
244// initialized global variables, so those need to be marked (both in the header and
245// implementation) with FLEECE_PUBLIC. See kFLNullValue below and in Fleece.cc
246// for an example.
247#if defined(_MSC_VER)
248#ifdef FLEECE_EXPORTS
249#define FLEECE_PUBLIC __declspec(dllexport)
250#else
251#define FLEECE_PUBLIC __declspec(dllimport)
252#endif
253#else
254#define FLEECE_PUBLIC __attribute__((visibility("default")))
255#endif
256
257#ifdef __cplusplus
258 #define FLAPI noexcept
259#else
260 #define FLAPI
261#endif
262
263#else // _FLEECE_COMPILER_SUPPORT_H
264#warn "Compiler is not honoring #pragma once"
265#endif