From 18257373a6a972f154352985232e1051e075deff Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 4 Mar 2026 17:30:46 +1300 Subject: [PATCH v4 06/21] Provide way for macros to detect PG_TRY scope. For code that can't work safely around setjmp()/longjmp() and thus in a PG_TRY/CATCH/FINALLY block, provide a macro "pg_in_lexical_scope(PG_TRY)" that can be tested at compile time. --- configure | 101 +++++++++++++++++++++++++++++++++++++ configure.ac | 13 +++++ meson.build | 9 ++++ src/include/c.h | 27 ++++++++++ src/include/pg_config.h.in | 6 +++ src/include/utils/elog.h | 36 +++++++++++++ 6 files changed, 192 insertions(+) diff --git a/configure b/configure index 2b80b62dffe..a5ee71cf728 100755 --- a/configure +++ b/configure @@ -5992,6 +5992,107 @@ if test x"$pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local" = x"yes"; then fi + # We also want to make the usage of the above options available to macros. + NOT_THE_CFLAGS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wshadow=compatible-local, for NOT_THE_CFLAGS" >&5 +$as_echo_n "checking whether ${CC} supports -Wshadow=compatible-local, for NOT_THE_CFLAGS... " >&6; } +if ${pgac_cv_prog_CC_cflags__Wshadow_compatible_local+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_save_CFLAGS=$CFLAGS +pgac_save_CC=$CC +CC=${CC} +CFLAGS="${NOT_THE_CFLAGS} -Wshadow=compatible-local" +ac_save_c_werror_flag=$ac_c_werror_flag +ac_c_werror_flag=yes +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + pgac_cv_prog_CC_cflags__Wshadow_compatible_local=yes +else + pgac_cv_prog_CC_cflags__Wshadow_compatible_local=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_c_werror_flag=$ac_save_c_werror_flag +CFLAGS="$pgac_save_CFLAGS" +CC="$pgac_save_CC" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CC_cflags__Wshadow_compatible_local" >&5 +$as_echo "$pgac_cv_prog_CC_cflags__Wshadow_compatible_local" >&6; } +if test x"$pgac_cv_prog_CC_cflags__Wshadow_compatible_local" = x"yes"; then + NOT_THE_CFLAGS="${NOT_THE_CFLAGS} -Wshadow=compatible-local" +fi + + if test -n "$NOT_THE_CFLAGS"; then + +$as_echo "#define WARNING_CC_SHADOW_COMPATIBLE_LOCAL 1" >>confdefs.h + + fi + NOT_THE_CFLAGS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CXX} supports -Wshadow=compatible-local, for NOT_THE_CFLAGS" >&5 +$as_echo_n "checking whether ${CXX} supports -Wshadow=compatible-local, for NOT_THE_CFLAGS... " >&6; } +if ${pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_save_CXXFLAGS=$CXXFLAGS +pgac_save_CXX=$CXX +CXX=${CXX} +CXXFLAGS="${NOT_THE_CFLAGS} -Wshadow=compatible-local" +ac_save_cxx_werror_flag=$ac_cxx_werror_flag +ac_cxx_werror_flag=yes +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local=yes +else + pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_cxx_werror_flag=$ac_save_cxx_werror_flag +CXXFLAGS="$pgac_save_CXXFLAGS" +CXX="$pgac_save_CXX" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local" >&5 +$as_echo "$pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local" >&6; } +if test x"$pgac_cv_prog_CXX_cxxflags__Wshadow_compatible_local" = x"yes"; then + NOT_THE_CFLAGS="${NOT_THE_CFLAGS} -Wshadow=compatible-local" +fi + + if test -n "$NOT_THE_CFLAGS"; then + +$as_echo "#define WARNING_CXX_SHADOW_COMPATIBLE_LOCAL 1" >>confdefs.h + + fi # This was included in -Wall/-Wformat in older GCC versions { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wformat-security, for CFLAGS" >&5 diff --git a/configure.ac b/configure.ac index e0c4a089f61..b13cfa1813f 100644 --- a/configure.ac +++ b/configure.ac @@ -577,6 +577,19 @@ if test "$GCC" = yes -a "$ICC" = no; then PGAC_PROG_CXX_CFLAGS_OPT([-Wcast-function-type]) PGAC_PROG_CC_CFLAGS_OPT([-Wshadow=compatible-local]) PGAC_PROG_CXX_CFLAGS_OPT([-Wshadow=compatible-local]) + # We also want to make the usage of the above options available to macros. + NOT_THE_CFLAGS="" + PGAC_PROG_VARCC_VARFLAGS_OPT(CC, NOT_THE_CFLAGS, [-Wshadow=compatible-local]) + if test -n "$NOT_THE_CFLAGS"; then + AC_DEFINE([WARNING_CC_SHADOW_COMPATIBLE_LOCAL], 1, + [Define to 1 if your C compiler understands -Wshadow=compatible-local]) + fi + NOT_THE_CFLAGS="" + PGAC_PROG_VARCXX_VARFLAGS_OPT(CXX, NOT_THE_CFLAGS, [-Wshadow=compatible-local]) + if test -n "$NOT_THE_CFLAGS"; then + AC_DEFINE([WARNING_CXX_SHADOW_COMPATIBLE_LOCAL], 1, + [Define to 1 if your C++ compiler understands -Wshadow=compatible-local]) + fi # This was included in -Wall/-Wformat in older GCC versions PGAC_PROG_CC_CFLAGS_OPT([-Wformat-security]) PGAC_PROG_CXX_CFLAGS_OPT([-Wformat-security]) diff --git a/meson.build b/meson.build index 12dc989a5ab..db1f38dff93 100644 --- a/meson.build +++ b/meson.build @@ -2208,6 +2208,15 @@ if have_cxx cxxflags_warn += cxx.get_supported_arguments(common_warning_flags) endif +# Advertise whether -Wshadow=compatible-local is active, so that it can be +# disabled in cases where that is expected. +if cc.has_argument('-Wshadow=compatible-local') + cdata.set('WARNING_CC_SHADOW_COMPATIBLE_LOCAL', 1) +endif +if have_cxx and cxx.has_argument('-Wshadow=compatible-local') + cdata.set('WARNING_CXX_SHADOW_COMPATIBLE_LOCAL', 1) +endif + # To require fallthrough attribute annotations, use # -Wimplicit-fallthrough=5 with gcc and -Wimplicit-fallthrough with # clang. The latter is also accepted on gcc but does not enforce diff --git a/src/include/c.h b/src/include/c.h index 29fef2f54e1..97ba778eb90 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -561,6 +561,33 @@ typedef void (*pg_funcptr_t) (void); #define HAVE_PRAGMA_GCC_SYSTEM_HEADER 1 #endif +/* + * Sometimes it is useful to be able to disable GCC's shadow warnings for a + * specific declaration. + * + * -Wdeclaration-after-statement is also temporarily suppressed, because the + * pragma itself is treated as a statement while the purpose of these macros + * is to wrap a declaration. + */ +#if !defined(__clang__) && \ + ((defined(__cplusplus) && defined(WARNING_CXX_SHADOW_COMPATIBLE_LOCAL)) || \ + (!defined(__cplusplus) && defined(WARNING_CC_SHADOW_COMPATIBLE_LOCAL))) +#if !defined(__cplusplus) +#define pg_pragma_ignore_declaration_after_statement \ + _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\""); +#else +#define pg_pragma_ignore_declaration_after_statement +#endif +#define pg_begin_ignore_shadow_warning() \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wshadow=compatible-local\""); \ + pg_pragma_ignore_declaration_after_statement +#define pg_end_ignore_shadow_warning() \ + _Pragma("GCC diagnostic pop") +#else +#define pg_begin_ignore_shadow_warning() +#define pg_end_ignore_shadow_warning() +#endif /* ---------------------------------------------------------------- * Section 2: bool, true, false diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index c4574406e04..f956012be3d 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -762,6 +762,12 @@ /* Define to 1 to build with ZSTD support. (--with-zstd) */ #undef USE_ZSTD +/* Define to 1 if your C compiler understands -Wshadow=compatible-local */ +#undef WARNING_CC_SHADOW_COMPATIBLE_LOCAL + +/* Define to 1 if your C++ compiler understands -Wshadow=compatible-local */ +#undef WARNING_CXX_SHADOW_COMPATIBLE_LOCAL + /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index a12b379e09a..30afcfbf453 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -316,6 +316,39 @@ typedef struct ErrorContextCallback extern PGDLLIMPORT ErrorContextCallback *error_context_stack; +/* Support for testing if a macro is inside a PG_TRY/... block. */ +typedef char pg_lexical_scope_false_type; +typedef int pg_lexical_scope_true_type; + +/* Declare a tag as a variable in global scope. It has no storage. */ +#define pg_declare_lexical_scope_tag(name) \ + extern pg_lexical_scope_false_type \ + lexical_scope_tag_##name pg_attribute_unused() + +/* + * Declare a tag as a local typedef that hides the name of the variable, + * within the current lexical scope. + * + * On its own, "shadowing" a variable name with a type name doesn't trigger + * GCC's -Wshadow=compatible-local warning, but we want to be able to handle + * nested PG_TRY blocks using the same tag name. Disable the warning locally, + * if it's enabled. + */ +#define pg_set_lexical_scope_tag(name) \ + pg_begin_ignore_shadow_warning() \ + typedef pg_lexical_scope_true_type \ + lexical_scope_tag_##name pg_attribute_unused(); \ + pg_end_ignore_shadow_warning() + +/* Test whether we are inside a lexical scope that has "set" the tag. */ +#define pg_in_lexical_scope_p(name) \ + (sizeof(lexical_scope_tag_##name) == sizeof(pg_lexical_scope_true_type)) + +pg_declare_lexical_scope_tag(PG_TRY); +pg_declare_lexical_scope_tag(PG_CATCH); +pg_declare_lexical_scope_tag(PG_FINALLY); + + /*---------- * API for catching ereport(ERROR) exits. Use these macros like so: * @@ -391,12 +424,14 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack; bool _do_rethrow##__VA_ARGS__ = false; \ if (sigsetjmp(_local_sigjmp_buf##__VA_ARGS__, 0) == 0) \ { \ + pg_set_lexical_scope_tag(PG_TRY); \ PG_exception_stack = &_local_sigjmp_buf##__VA_ARGS__ #define PG_CATCH(...) \ } \ else \ { \ + pg_set_lexical_scope_tag(PG_CATCH); \ PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ error_context_stack = _save_context_stack##__VA_ARGS__ @@ -405,6 +440,7 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack; else \ _do_rethrow##__VA_ARGS__ = true; \ { \ + pg_set_lexical_scope_tag(PG_FINALLY); \ PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ error_context_stack = _save_context_stack##__VA_ARGS__ -- 2.50.1 (Apple Git-155)