From 4bb09d7bd1790b735f2957ae92fc76e967a122d5 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Thu, 3 Sep 2020 12:05:04 +0800
Subject: [PATCH 7/9] Use __has_attribute for compiler attribute detection
 where possible

GCC 5, LLVM clang, suncc 5.13, and increasingly other toolchains
support the __has_attribute function-like macro as a preprocessor
extension. This macro can be used to detect whether a given
__attribute__((attname)) is supported by the compiler without needing
external configure tests etc.

Adopt this in c.h in place of explicit tests for __GNUC__ where
possible. While clang and llvm both define __GNUC__ to version
comparable to the equivalent gcc feature set, it's more explicit to
test for the actual features we want rather than a compiler version.
---
 revertme        | 17 +++++++++
 src/include/c.h | 92 ++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 96 insertions(+), 13 deletions(-)
 create mode 100644 revertme

diff --git a/revertme b/revertme
new file mode 100644
index 0000000000..1b177c71eb
--- /dev/null
+++ b/revertme
@@ -0,0 +1,17 @@
+diff --git a/src/include/c.h b/src/include/c.h
+index f2cd6e12a0..1d1f489d34 100644
+--- a/src/include/c.h
++++ b/src/include/c.h
+@@ -205,8 +205,11 @@
+  * See
+  *  - the pgl_errcontext_check() macro in elog.h
+  *  - https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute
++ *
++ * Added in gcc 3.4, but that's so old we'll just require gcc4.  clang claims
++ * to be a much newer gcc, so it'll be fine.
+  */
+-#if __has_attribute(cleanup)
++#if __GNUC__ >= 4
+ #define pgl_attribute_cleanup(cb) __attribute__((cleanup(cb)))
+ #ifdef USE_ASSERT_CHECKING
+ #define pgl_attribute_cleanup_cassert(cb) __attribute__((cleanup(cb)))
diff --git a/src/include/c.h b/src/include/c.h
index 5ded7f3d16..237dd6e679 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -85,26 +85,71 @@
 
 /*
  * Disable "inline" if PG_FORCE_DISABLE_INLINE is defined.
+ *
  * This is used to work around compiler bugs and might also be useful for
  * investigatory purposes.
+ *
+ * In most cases it's better to use -fno-inline.
  */
 #ifdef PG_FORCE_DISABLE_INLINE
 #undef inline
 #define inline
 #endif
 
+/*
+ * Attribute macro support detection.
+ *
+ * GCC, LLVM's clang and sunpro C all support the __has_attribute preprocessor
+ * extension to allow for compile-time detection of individual attribute
+ * support without needing to use configure tests, compiler version guards,
+ * etc.
+ *
+ * __has_attribute was added in:
+ *
+ * - clang 2.9 (2010)
+ * - gcc 5 (2014)
+ * - suncc 5.13 (late 2014)
+ *
+ * See:
+ *
+ * - https://clang.llvm.org/docs/LanguageExtensions.html
+ * - https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html
+ *
+ * We'll treat GCC and clang versions older than these as not supporting the
+ * attribute tested for.
+ *
+ * Explicit tests are still required for newer compilers that support some
+ * attributes we want, but not the __has_attribute test, like XLC or older
+ * SUNPRO compilers.
+ */
+#ifdef __has_attribute
+#define pg_has_attribute(attname) __has_attribute(attname)
+#else
+#define pg_has_attribute(attname) 0
+#endif
+
+/* Expose the similar __has_builtin for convenience here too */
+#ifdef __has_builtin
+#define pg_has_builtin(builtinname) __has_builtin(builtinname)
+#else
+#define pg_has_builtin(builtinname) 0
+#endif
+
 /*
  * Attribute macros
  *
  * GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
  * GCC: https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
  * Sunpro: https://docs.oracle.com/cd/E18659_01/html/821-1384/gjzke.html
+ *         https://docs.oracle.com/cd/E77782_01/html/E77788/gjzke.html
  * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/function_attributes.html
  * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/type_attrib.html
  */
 
-/* only GCC supports the unused attribute */
-#ifdef __GNUC__
+/*
+ * Unused attribute: silence warnings for unused variables, functions, etc.
+ */
+#if pg_has_attribute(unused)
 #define pg_attribute_unused() __attribute__((unused))
 #else
 #define pg_attribute_unused()
@@ -121,8 +166,11 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
-/* GCC and XLC support format attributes */
-#if defined(__GNUC__) || defined(__IBMC__)
+/*
+ * GCC/clang and XLC support format attributes to check the arguments of
+ * printf()-style variadic argument lists against the format string.
+ */
+#if (pg_has_attribute(format) && pg_has_attribute(format_arg)) || defined(__IBMC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
 #define pg_attribute_printf(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE, f, a)))
 #else
