// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_ #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_ #include "partition_alloc/build_config.h" // A wrapper around `__has_cpp_attribute`. #if defined(__has_cpp_attribute) #define PA_HAS_CPP_ATTRIBUTE(x) … #else #define PA_HAS_CPP_ATTRIBUTE … #endif // A wrapper around `__has_attribute`, similar to PA_HAS_CPP_ATTRIBUTE. #if defined(__has_attribute) #define PA_HAS_ATTRIBUTE(x) … #else #define PA_HAS_ATTRIBUTE … #endif // A wrapper around `__has_builtin`, similar to PA_HAS_CPP_ATTRIBUTE. #if defined(__has_builtin) #define PA_HAS_BUILTIN(x) … #else #define PA_HAS_BUILTIN … #endif // Annotate a function indicating it should not be inlined. // Use like: // NOINLINE void DoStuff() { ... } #if defined(__clang__) && PA_HAS_ATTRIBUTE(noinline) #define PA_NOINLINE … #elif PA_BUILDFLAG(PA_COMPILER_GCC) && PA_HAS_ATTRIBUTE(noinline) #define PA_NOINLINE … #elif PA_BUILDFLAG(PA_COMPILER_MSVC) #define PA_NOINLINE … #else #define PA_NOINLINE #endif #if defined(__clang__) && defined(NDEBUG) && PA_HAS_ATTRIBUTE(always_inline) #define PA_ALWAYS_INLINE … #elif PA_BUILDFLAG(PA_COMPILER_GCC) && defined(NDEBUG) && \ PA_HAS_ATTRIBUTE(always_inline) #define PA_ALWAYS_INLINE … #elif PA_BUILDFLAG(PA_COMPILER_MSVC) && defined(NDEBUG) #define PA_ALWAYS_INLINE … #else #define PA_ALWAYS_INLINE … #endif // Annotate a function indicating it should never be tail called. Useful to make // sure callers of the annotated function are never omitted from call-stacks. // To provide the complementary behavior (prevent the annotated function from // being omitted) look at NOINLINE. Also note that this doesn't prevent code // folding of multiple identical caller functions into a single signature. To // prevent code folding, see NO_CODE_FOLDING() in base/debug/alias.h. // Use like: // void NOT_TAIL_CALLED FooBar(); #if defined(__clang__) && PA_HAS_ATTRIBUTE(not_tail_called) #define PA_NOT_TAIL_CALLED … #else #define PA_NOT_TAIL_CALLED #endif // Annotate a function indicating it must be tail called. // Can be used only on return statements, even for functions returning void. // Caller and callee must have the same number of arguments and its types must // be "similar". #if defined(__clang__) && PA_HAS_ATTRIBUTE(musttail) #define PA_MUSTTAIL … #else #define PA_MUSTTAIL #endif // In case the compiler supports it PA_NO_UNIQUE_ADDRESS evaluates to the C++20 // attribute [[no_unique_address]]. This allows annotating data members so that // they need not have an address distinct from all other non-static data members // of its class. // // References: // * https://en.cppreference.com/w/cpp/language/attributes/no_unique_address // * https://wg21.link/dcl.attr.nouniqueaddr #if PA_BUILDFLAG(PA_COMPILER_MSVC) && \ PA_HAS_CPP_ATTRIBUTE(msvc::no_unique_address) // Unfortunately MSVC ignores [[no_unique_address]] (see // https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#msvc-extensions-and-abi), // and clang-cl matches it for ABI compatibility reasons. We need to prefer // [[msvc::no_unique_address]] when available if we actually want any effect. #define PA_NO_UNIQUE_ADDRESS … #elif PA_HAS_CPP_ATTRIBUTE(no_unique_address) #define PA_NO_UNIQUE_ADDRESS … #else #define PA_NO_UNIQUE_ADDRESS #endif // Tells the compiler a function is using a printf-style format string. // |format_param| is the one-based index of the format string parameter; // |dots_param| is the one-based index of the "..." parameter. // For v*printf functions (which take a va_list), pass 0 for dots_param. // (This is undocumented but matches what the system C headers do.) // For member functions, the implicit this parameter counts as index 1. #if (PA_BUILDFLAG(PA_COMPILER_GCC) || defined(__clang__)) && \ PA_HAS_ATTRIBUTE(format) #define PA_PRINTF_FORMAT(format_param, dots_param) … #else #define PA_PRINTF_FORMAT … #endif // Sanitizers annotations. #if PA_HAS_ATTRIBUTE(no_sanitize) #define PA_NO_SANITIZE(what) … #endif #if !defined(PA_NO_SANITIZE) #define PA_NO_SANITIZE … #endif // MemorySanitizer annotations. #if defined(MEMORY_SANITIZER) #include <sanitizer/msan_interface.h> // Mark a memory region fully initialized. // Use this to annotate code that deliberately reads uninitialized data, for // example a GC scavenging root set pointers from the stack. #define PA_MSAN_UNPOISON … #else // MEMORY_SANITIZER #define PA_MSAN_UNPOISON(p, size) … #endif // MEMORY_SANITIZER // Compiler feature-detection. // clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension #if defined(__has_feature) #define PA_HAS_FEATURE(FEATURE) … #else #define PA_HAS_FEATURE … #endif // The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints // to Clang which control what code paths are statically analyzed, // and is meant to be used in conjunction with assert & assert-like functions. // The expression is passed straight through if analysis isn't enabled. // // ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current // codepath and any other branching codepaths that might follow. #if defined(__clang_analyzer__) namespace partition_alloc::internal { inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) { return false; } inline constexpr bool AnalyzerAssumeTrue(bool arg) { // PartitionAllocAnalyzerNoReturn() is invoked and analysis is terminated if // |arg| is false. return arg || AnalyzerNoReturn(); } } // namespace partition_alloc::internal #define PA_ANALYZER_ASSUME_TRUE … #define PA_ANALYZER_SKIP_THIS_PATH … #else // !defined(__clang_analyzer__) #define PA_ANALYZER_ASSUME_TRUE(arg) … #define PA_ANALYZER_SKIP_THIS_PATH() … #endif // defined(__clang_analyzer__) // Use nomerge attribute to disable optimization of merging multiple same calls. #if defined(__clang__) && PA_HAS_ATTRIBUTE(nomerge) #define PA_NOMERGE … #else #define PA_NOMERGE #endif // Marks a type as being eligible for the "trivial" ABI despite having a // non-trivial destructor or copy/move constructor. Such types can be relocated // after construction by simply copying their memory, which makes them eligible // to be passed in registers. The canonical example is std::unique_ptr. // // Use with caution; this has some subtle effects on constructor/destructor // ordering and will be very incorrect if the type relies on its address // remaining constant. When used as a function argument (by value), the value // may be constructed in the caller's stack frame, passed in a register, and // then used and destructed in the callee's stack frame. A similar thing can // occur when values are returned. // // TRIVIAL_ABI is not needed for types which have a trivial destructor and // copy/move constructors, such as base::TimeTicks and other POD. // // It is also not likely to be effective on types too large to be passed in one // or two registers on typical target ABIs. // // See also: // https://clang.llvm.org/docs/AttributeReference.html#trivial-abi // https://libcxx.llvm.org/docs/DesignDocs/UniquePtrTrivialAbi.html #if defined(__clang__) && PA_HAS_ATTRIBUTE(trivial_abi) #define PA_TRIVIAL_ABI … #else #define PA_TRIVIAL_ABI #endif // Requires constant initialization. See constinit in C++20. Allows to rely on a // variable being initialized before execution, and not requiring a global // constructor. #if PA_HAS_ATTRIBUTE(require_constant_initialization) #define PA_CONSTINIT … #endif #if !defined(PA_CONSTINIT) #define PA_CONSTINIT #endif #if defined(__clang__) #define PA_GSL_POINTER … #else #define PA_GSL_POINTER #endif // Constexpr destructors were introduced in C++20. PartitionAlloc's minimum // supported C++ version is C++17. #if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L #define PA_CONSTEXPR_DTOR … #else #define PA_CONSTEXPR_DTOR #endif // PA_LIFETIME_BOUND indicates that a resource owned by a function parameter or // implicit object parameter is retained by the return value of the annotated // function (or, for a parameter of a constructor, in the value of the // constructed object). This attribute causes warnings to be produced if a // temporary object does not live long enough. // // When applied to a reference parameter, the referenced object is assumed to be // retained by the return value of the function. When applied to a non-reference // parameter (for example, a pointer or a class type), all temporaries // referenced by the parameter are assumed to be retained by the return value of // the function. // // See also the upstream documentation: // https://clang.llvm.org/docs/AttributeReference.html#lifetimebound // // This attribute is based on `ABSL_ATTRIBUTE_LIFETIME_BOUND`, but: // * A separate definition is provided to avoid PartitionAlloc => Abseil // dependency // * The definition is tweaked to avoid `__attribute__(lifetime))` because it // can't be applied in the same places as `[[clang::lifetimebound]]`. In // particular `operator T*&() && __attribute__(lifetime))` fails to compile on // `clang` with the following error: 'lifetimebound' attribute only applies to // parameters and implicit object parameters #if PA_HAS_CPP_ATTRIBUTE(clang::lifetimebound) #define PA_LIFETIME_BOUND … #else #define PA_LIFETIME_BOUND #endif // Clang instrumentation may allocate, leading to reentrancy in the allocator, // and crashes when generating a PGO profile. This attribute disables profiling // for a function. // // See // https://clang.llvm.org/docs/AttributeReference.html#no-profile-instrument-function #if PA_HAS_CPP_ATTRIBUTE(gnu::no_profile_instrument_function) #define PA_NOPROFILE … #else #define PA_NOPROFILE #endif #endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_