diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/zircon/LICENSE | 24 | ||||
| -rw-r--r-- | include/zircon/README.lume | 11 | ||||
| -rw-r--r-- | include/zircon/assert.h | 246 | ||||
| -rw-r--r-- | include/zircon/compiler.h | 380 |
4 files changed, 661 insertions, 0 deletions
diff --git a/include/zircon/LICENSE b/include/zircon/LICENSE new file mode 100644 index 0000000..7ed244f --- /dev/null +++ b/include/zircon/LICENSE @@ -0,0 +1,24 @@ +Copyright 2019 The Fuchsia Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/include/zircon/README.lume b/include/zircon/README.lume new file mode 100644 index 0000000..41e610f --- /dev/null +++ b/include/zircon/README.lume @@ -0,0 +1,11 @@ +Zircon public support headers required by the first kernel library batch + +Fuchsia revision: f8d670ab4bbb71bfb4d569893ba12fbb8a83bacd + +Imported files: + zircon/system/public/zircon/compiler.h + sdk/lib/zircon-assert/zircon/assert.h + +The assert header is a regular-file copy of the SDK target. The corresponding +path under zircon/system/public is a Fuchsia-tree-relative symbolic link and +is deliberately not reproduced as a broken link. diff --git a/include/zircon/assert.h b/include/zircon/assert.h new file mode 100644 index 0000000..47f8c4d --- /dev/null +++ b/include/zircon/assert.h @@ -0,0 +1,246 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_ZIRCON_ASSERT_ZIRCON_ASSERT_H_ +#define LIB_ZIRCON_ASSERT_ZIRCON_ASSERT_H_ + +// For a description of which asserts are enabled at which debug levels, see the documentation for +// GN build argument |assert_level|. + +#ifdef _KERNEL +#include <assert.h> +#define ZX_PANIC(args...) PANIC(args) +#define ZX_ASSERT(args...) ASSERT(args) +#define ZX_ASSERT_MSG(args...) ASSERT_MSG(args) +#define ZX_DEBUG_ASSERT(args...) DEBUG_ASSERT(args) +#define ZX_DEBUG_ASSERT_MSG(args...) DEBUG_ASSERT_MSG(args) +#define ZX_DEBUG_ASSERT_COND(args...) DEBUG_ASSERT_COND(args) +#define ZX_DEBUG_ASSERT_MSG_COND(args...) DEBUG_ASSERT_MSG_COND(args) +#define ZX_DEBUG_ASSERT_IMPLEMENTED DEBUG_ASSERT_IMPLEMENTED + +#else // #ifdef _KERNEL + +#include <zircon/compiler.h> + +__BEGIN_CDECLS +// NOLINTNEXTLINE(bugprone-reserved-identifier) +void __zx_panic(const char* format, ...) __NO_RETURN __PRINTFLIKE(1, 2); +__END_CDECLS + +#define ZX_PANIC(fmt, ...) __zx_panic((fmt), ##__VA_ARGS__) + +// Conditionally implement ZX_DEBUG_ASSERT based on ZX_ASSERT_LEVEL. +// +// ZX_DEBUG_ASSERT_IMPLEMENTED is intended to be used to conditionalize code +// that is logically part of a debug assert. It's useful for performing complex +// consistency checks that are difficult to work into a ZX_DEBUG_ASSERT +// statement. +#ifdef ZX_ASSERT_LEVEL +#define ZX_DEBUG_ASSERT_IMPLEMENTED (ZX_ASSERT_LEVEL > 1) +#else +#define ZX_DEBUG_ASSERT_IMPLEMENTED 0 +#endif + +// Notes about the C++ and C versions of the assert macros. +// +// The C++ versions of these macros follow a very specific form for testing the +// assert predicate `x`. Specifically, the test of the predicate is _always_ +// written simply as `if (x)`. Not: +// +// 1) `if (!x)` // or +// 2) `if ((x))` // or +// 3) `if (unlikely(!(x))) // or +// 4) `if (ZX_DEBUG_ASSERT_ENABLED && unlikely(!(x))) // or, anything else. +// +// It is *always* just `if (x)`. There is a method to this madness. The +// primary reason for this is to catch mistakes of the following form: +// +// ZX_DEBUG_ASSERT(my_bool_variable = false); +// ZX_ASSERT(my_int_variable = 5); +// +// Both of these are examples of a pattern where a code author meant to use +// comparison (`==`), but accidentally used assignment (`=`), meaning that the +// first of these examples is always going to fire, while the second will never +// fire. Both of them will have a side effect of mutating their variable, but a +// ZX_DEBUG_ASSERT's mutation will drop out of a release build. +// +// :: Accidental Assignment Protection :: +// +// This is all very bad, and _should_ be caught by the -Wparentheses warning, +// when enabled (which it usually is). Unfortunately, surrounding an assignment +// operation in a set of `()` will suppress the warning. Pretty much any other +// form of the predicate test ends up requiring that we add in an extra pair of +// `()`. This also includes wrapping the predicate in things like `unlikely(x)` +// and `likely(x)`. So, we have to restrict ourselves strictly to testing with +// `if (x)` in order to get the accidental assignment protection we desire. +// +// :: Temporary Variable Latching :: +// +// A surprise advantage to taking this approach is that it allows us (in C++) to +// more easily write predicates which involve latching to a temporary variable. +// Consider a case where we want to debug assert something about a value +// returned by a function which is expensive to call. We could write: +// +// DEBUG_ASSERT_MSG(Expensive() == 5, +// "Expensive() returned a non-five value (%u)", +// Expensive()); +// +// But now we are calling the expensive function twice. We could also say: +// +// [[maybe_unused]] const uint32_t e = Expensive(); +// ZX_DEBUG_ASSERT_MSG(e, "Expensive() returned a non-five value (%u)", e); +// +// but it takes a couple of lines, we have to add in a [[maybe_unused]] +// annotation, and we may still be forced to evaluate Expensive if the compiler +// cannot tell that it is guaranteed to have no side effects. +// +// With the new only-`if (x)` form of testing the predicate, however, we can do +// better. Now, we can write: +// +// ZX_DEBUG_ASSERT_MSG(const uint32_t e = Expensive(); e == 5, +// "Expensive() returned a non-five value (%u)", e); +// +// We still get our protection against accidental assignment, we are guaranteed +// to evaluate Expensive exactly once in a debug build, and zero times in a +// release build. +// +// :: WARNING - C code does not get these benefits :: +// +// To write in this style, but also preserve the likely/unlikely hinting +// benefits, we are forced to use C++'s standardized attributes `[[likely]]` and +// `[[unlikely]]``. These are not available in C, which has to use the old +// compiler attribute macros, which always end up introducing `()`, and +// suppressing the accidental assignment protection. Right now, there is no +// good way around this, and as long as we are building C code using this +// header, we will need to maintain a version of these macros which do not offer +// the same level of protection. +// +#ifdef __cplusplus + +// Only use the [[likely]] attribute if we are sure the compiler is going to +// understand it. +#if defined(__has_cpp_attribute) && (__has_cpp_attribute(likely) >= 201803L) +// NOLINTNEXTLINE(bugprone-reserved-identifier) +#define _ZIRCON_ASSERT_ATTRIBUTE_LIKELY [[likely]] +#else +// NOLINTNEXTLINE(bugprone-reserved-identifier) +#define _ZIRCON_ASSERT_ATTRIBUTE_LIKELY +#endif + +// Assert that |x| is true, else panic. +// +// ZX_ASSERT is always enabled and |x| will be evaluated regardless of any build arguments. +#define ZX_ASSERT(x) \ + do { \ + if (x) \ + _ZIRCON_ASSERT_ATTRIBUTE_LIKELY { break; } \ + else { /* NOLINT(readability-else-after-return) */ \ + ZX_PANIC("ASSERT FAILED at (%s:%d): %s", __FILE__, __LINE__, #x); \ + } \ + } while (0) + +// Assert that |x| is true, else panic with the given message. +// +// ZX_ASSERT_MSG is always enabled and |x| will be evaluated regardless of any build arguments. +#define ZX_ASSERT_MSG(x, msg, msgargs...) \ + do { \ + if (x) \ + _ZIRCON_ASSERT_ATTRIBUTE_LIKELY { break; } \ + else { \ + ZX_PANIC("ASSERT FAILED at (%s:%d): %s" msg, __FILE__, __LINE__, #x, ##msgargs); \ + } \ + } while (0) + +// Assert that |x| is true, else panic. +// +// Depending on build arguments, ZX_DEBUG_ASSERT may or may not be enabled. When disabled, |x| will +// not be evaluated. +#define ZX_DEBUG_ASSERT(x) \ + do { \ + if (ZX_DEBUG_ASSERT_IMPLEMENTED) { \ + if (x) \ + _ZIRCON_ASSERT_ATTRIBUTE_LIKELY { break; } \ + else { \ + ZX_PANIC("DEBUG ASSERT FAILED at (%s:%d): %s", __FILE__, __LINE__, #x); \ + } \ + } \ + } while (0) + +// Assert that |x| is true, else panic with the given message. +// +// Depending on build arguments, ZX_DEBUG_ASSERT_MSG may or may not be enabled. When disabled, |x| +// will not be evaluated. +#define ZX_DEBUG_ASSERT_MSG(x, msg, msgargs...) \ + do { \ + if (ZX_DEBUG_ASSERT_IMPLEMENTED) { \ + if (x) \ + _ZIRCON_ASSERT_ATTRIBUTE_LIKELY { break; } \ + else { \ + ZX_PANIC("DEBUG ASSERT FAILED at (%s:%d): %s" msg, __FILE__, __LINE__, #x, ##msgargs); \ + } \ + } \ + } while (0) + +#else // #ifdef __cplusplus + +// Assert that |x| is true, else panic. +// +// ZX_ASSERT is always enabled and |x| will be evaluated regardless of any build arguments. +#define ZX_ASSERT(x) \ + do { \ + if (unlikely(!(x))) { \ + ZX_PANIC("ASSERT FAILED at (%s:%d): %s", __FILE__, __LINE__, #x); \ + } \ + } while (0) + +// Assert that |x| is true, else panic with the given message. +// +// ZX_ASSERT_MSG is always enabled and |x| will be evaluated regardless of any build arguments. +#define ZX_ASSERT_MSG(x, msg, msgargs...) \ + do { \ + if (unlikely(!(x))) { \ + ZX_PANIC("ASSERT FAILED at (%s:%d): %s" msg, __FILE__, __LINE__, #x, ##msgargs); \ + } \ + } while (0) + +// Assert that |x| is true, else panic. +// +// Depending on build arguments, ZX_DEBUG_ASSERT may or may not be enabled. When disabled, |x| will +// not be evaluated. +#define ZX_DEBUG_ASSERT(x) \ + do { \ + if (ZX_DEBUG_ASSERT_IMPLEMENTED && unlikely(!(x))) { \ + ZX_PANIC("DEBUG ASSERT FAILED at (%s:%d): %s", __FILE__, __LINE__, #x); \ + } \ + } while (0) + +// Assert that |x| is true, else panic with the given message. +// +// Depending on build arguments, ZX_DEBUG_ASSERT_MSG may or may not be enabled. When disabled, |x| +// will not be evaluated. +#define ZX_DEBUG_ASSERT_MSG(x, msg, msgargs...) \ + do { \ + if (ZX_DEBUG_ASSERT_IMPLEMENTED && unlikely(!(x))) { \ + ZX_PANIC("DEBUG ASSERT FAILED at (%s:%d): %s" msg, __FILE__, __LINE__, #x, ##msgargs); \ + } \ + } while (0) + +#endif // #ifdef __cplusplus + // +// implement _COND versions of ZX_DEBUG_ASSERT which only emit the body if +// ZX_DEBUG_ASSERT_IMPLEMENTED is set +#if ZX_DEBUG_ASSERT_IMPLEMENTED +#define ZX_DEBUG_ASSERT_COND(x) ZX_DEBUG_ASSERT(x) +#define ZX_DEBUG_ASSERT_MSG_COND(x, msg, msgargs...) ZX_DEBUG_ASSERT_MSG(x, msg, msgargs) +#else +#define ZX_DEBUG_ASSERT_COND(x) \ + do { \ + } while (0) +#define ZX_DEBUG_ASSERT_MSG_COND(x, msg, msgargs...) \ + do { \ + } while (0) +#endif + +#endif // #ifdef _KERNEL +#endif // LIB_ZIRCON_ASSERT_ZIRCON_ASSERT_H_ diff --git a/include/zircon/compiler.h b/include/zircon/compiler.h new file mode 100644 index 0000000..45ea8d6 --- /dev/null +++ b/include/zircon/compiler.h @@ -0,0 +1,380 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file provides macros for unifying differences in C/C++ compiler +// extensions, and providing backwards-compatibility for older C++ standards. +// +// May be included by C, C++, and assembly files. + +#ifndef ZIRCON_COMPILER_H_ +#define ZIRCON_COMPILER_H_ + +// Ensure we are using a known compiler. +#if !defined(__GNUC__) && !defined(__clang__) +#error "Unrecognized compiler!" +#endif + +// Feature checking macros. +// +// If feature checking macros are not provided by the compiler, we assume that the +// checked features are unavailable. + +// C++11 attribute checking. +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +// clang feature checking. +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if !defined(__ASSEMBLER__) + +// C++ header guards. +#ifdef __cplusplus +#define __BEGIN_CDECLS extern "C" { +#define __END_CDECLS } +#else +#define __BEGIN_CDECLS +#define __END_CDECLS +#endif + +// +// Function and data attributes. +// + +// Function inlining directives. +#define __NO_INLINE __attribute__((__noinline__)) +#define __ALWAYS_INLINE __attribute__((__always_inline__)) + +// Avoid issuing a warning if the given variable/function is unused. +#ifndef __cplusplus +#define __UNUSED __attribute__((__unused__)) +#endif + +// Pack the given structure or class, omitting padding between fields. +#define __PACKED __attribute__((packed)) + +// Place the variable in thread-local storage. +#define __THREAD __thread + +// Align the variable or type to at least `x` bytes. `x` must be a power of two. +#define __ALIGNED(x) __attribute__((aligned(x))) + +// Declare the given function will never return. (such as `exit`, `abort`, etc). +#define __NO_RETURN __attribute__((__noreturn__)) + +// Warn if the result of this function is ignored by the caller. +#define __WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + +// Declare that the given stack variable may be left uninitialized if it does +// not have a specified initial value. +#if defined(__clang__) +#define __UNINITIALIZED __attribute__((uninitialized)) +#else +#define __UNINITIALIZED +#endif + +// Warn if a constructed objected is not used by the caller. +// +// Generates a warning on code like this: +// +// { +// AutoLock(&mutex); // error: the AutoLock goes out of scope immediately. +// locked_variable = 42; +// } +// +// C++17 defines [[nodiscard]] to do this, but some older but supported +// versions of GCC support [[nodiscard]] on functions but not constructors. +// Having a separate __WARN_UNUSED_CONSTRUCTOR allows us to hide the attribute +// only on constructors on old versions of GCC. +#if defined(__cplusplus) +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 10)) +#define __WARN_UNUSED_CONSTRUCTOR [[nodiscard]] +#else +#define __WARN_UNUSED_CONSTRUCTOR +#endif +#endif + +// Mark a function or variable as deprecated, warning about any callers. +#if !defined(__DEPRECATE) +#define __DEPRECATE __attribute__((__deprecated__)) +#endif + +// Mark a function as having no visible side-effects: It may read memory, but +// will not modify it. +// +// Multiple calls to the function may be optimized away by the compiler. +#define __PURE __attribute__((__pure__)) + +// Mark a function has having an output determined solely on its input +// parameters (but not memory). +// +// Multiple calls to the function may be optimized away by the compiler, even +// if memory is modified between calls. +#define __CONST __attribute__((__const__)) + +// The given function is malloc-like, returning a pointer to new, unused +// memory. +// +// The compiler can assume that the returned pointer does not alias any other +// pointer, which may help the compiler optimize the program. +#define __MALLOC __attribute__((__malloc__)) + +// The given function allocates memory of size argument |x| or |x| * |y| and returns +// a pointer to that memory. Argument indexes are one-based. The compiler can use this +// information to support compile-time __builtin_object_size checks. +#if defined(__clang__) +#define __ALLOC_SIZE(x, ...) __attribute__((__alloc_size__(x, ##__VA_ARGS__))) +#else +// TODO(fxrev.dev/571541): GCC warns incorrectly on constructs that could result in +// large allocations for type reasons but cannot for other (checked) reasons. Disable +// the attribute there. +#define __ALLOC_SIZE(x, ...) +#endif + +// Indicate that the given function takes a printf/scanf-style format string. +// +// "__fmt" is the argument number of the format string, indexed from 1. +// "__varargs" is the argument number of the variable args "..." argument +// counting from 1. +// +// If applied to a class method, the implicit "this" parameter counts as the +// first argument. +#define __PRINTFLIKE(__fmt, __varargs) __attribute__((__format__(__printf__, __fmt, __varargs))) +#define __SCANFLIKE(__fmt, __varargs) __attribute__((__format__(__scanf__, __fmt, __varargs))) + +// Indicate that the `n`th argument to a function is non-null. +// +// The compiler will emit warnings if it can prove an argument is null, and +// may optimise assuming that the values are non-null. +#define __NONNULL(n) __attribute__((__nonnull__ n)) + +// The given function is a "leaf", and won't call further functions. +// +// Leaf functions must only return directly, and not call back into the +// current compilation unit (either via direct calls, or function pointers). +// +// May help the compiler optimize calls to the function in some cases. +#define __LEAF_FN __attribute__((__leaf__)) + +// Mark the given function or variable as `constexpr`. +// +// Used in code included by both C and C++. Code that is pure C++ should use +// `constexpr` directly. +#ifdef __cplusplus +#define __CONSTEXPR constexpr +#else +#define __CONSTEXPR +#endif + +// Optimize the given function using custom flags. +// +// For example, +// +// __OPTIMIZE("O3") int myfunction() { ... } +// +// will cause GCC to optimize the function at the O3 level, independent +// of what the compiler optimization flags are. +#if !defined(__clang__) +#define __OPTIMIZE(x) __attribute__((__optimize__(x))) +#else +#define __OPTIMIZE(x) +#endif + +// Indicate the given function should not use LLVM's stack hardening features, +// but instead put all local variables on the standard stack. +// +// c.f. https://clang.llvm.org/docs/SafeStack.html +#if defined(__clang__) +#define __NO_SAFESTACK __attribute__((__no_sanitize__("safe-stack", "shadow-call-stack"))) +#else +#define __NO_SAFESTACK +#endif + +// The given C++ class or struct need not have a unique address when part of +// a larger struct or class, but can be safely collapsed into a zero-byte +// object by the compiler. +#if __has_cpp_attribute(no_unique_address) +#define __NO_UNIQUE_ADDRESS [[no_unique_address]] +#elif __has_cpp_attribute(msvc::no_unique_address) +// msvc targets, as used by efi, have a different attribute name, even when +// targeting C++20. +#define __NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +#else +#define __NO_UNIQUE_ADDRESS +#endif + +// Indicate that the given function should be treated by the Clang static +// analyzer as if it doesn't return. +// +// A workaround to help static analyzer identify assertion failures +#if defined(__clang__) +#define __ANALYZER_CREATE_SINK __attribute__((analyzer_noreturn)) +#else +#define __ANALYZER_CREATE_SINK +#endif + +// Mark the given function as externally visible, and shouldn't be optimized +// away by link-time optimizations or whole-program optimizations. +#if !defined(__clang__) +#define __EXTERNALLY_VISIBLE __attribute__((__externally_visible__)) +#else +#define __EXTERNALLY_VISIBLE +#endif + +// Declare that this function declaration should be emitted as an alias for +// another function. +#define __ALIAS(x) __attribute__((__alias__(x))) + +// Place the given global into a particular linker section. +#define __SECTION(x) __attribute__((__section__(x))) + +// The given function or global should be given a weak symbol, or a weak +// alias to another symbol. +#define __WEAK __attribute__((__weak__)) +#define __WEAK_ALIAS(x) __attribute__((__weak__, __alias__(x))) + +// The given static variable should still be emitted by the compiler, even if it +// appears unused to the compiler. +// +// Rarely needed. Not to be confused with "__UNUSED", which avoids the +// compiler warning if a variable appears unused. +#define __ALWAYS_EMIT __attribute__((__used__)) + +// Declare this object's ELF symbol visibility. +#define __EXPORT __attribute__((__visibility__("default"))) +#define __LOCAL __attribute__((__visibility__("hidden"))) + +// +// Builtin functions. +// + +// Provide a hint to the compiler that the given expression is likely/unlikely +// to be true. +// +// if (unlikely(status != ZX_OK)) { +// error(...); +// } +// +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +// Return the program counter of the calling function. +#define __GET_CALLER(x) __builtin_return_address(0) + +// Return the address of the current stack frame. +#define __GET_FRAME(x) __builtin_frame_address(0) + +// Return true if the given expression is a known compile-time constant. +#define __ISCONSTANT(x) __builtin_constant_p(x) + +// Assume this branch of code cannot be reached. +#define __UNREACHABLE __builtin_unreachable() + +// Get the offset of `field` from the beginning of the struct or class `type`. +#define __offsetof(type, field) __builtin_offsetof(type, field) + +// Perform an arithmetic operation, returning "true" if the operation overflowed. +// +// Equivalent to: { *result = a + b; return _overflow_occurred; } +#define add_overflow(a, b, result) __builtin_add_overflow(a, b, result) +#define sub_overflow(a, b, result) __builtin_sub_overflow(a, b, result) +#define mul_overflow(a, b, result) __builtin_mul_overflow(a, b, result) + +// Indicate the given case of a switch statement is intended to fall through +// to the next case, and avoid generating a compiler warning. +// +// switch (n) { +// case 0: +// case 1: +// handle_zero_and_one_case(); +// __FALLTHROUGH; +// default: +// handle_all_cases(); +// break; +// } +// +#if defined(__cplusplus) +#define __FALLTHROUGH [[fallthrough]] +#elif defined(__cplusplus) && defined(__clang__) +#define __FALLTHROUGH [[clang::fallthrough]] +// The GNU style attribute is supported by Clang for C code, but __GNUC__ for +// clang right now is 4. +#elif __GNUC__ >= 7 || (!defined(__cplusplus) && defined(__clang__)) +#define __FALLTHROUGH __attribute__((__fallthrough__)) +#else +#define __FALLTHROUGH \ + do { \ + } while (0) +#endif + +// Locking annotations. +// +// The following annotations allow compile-time checking that annotated data +// is only accessed while holding the correct locks. +// +// The annotations are only supported by Clang, and frequently used with C++ +// standard library types in userspace, so only enable in Clang when we know +// that the C++ standard library types are annotated or if we're in kernel +// code. +#if defined(__clang__) && (defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) || defined(_KERNEL)) +#define __THREAD_ANNOTATION(x) __attribute__((x)) +#else +#define __THREAD_ANNOTATION(x) +#endif +#define __TA_CAPABILITY(x) __THREAD_ANNOTATION(__capability__(x)) +#define __TA_GUARDED(x) __THREAD_ANNOTATION(__guarded_by__(x)) +#define __TA_ACQUIRE(...) __THREAD_ANNOTATION(__acquire_capability__(__VA_ARGS__)) +#define __TA_ACQUIRE_SHARED(...) __THREAD_ANNOTATION(__acquire_shared_capability__(__VA_ARGS__)) +#define __TA_TRY_ACQUIRE(...) __THREAD_ANNOTATION(__try_acquire_capability__(__VA_ARGS__)) +#define __TA_TRY_ACQUIRE_SHARED(...) \ + __THREAD_ANNOTATION(__try_acquire_shared_capability__(__VA_ARGS__)) +// Neither ACQUIRED_BEFORE nor ACQUIRED_AFTER are implemented in clang. Users of these macros must +// not rely upon them to catch lock ordering bugs, and must treat them as documentation only. +// See: +// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#acquired-before-and-acquired-after-are-currently-unimplemented +#define __TA_ACQUIRED_BEFORE(...) __THREAD_ANNOTATION(__acquired_before__(__VA_ARGS__)) +#define __TA_ACQUIRED_AFTER(...) __THREAD_ANNOTATION(__acquired_after__(__VA_ARGS__)) +#define __TA_RELEASE(...) __THREAD_ANNOTATION(__release_capability__(__VA_ARGS__)) +#define __TA_RELEASE_SHARED(...) __THREAD_ANNOTATION(__release_shared_capability__(__VA_ARGS__)) +#define __TA_REQUIRES(...) __THREAD_ANNOTATION(__requires_capability__(__VA_ARGS__)) +#define __TA_REQUIRES_SHARED(...) __THREAD_ANNOTATION(__requires_shared_capability__(__VA_ARGS__)) +#define __TA_EXCLUDES(...) __THREAD_ANNOTATION(__locks_excluded__(__VA_ARGS__)) +#define __TA_ASSERT(...) __THREAD_ANNOTATION(__assert_capability__(__VA_ARGS__)) +#define __TA_ASSERT_SHARED(...) __THREAD_ANNOTATION(__assert_shared_capability__(__VA_ARGS__)) +#define __TA_RETURN_CAPABILITY(x) __THREAD_ANNOTATION(__lock_returned__(x)) +#define __TA_SCOPED_CAPABILITY __THREAD_ANNOTATION(__scoped_lockable__) +#define __TA_NO_THREAD_SAFETY_ANALYSIS __THREAD_ANNOTATION(__no_thread_safety_analysis__) + +// Experimental lifetime analysis annotations. +#ifndef __OWNER +#ifdef __clang__ +#define __OWNER(x) [[gsl::Owner(x)]] +#define __POINTER(x) [[gsl::Pointer(x)]] +#else +#define __OWNER(x) +#define __POINTER(x) +#endif +#endif + +#if defined(__cpp_constinit) && __cpp_constinit >= 201907L +#define __CONSTINIT constinit +#elif defined(__clang__) +#define __CONSTINIT [[clang::require_constant_initialization]] +#elif defined(__GNUC__) && __GNUC__ >= 13 +#define __CONSTINIT __constinit +#else +#define __CONSTINIT +#endif + +#endif // !defined(__ASSEMBLER__) + +#endif // ZIRCON_COMPILER_H_ |
