From a9b2f0495cabb1ff01b51bcd0625cb1fd82da4ce Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 14 Oct 2022 11:00:07 -0700 Subject: Use attribute testing to simplify portable attribute macros Fixes #4025 PiperOrigin-RevId: 481186097 Change-Id: Id7d09e4626e5ccf564e8cfaa65581c1cd827918d --- googletest/include/gtest/internal/gtest-port.h | 85 +++++++++++--------------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index 3556fdb9..50d4c41f 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -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) -#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused)) -#elif defined(__clang__) -#if __has_attribute(unused) +#if GTEST_HAVE_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 { -- cgit v1.2.3