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