@@ -130,19 +178,24 @@
 #define pg_attribute_printf(f,a)
 #endif
 
-/* GCC, Sunpro and XLC support aligned, packed and noreturn */
-#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
-#define pg_attribute_aligned(a) __attribute__((aligned(a)))
+/* GCC/clang, Sunpro and XLC support noreturn */
+#if pg_has_attribute(noreturn) || defined(__SUNPRO_C) || defined(__IBMC__)
 #define pg_attribute_noreturn() __attribute__((noreturn))
-#define pg_attribute_packed() __attribute__((packed))
 #define HAVE_PG_ATTRIBUTE_NORETURN 1
 #else
+#define pg_attribute_noreturn()
+#endif
+
+/* GCC/clang, Sunpro and XLC support aligned and packed  */
+#if (pg_has_attribute(aligned) && pg_has_attribute(packed)) || defined(__SUNPRO_C) || defined(__IBMC__)
+#define pg_attribute_aligned(a) __attribute__((aligned(a)))
+#define pg_attribute_packed() __attribute__((packed))
+#else
 /*
  * NB: aligned and packed are not given default definitions because they
  * affect code functionality; they *must* be implemented by the compiler
  * if they are to be used.
  */
-#define pg_attribute_noreturn()
 #endif
 
 /*
@@ -151,8 +204,12 @@
  * choose not to.  But, if possible, don't force inlining in unoptimized
  * debug builds.
  */
-#if (defined(__GNUC__) && __GNUC__ > 3 && defined(__OPTIMIZE__)) || defined(__SUNPRO_C) || defined(__IBMC__)
-/* GCC > 3, Sunpro and XLC support always_inline via __attribute__ */
+#if defined(__NO_INLINE__) || defined(PG_FORCE_DISABLE_INLINE)
+/* Omit force inline completely if optimisation is off or inlining disabled */
+#define pg_attribute_always_inline
+#else
+#if pg_has_attribute(always_inline) || defined(__SUNPRO_C) || defined(__IBMC__)
+/* GCC, Sunpro and XLC support always_inline via __attribute__ */
 #define pg_attribute_always_inline __attribute__((always_inline)) inline
 #elif defined(_MSC_VER)
 /* MSVC has a special keyword for this */
@@ -161,6 +218,7 @@
 /* Otherwise, the best we can do is to say "inline" */
 #define pg_attribute_always_inline inline
 #endif
+#endif
 
 /*
  * Forcing a function not to be inlined can be useful if it's the slow path of
@@ -169,7 +227,7 @@
  * above, this should be placed before the function's return type and name.
  */
 /* GCC, Sunpro and XLC support noinline via __attribute__ */
-#if (defined(__GNUC__) && __GNUC__ > 2) || defined(__SUNPRO_C) || defined(__IBMC__)
+#if __has_attribute(nolinline) || defined(__SUNPRO_C) || defined(__IBMC__)
 #define pg_noinline __attribute__((noinline))
 /* msvc via declspec */
 #elif defined(_MSC_VER)
@@ -240,8 +298,12 @@
  *
  * These should only be used sparingly, in very hot code paths. It's very easy
  * to mis-estimate likelihoods.
+ *
+ * Disable by defining PG_FORCE_DISABLE_BRANCH_HINTS in pg_config_manual.h when
+ * looking into branch prediction hinting issues, or per-file by defining it
+ * before including postgresql.h.
  */
-#if __GNUC__ >= 3
+#if pg_has_builtin(__builtin_expect)
 #define likely(x)	__builtin_expect((x) != 0, 1)
 #define unlikely(x) __builtin_expect((x) != 0, 0)
 #else
@@ -250,6 +312,8 @@
 #endif
 
 /*
+ * PostgreSQL aliases for C preprocessor token pasting and stringification.
+ *
  * CppAsString
  *		Convert the argument to a string, using the C preprocessor.
  * CppAsString2
@@ -260,6 +324,8 @@
  * Note: There used to be support here for pre-ANSI C compilers that didn't
  * support # and ##.  Nowadays, these macros are just for clarity and/or
  * backward compatibility with existing PostgreSQL code.
+ *
+ * A common use of CppAsString is to stringify the names of enums.
  */
 #define CppAsString(identifier) #identifier
 #define CppAsString2(x)			CppAsString(x)
-- 
2.26.2

