Add infrastructure for compile-time assertions about variable types.

Currently, the macros only work with fairly recent gcc versions, but there
is room to expand them to other compilers that have comparable features.

Heavily revised and autoconfiscated version of a patch by Andres Freund.
This commit is contained in:
Tom Lane 2012-09-30 14:38:31 -04:00
parent 26fd82ddf1
commit ea473fb2de
6 changed files with 214 additions and 0 deletions

View File

@ -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 # PGAC_PROG_CC_CFLAGS_OPT
# ----------------------- # -----------------------
# Given a string, check if the compiler supports the string as a # Given a string, check if the compiler supports the string as a

119
configure vendored
View File

@ -15524,6 +15524,125 @@ cat >>confdefs.h <<\_ACEOF
_ACEOF _ACEOF
fi 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 fi
{ $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 { $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; } $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }

View File

@ -1104,6 +1104,8 @@ AC_C_FLEXIBLE_ARRAY_MEMBER
PGAC_C_SIGNED PGAC_C_SIGNED
AC_C_VOLATILE AC_C_VOLATILE
PGAC_C_FUNCNAME_SUPPORT PGAC_C_FUNCNAME_SUPPORT
PGAC_C_STATIC_ASSERT
PGAC_C_TYPES_COMPATIBLE
PGAC_STRUCT_TIMEZONE PGAC_STRUCT_TIMEZONE
PGAC_UNION_SEMUN PGAC_UNION_SEMUN
PGAC_STRUCT_SOCKADDR_UN PGAC_STRUCT_SOCKADDR_UN

View File

@ -689,6 +689,47 @@ typedef NameData *Name;
} while (0) } 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 * Section 7: random stuff
* ---------------------------------------------------------------- * ----------------------------------------------------------------

View File

@ -635,6 +635,12 @@
/* Define to 1 if you have the <winldap.h> header file. */ /* Define to 1 if you have the <winldap.h> header file. */
#undef HAVE_WINLDAP_H #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. */ /* Define to the appropriate snprintf format for 64-bit ints. */
#undef INT64_FORMAT #undef INT64_FORMAT

View File

@ -526,6 +526,12 @@
/* Define to 1 if you have the <winldap.h> header file. */ /* Define to 1 if you have the <winldap.h> header file. */
/* #undef HAVE_WINLDAP_H */ /* #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 to the appropriate snprintf format for 64-bit ints, if any. */
#define INT64_FORMAT "%lld" #define INT64_FORMAT "%lld"