diff --git a/contrib/hstore/hstore_compat.c b/contrib/hstore/hstore_compat.c index 88764b1b698947e3a5c8903e3be53c652282c029..6327a8e8bb58a5c6e32e8884690ee5b5ece53417 100644 --- a/contrib/hstore/hstore_compat.c +++ b/contrib/hstore/hstore_compat.c @@ -94,7 +94,7 @@ * etc. are compatible. * * If the above statement isn't true on some bizarre platform, we're - * a bit hosed (see Assert in hstoreValidOldFormat). + * a bit hosed (see StaticAssertStmt in hstoreValidOldFormat). */ typedef struct { @@ -180,7 +180,8 @@ hstoreValidOldFormat(HStore *hs) return 0; /* New format uses an HEntry for key and another for value */ - Assert(sizeof(HOldEntry) == (2 * sizeof(HEntry))); + StaticAssertStmt(sizeof(HOldEntry) == 2 * sizeof(HEntry), + "old hstore format is not upward-compatible"); if (count == 0) return 2; diff --git a/src/include/c.h b/src/include/c.h index 06f689d35937b13178f263a6d5db6752e8b96a07..bec1eb3da46528f9d0167c4c954c5a34eefb284a 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -690,14 +690,18 @@ typedef NameData *Name; /* - * Macros to support compile-time assertion checks, if the compiler has them. + * Macros to support compile-time assertion checks. * * 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 + * gcc 4.6 and up supports _Static_assert(), but there are bizarre syntactic * placement restrictions. These macros make it safe to use as a statement * or in an expression, respectively. + * + * Otherwise we fall back on a kluge that assumes the compiler will complain + * about a negative width for a struct bit-field. This will not include a + * helpful error message, but it beats not getting an error at all. */ #ifdef HAVE__STATIC_ASSERT #define StaticAssertStmt(condition, errmessage) \ @@ -705,8 +709,10 @@ typedef NameData *Name; #define StaticAssertExpr(condition, errmessage) \ ({ StaticAssertStmt(condition, errmessage); true; }) #else /* !HAVE__STATIC_ASSERT */ -#define StaticAssertStmt(condition, errmessage) -#define StaticAssertExpr(condition, errmessage) ((void) true) +#define StaticAssertStmt(condition, errmessage) \ + ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; })) +#define StaticAssertExpr(condition, errmessage) \ + StaticAssertStmt(condition, errmessage) #endif /* HAVE__STATIC_ASSERT */ @@ -716,6 +722,10 @@ typedef NameData *Name; * AssertVariableIsOfType() can be used as a statement. * AssertVariableIsOfTypeMacro() is intended for use in macros, eg * #define foo(x) (AssertVariableIsOfTypeMacro(x, int), bar(x)) + * + * If we don't have __builtin_types_compatible_p, we can still assert that + * the types have the same size. This is far from ideal (especially on 32-bit + * platforms) but it provides at least some coverage. */ #ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P #define AssertVariableIsOfType(varname, typename) \ @@ -725,8 +735,12 @@ typedef NameData *Name; 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) +#define AssertVariableIsOfType(varname, typename) \ + StaticAssertStmt(sizeof(varname) == sizeof(typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) +#define AssertVariableIsOfTypeMacro(varname, typename) \ + StaticAssertExpr(sizeof(varname) == sizeof(typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) #endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */