diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index 9398ca6c4777c0f2aeec3f79f1ea6207563b3c91..069b468daac4de098e89ae81bf7ac9cdd6e59dac 100644 --- a/config/c-compiler.m4 +++ b/config/c-compiler.m4 @@ -121,6 +121,46 @@ fi])# PGAC_C_FUNCNAME_SUPPORT +# PGAC_C_STATIC_ASSERT +# ----------------------- +# Check if the C compiler understands _Static_assert(), +# and define HAVE__STATIC_ASSERT if so. +# +# We actually check the syntax ({ _Static_assert(...) }), because we need +# gcc-style compound expressions to be able to wrap the thing into macros. +AC_DEFUN([PGAC_C_STATIC_ASSERT], +[AC_CACHE_CHECK(for _Static_assert, pgac_cv__static_assert, +[AC_TRY_LINK([], +[({ _Static_assert(1, "foo"); })], +[pgac_cv__static_assert=yes], +[pgac_cv__static_assert=no])]) +if test x"$pgac_cv__static_assert" = xyes ; then +AC_DEFINE(HAVE__STATIC_ASSERT, 1, + [Define to 1 if your compiler understands _Static_assert.]) +fi])# PGAC_C_STATIC_ASSERT + + + +# PGAC_C_TYPES_COMPATIBLE +# ----------------------- +# Check if the C compiler understands __builtin_types_compatible_p, +# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so. +# +# We check usage with __typeof__, though it's unlikely any compiler would +# have the former and not the latter. +AC_DEFUN([PGAC_C_TYPES_COMPATIBLE], +[AC_CACHE_CHECK(for __builtin_types_compatible_p, pgac_cv__types_compatible, +[AC_TRY_COMPILE([], +[ int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)]; ], +[pgac_cv__types_compatible=yes], +[pgac_cv__types_compatible=no])]) +if test x"$pgac_cv__types_compatible" = xyes ; then +AC_DEFINE(HAVE__BUILTIN_TYPES_COMPATIBLE_P, 1, + [Define to 1 if your compiler understands __builtin_types_compatible_p.]) +fi])# PGAC_C_TYPES_COMPATIBLE + + + # PGAC_PROG_CC_CFLAGS_OPT # ----------------------- # Given a string, check if the compiler supports the string as a diff --git a/configure b/configure index 56da7cdc73f3dd8241f3d6cddc094cdd3b347dfa..c6dcc8bfaaf5866ca532aef680f00dfb12cb7ebc 100755 --- a/configure +++ b/configure @@ -15524,6 +15524,125 @@ cat >>confdefs.h <<\_ACEOF _ACEOF fi +fi +{ $as_echo "$as_me:$LINENO: checking for _Static_assert" >&5 +$as_echo_n "checking for _Static_assert... " >&6; } +if test "${pgac_cv__static_assert+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +({ _Static_assert(1, "foo"); }) + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + pgac_cv__static_assert=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + pgac_cv__static_assert=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $pgac_cv__static_assert" >&5 +$as_echo "$pgac_cv__static_assert" >&6; } +if test x"$pgac_cv__static_assert" = xyes ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE__STATIC_ASSERT 1 +_ACEOF + +fi +{ $as_echo "$as_me:$LINENO: checking for __builtin_types_compatible_p" >&5 +$as_echo_n "checking for __builtin_types_compatible_p... " >&6; } +if test "${pgac_cv__types_compatible+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)]; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + pgac_cv__types_compatible=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + pgac_cv__types_compatible=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $pgac_cv__types_compatible" >&5 +$as_echo "$pgac_cv__types_compatible" >&6; } +if test x"$pgac_cv__types_compatible" = xyes ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1 +_ACEOF + fi { $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } diff --git a/configure.in b/configure.in index 8d02abb4cca6538b8b16d30bc8589ca9febe9902..fef8e7f013a9020576d9f2d22b7c2aa112282632 100644 --- a/configure.in +++ b/configure.in @@ -1104,6 +1104,8 @@ AC_C_FLEXIBLE_ARRAY_MEMBER PGAC_C_SIGNED AC_C_VOLATILE PGAC_C_FUNCNAME_SUPPORT +PGAC_C_STATIC_ASSERT +PGAC_C_TYPES_COMPATIBLE PGAC_STRUCT_TIMEZONE PGAC_UNION_SEMUN PGAC_STRUCT_SOCKADDR_UN diff --git a/src/include/c.h b/src/include/c.h index 50e1ecfde4da66899eb294f9b51a8b49bc7c297e..06f689d35937b13178f263a6d5db6752e8b96a07 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -689,6 +689,47 @@ typedef NameData *Name; } while (0) +/* + * Macros to support compile-time assertion checks, if the compiler has them. + * + * If the "condition" (a compile-time-constant expression) evaluates to false, + * throw a compile error using the "errmessage" (a string literal). + * + * gcc 4.6 and up supports _Static_assert(), but it has bizarre syntactic + * placement restrictions. These macros make it safe to use as a statement + * or in an expression, respectively. + */ +#ifdef HAVE__STATIC_ASSERT +#define StaticAssertStmt(condition, errmessage) \ + do { _Static_assert(condition, errmessage); } while(0) +#define StaticAssertExpr(condition, errmessage) \ + ({ StaticAssertStmt(condition, errmessage); true; }) +#else /* !HAVE__STATIC_ASSERT */ +#define StaticAssertStmt(condition, errmessage) +#define StaticAssertExpr(condition, errmessage) ((void) true) +#endif /* HAVE__STATIC_ASSERT */ + + +/* + * Compile-time checks that a variable (or expression) has the specified type. + * + * AssertVariableIsOfType() can be used as a statement. + * AssertVariableIsOfTypeMacro() is intended for use in macros, eg + * #define foo(x) (AssertVariableIsOfTypeMacro(x, int), bar(x)) + */ +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define AssertVariableIsOfType(varname, typename) \ + StaticAssertStmt(__builtin_types_compatible_p(__typeof__(varname), typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) +#define AssertVariableIsOfTypeMacro(varname, typename) \ + StaticAssertExpr(__builtin_types_compatible_p(__typeof__(varname), typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) +#else /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */ +#define AssertVariableIsOfType(varname, typename) +#define AssertVariableIsOfTypeMacro(varname, typename) ((void) true) +#endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */ + + /* ---------------------------------------------------------------- * Section 7: random stuff * ---------------------------------------------------------------- diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 1ffb032835f1fa324fda404647551d8529040269..58cd5907dd4c487a6e556a79754109822c40334e 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -635,6 +635,12 @@ /* Define to 1 if you have the <winldap.h> header file. */ #undef HAVE_WINLDAP_H +/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ +#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P + +/* Define to 1 if your compiler understands _Static_assert. */ +#undef HAVE__STATIC_ASSERT + /* Define to the appropriate snprintf format for 64-bit ints. */ #undef INT64_FORMAT diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index b7b7c641d3af10c10c377bfce5f29cd2c138f942..4d9cc55c69908e34c6ffc3cbebbc1be6ff2f96f9 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -526,6 +526,12 @@ /* Define to 1 if you have the <winldap.h> header file. */ /* #undef HAVE_WINLDAP_H */ +/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ +/* #undef HAVE__BUILTIN_TYPES_COMPATIBLE_P */ + +/* Define to 1 if your compiler understands _Static_assert. */ +/* #undef HAVE__STATIC_ASSERT */ + /* Define to the appropriate snprintf format for 64-bit ints, if any. */ #define INT64_FORMAT "%lld"