Use attribute testing to simplify portable attribute macros

Fixes #4025

PiperOrigin-RevId: 481186097
Change-Id: Id7d09e4626e5ccf564e8cfaa65581c1cd827918d
This commit is contained in:
Derek Mauro 2022-10-14 11:00:07 -07:00 committed by Copybara-Service
parent 137b6e2770
commit a9b2f0495c

View File

@ -642,6 +642,22 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
default: // NOLINT
#endif
// GTEST_HAVE_ATTRIBUTE_
//
// A function-like feature checking macro that is a wrapper around
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
// nonzero constant integer if the attribute is supported or 0 if not.
//
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
//
// GCC: https://gcc.gnu.org/gcc-5/changes.html
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
#ifdef __has_attribute
#define GTEST_HAVE_ATTRIBUTE_(x) __has_attribute(x)
#else
#define GTEST_HAVE_ATTRIBUTE_(x) 0
#endif
// Use this annotation at the end of a struct/class definition to
// prevent the compiler from optimizing away instances that are never
// used. This is useful when all interesting logic happens inside the
@ -653,30 +669,22 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
//
// Also use it after a variable or parameter declaration to tell the
// compiler the variable/parameter does not have to be used.
#if defined(__GNUC__) && !defined(COMPILER_ICC)
#if GTEST_HAVE_ATTRIBUTE_(unused)
#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused))
#elif defined(__clang__)
#if __has_attribute(unused)
#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused))
#endif
#endif
#ifndef GTEST_ATTRIBUTE_UNUSED_
#else
#define GTEST_ATTRIBUTE_UNUSED_
#endif
// Use this annotation before a function that takes a printf format string.
#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC)
#if defined(__MINGW_PRINTF_FORMAT)
#if GTEST_HAVE_ATTRIBUTE_(format) && defined(__MINGW_PRINTF_FORMAT)
// MinGW has two different printf implementations. Ensure the format macro
// matches the selected implementation. See
// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/.
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
__attribute__(( \
__format__(__MINGW_PRINTF_FORMAT, string_index, first_to_check)))
#else
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
__attribute__((__format__(__printf__, string_index, first_to_check)))
#endif
__attribute__((format(__MINGW_PRINTF_FORMAT, string_index, first_to_check)))
#elif GTEST_HAVE_ATTRIBUTE_(format)
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
__attribute__((format(printf, string_index, first_to_check)))
#else
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
#endif
@ -686,11 +694,11 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
// following the argument list:
//
// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
#if defined(__GNUC__) && !defined(COMPILER_ICC)
#if GTEST_HAVE_ATTRIBUTE_(warn_unused_result)
#define GTEST_MUST_USE_RESULT_ __attribute__((warn_unused_result))
#else
#define GTEST_MUST_USE_RESULT_
#endif // __GNUC__ && !COMPILER_ICC
#endif
// MS C++ compiler emits warning when a conditional expression is compile time
// constant. In some contexts this warning is false positive and needs to be
@ -746,7 +754,7 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#elif GTEST_CREATE_SHARED_LIBRARY
#define GTEST_API_ __declspec(dllexport)
#endif
#elif __GNUC__ >= 4 || defined(__clang__)
#elif GTEST_HAVE_ATTRIBUTE_(visibility)
#define GTEST_API_ __attribute__((visibility("default")))
#endif // _MSC_VER
@ -760,20 +768,17 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#define GTEST_DEFAULT_DEATH_TEST_STYLE "fast"
#endif // GTEST_DEFAULT_DEATH_TEST_STYLE
#ifdef __GNUC__
#if GTEST_HAVE_ATTRIBUTE_(noinline)
// Ask the compiler to never inline a given function.
#define GTEST_NO_INLINE_ __attribute__((noinline))
#else
#define GTEST_NO_INLINE_
#endif
#if defined(__clang__)
// Nested ifs to avoid triggering MSVC warning.
#if __has_attribute(disable_tail_calls)
#if GTEST_HAVE_ATTRIBUTE_(disable_tail_calls)
// Ask the compiler not to perform tail call optimization inside
// the marked function.
#define GTEST_NO_TAIL_CALL_ __attribute__((disable_tail_calls))
#endif
#elif __GNUC__
#define GTEST_NO_TAIL_CALL_ \
__attribute__((optimize("no-optimize-sibling-calls")))
@ -792,50 +797,34 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
// A function level attribute to disable checking for use of uninitialized
// memory when built with MemorySanitizer.
#if defined(__clang__)
#if __has_feature(memory_sanitizer)
#if GTEST_HAVE_ATTRIBUTE_(no_sanitize_memory)
#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ __attribute__((no_sanitize_memory))
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
#endif // __has_feature(memory_sanitizer)
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
#endif // __clang__
#endif
// A function level attribute to disable AddressSanitizer instrumentation.
#if defined(__clang__)
#if __has_feature(address_sanitizer)
#if GTEST_HAVE_ATTRIBUTE_(no_sanitize_address)
#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \
__attribute__((no_sanitize_address))
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
#endif // __has_feature(address_sanitizer)
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
#endif // __clang__
#endif
// A function level attribute to disable HWAddressSanitizer instrumentation.
#if defined(__clang__)
#if __has_feature(hwaddress_sanitizer)
#if GTEST_HAVE_ATTRIBUTE_(no_sanitize)
#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \
__attribute__((no_sanitize("hwaddress")))
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
#endif // __has_feature(hwaddress_sanitizer)
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
#endif // __clang__
#endif
// A function level attribute to disable ThreadSanitizer instrumentation.
#if defined(__clang__)
#if __has_feature(thread_sanitizer)
#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ __attribute__((no_sanitize_thread))
#if GTEST_HAVE_ATTRIBUTE_(no_sanitize_thread)
#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ __attribute((no_sanitize_thread))
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
#endif // __has_feature(thread_sanitizer)
#else
#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
#endif // __clang__
#endif
namespace testing {