Add declaration-level assertions for compile-time checks
Those new assertions can be used at file scope, outside of any function for compilation checks. This commit provides implementations for C and C++, and fallback implementations. Author: Peter Smith Reviewed-by: Andres Freund, Kyotaro Horiguchi, Dagfinn Ilmari Mannsåker, Michael Paquier Discussion: https://postgr.es/m/201DD0641B056142AC8C6645EC1B5F62014B8E8030@SYD1217
This commit is contained in:
parent
6148e2b9a6
commit
f1f10a1ba9
|
@ -119,14 +119,7 @@ PageIsVerified(Page page, BlockNumber blkno)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Check all-zeroes case */
|
||||||
* Check all-zeroes case. Luckily BLCKSZ is guaranteed to always be a
|
|
||||||
* multiple of size_t - and it's much faster to compare memory using the
|
|
||||||
* native word size.
|
|
||||||
*/
|
|
||||||
StaticAssertStmt(BLCKSZ == (BLCKSZ / sizeof(size_t)) * sizeof(size_t),
|
|
||||||
"BLCKSZ has to be a multiple of sizeof(size_t)");
|
|
||||||
|
|
||||||
all_zeroes = true;
|
all_zeroes = true;
|
||||||
pagebytes = (size_t *) page;
|
pagebytes = (size_t *) page;
|
||||||
for (i = 0; i < (BLCKSZ / sizeof(size_t)); i++)
|
for (i = 0; i < (BLCKSZ / sizeof(size_t)); i++)
|
||||||
|
|
|
@ -36,6 +36,9 @@ const char *const LockTagTypeNames[] = {
|
||||||
"advisory"
|
"advisory"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_ADVISORY + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/* This must match enum PredicateLockTargetType (predicate_internals.h) */
|
/* This must match enum PredicateLockTargetType (predicate_internals.h) */
|
||||||
static const char *const PredicateLockTagTypeNames[] = {
|
static const char *const PredicateLockTagTypeNames[] = {
|
||||||
"relation",
|
"relation",
|
||||||
|
@ -43,6 +46,9 @@ static const char *const PredicateLockTagTypeNames[] = {
|
||||||
"tuple"
|
"tuple"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/* Working status for pg_lock_status */
|
/* Working status for pg_lock_status */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -241,6 +241,9 @@ static const struct config_enum_entry bytea_output_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(bytea_output_options) == (BYTEA_OUTPUT_HEX + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have different sets for client and server message level options because
|
* We have different sets for client and server message level options because
|
||||||
* they sort slightly different (see "log" level), and because "fatal"/"panic"
|
* they sort slightly different (see "log" level), and because "fatal"/"panic"
|
||||||
|
@ -286,6 +289,9 @@ static const struct config_enum_entry intervalstyle_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(intervalstyle_options) == (INTSTYLE_ISO_8601 + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry log_error_verbosity_options[] = {
|
static const struct config_enum_entry log_error_verbosity_options[] = {
|
||||||
{"terse", PGERROR_TERSE, false},
|
{"terse", PGERROR_TERSE, false},
|
||||||
{"default", PGERROR_DEFAULT, false},
|
{"default", PGERROR_DEFAULT, false},
|
||||||
|
@ -293,6 +299,9 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry log_statement_options[] = {
|
static const struct config_enum_entry log_statement_options[] = {
|
||||||
{"none", LOGSTMT_NONE, false},
|
{"none", LOGSTMT_NONE, false},
|
||||||
{"ddl", LOGSTMT_DDL, false},
|
{"ddl", LOGSTMT_DDL, false},
|
||||||
|
@ -301,6 +310,9 @@ static const struct config_enum_entry log_statement_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(log_statement_options) == (LOGSTMT_ALL + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry isolation_level_options[] = {
|
static const struct config_enum_entry isolation_level_options[] = {
|
||||||
{"serializable", XACT_SERIALIZABLE, false},
|
{"serializable", XACT_SERIALIZABLE, false},
|
||||||
{"repeatable read", XACT_REPEATABLE_READ, false},
|
{"repeatable read", XACT_REPEATABLE_READ, false},
|
||||||
|
@ -316,6 +328,9 @@ static const struct config_enum_entry session_replication_role_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(session_replication_role_options) == (SESSION_REPLICATION_ROLE_LOCAL + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry syslog_facility_options[] = {
|
static const struct config_enum_entry syslog_facility_options[] = {
|
||||||
#ifdef HAVE_SYSLOG
|
#ifdef HAVE_SYSLOG
|
||||||
{"local0", LOG_LOCAL0, false},
|
{"local0", LOG_LOCAL0, false},
|
||||||
|
@ -339,18 +354,27 @@ static const struct config_enum_entry track_function_options[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(track_function_options) == (TRACK_FUNC_ALL + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry xmlbinary_options[] = {
|
static const struct config_enum_entry xmlbinary_options[] = {
|
||||||
{"base64", XMLBINARY_BASE64, false},
|
{"base64", XMLBINARY_BASE64, false},
|
||||||
{"hex", XMLBINARY_HEX, false},
|
{"hex", XMLBINARY_HEX, false},
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(xmlbinary_options) == (XMLBINARY_HEX + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static const struct config_enum_entry xmloption_options[] = {
|
static const struct config_enum_entry xmloption_options[] = {
|
||||||
{"content", XMLOPTION_CONTENT, false},
|
{"content", XMLOPTION_CONTENT, false},
|
||||||
{"document", XMLOPTION_DOCUMENT, false},
|
{"document", XMLOPTION_DOCUMENT, false},
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(xmloption_options) == (XMLOPTION_CONTENT + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Although only "on", "off", and "safe_encoding" are documented, we
|
* Although only "on", "off", and "safe_encoding" are documented, we
|
||||||
* accept all the likely variants of "on" and "off".
|
* accept all the likely variants of "on" and "off".
|
||||||
|
@ -465,6 +489,9 @@ const struct config_enum_entry ssl_protocol_versions_info[] = {
|
||||||
{NULL, 0, false}
|
{NULL, 0, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static struct config_enum_entry shared_memory_options[] = {
|
static struct config_enum_entry shared_memory_options[] = {
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
{"sysv", SHMEM_TYPE_SYSV, false},
|
{"sysv", SHMEM_TYPE_SYSV, false},
|
||||||
|
@ -615,6 +642,9 @@ const char *const GucContext_Names[] =
|
||||||
/* PGC_USERSET */ "user"
|
/* PGC_USERSET */ "user"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(GucContext_Names) == (PGC_USERSET + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Displayable names for source types (enum GucSource)
|
* Displayable names for source types (enum GucSource)
|
||||||
*
|
*
|
||||||
|
@ -638,6 +668,9 @@ const char *const GucSource_Names[] =
|
||||||
/* PGC_S_SESSION */ "session"
|
/* PGC_S_SESSION */ "session"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(GucSource_Names) == (PGC_S_SESSION + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Displayable names for the groupings defined in enum config_group
|
* Displayable names for the groupings defined in enum config_group
|
||||||
*/
|
*/
|
||||||
|
@ -749,6 +782,9 @@ const char *const config_group_names[] =
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(config_group_names) == (DEVELOPER_OPTIONS + 2),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Displayable names for GUC variable types (enum config_type)
|
* Displayable names for GUC variable types (enum config_type)
|
||||||
*
|
*
|
||||||
|
@ -763,6 +799,9 @@ const char *const config_type_names[] =
|
||||||
/* PGC_ENUM */ "enum"
|
/* PGC_ENUM */ "enum"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unit conversion tables.
|
* Unit conversion tables.
|
||||||
*
|
*
|
||||||
|
|
|
@ -80,6 +80,9 @@ static const int dbObjectTypePriority[] =
|
||||||
38 /* DO_SUBSCRIPTION */
|
38 /* DO_SUBSCRIPTION */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(dbObjectTypePriority) == (DO_SUBSCRIPTION + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
static DumpId preDataBoundId;
|
static DumpId preDataBoundId;
|
||||||
static DumpId postDataBoundId;
|
static DumpId postDataBoundId;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ const char *const forkNames[] = {
|
||||||
"init" /* INIT_FORKNUM */
|
"init" /* INIT_FORKNUM */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StaticAssertDecl(lengthof(forkNames) == (MAX_FORKNUM + 1),
|
||||||
|
"array length mismatch");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* forkname_to_number - look up fork number by name
|
* forkname_to_number - look up fork number by name
|
||||||
*
|
*
|
||||||
|
|
|
@ -832,8 +832,10 @@ extern void ExceptionalCondition(const char *conditionName,
|
||||||
* throw a compile error using the "errmessage" (a string literal).
|
* throw a compile error using the "errmessage" (a string literal).
|
||||||
*
|
*
|
||||||
* gcc 4.6 and up supports _Static_assert(), but there are 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
|
* placement restrictions. Macros StaticAssertStmt() and StaticAssertExpr()
|
||||||
* or in an expression, respectively.
|
* make it safe to use as a statement or in an expression, respectively.
|
||||||
|
* The macro StaticAssertDecl() is suitable for use at file scope (outside of
|
||||||
|
* any function).
|
||||||
*
|
*
|
||||||
* Otherwise we fall back on a kluge that assumes the compiler will complain
|
* 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
|
* about a negative width for a struct bit-field. This will not include a
|
||||||
|
@ -845,11 +847,15 @@ extern void ExceptionalCondition(const char *conditionName,
|
||||||
do { _Static_assert(condition, errmessage); } while(0)
|
do { _Static_assert(condition, errmessage); } while(0)
|
||||||
#define StaticAssertExpr(condition, errmessage) \
|
#define StaticAssertExpr(condition, errmessage) \
|
||||||
((void) ({ StaticAssertStmt(condition, errmessage); true; }))
|
((void) ({ StaticAssertStmt(condition, errmessage); true; }))
|
||||||
|
#define StaticAssertDecl(condition, errmessage) \
|
||||||
|
_Static_assert(condition, errmessage)
|
||||||
#else /* !HAVE__STATIC_ASSERT */
|
#else /* !HAVE__STATIC_ASSERT */
|
||||||
#define StaticAssertStmt(condition, errmessage) \
|
#define StaticAssertStmt(condition, errmessage) \
|
||||||
((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
|
((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
|
||||||
#define StaticAssertExpr(condition, errmessage) \
|
#define StaticAssertExpr(condition, errmessage) \
|
||||||
StaticAssertStmt(condition, errmessage)
|
StaticAssertStmt(condition, errmessage)
|
||||||
|
#define StaticAssertDecl(condition, errmessage) \
|
||||||
|
extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
|
||||||
#endif /* HAVE__STATIC_ASSERT */
|
#endif /* HAVE__STATIC_ASSERT */
|
||||||
#else /* C++ */
|
#else /* C++ */
|
||||||
#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410
|
#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410
|
||||||
|
@ -857,12 +863,16 @@ extern void ExceptionalCondition(const char *conditionName,
|
||||||
static_assert(condition, errmessage)
|
static_assert(condition, errmessage)
|
||||||
#define StaticAssertExpr(condition, errmessage) \
|
#define StaticAssertExpr(condition, errmessage) \
|
||||||
({ static_assert(condition, errmessage); })
|
({ static_assert(condition, errmessage); })
|
||||||
#else
|
#define StaticAssertDecl(condition, errmessage) \
|
||||||
|
static_assert(condition, errmessage)
|
||||||
|
#else /* !__cpp_static_assert */
|
||||||
#define StaticAssertStmt(condition, errmessage) \
|
#define StaticAssertStmt(condition, errmessage) \
|
||||||
do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0)
|
do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0)
|
||||||
#define StaticAssertExpr(condition, errmessage) \
|
#define StaticAssertExpr(condition, errmessage) \
|
||||||
((void) ({ StaticAssertStmt(condition, errmessage); }))
|
((void) ({ StaticAssertStmt(condition, errmessage); }))
|
||||||
#endif
|
#define StaticAssertDecl(condition, errmessage) \
|
||||||
|
extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
|
||||||
|
#endif /* __cpp_static_assert */
|
||||||
#endif /* C++ */
|
#endif /* C++ */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -418,6 +418,16 @@ do { \
|
||||||
((overwrite) ? PAI_OVERWRITE : 0) | \
|
((overwrite) ? PAI_OVERWRITE : 0) | \
|
||||||
((is_heap) ? PAI_IS_HEAP : 0))
|
((is_heap) ? PAI_IS_HEAP : 0))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that BLCKSZ is a multiple of sizeof(size_t). In PageIsVerified(),
|
||||||
|
* it is much faster to check if a page is full of zeroes using the native
|
||||||
|
* word size. Note that this assertion is kept within a header to make
|
||||||
|
* sure that StaticAssertDecl() works across various combinations of
|
||||||
|
* platforms and compilers.
|
||||||
|
*/
|
||||||
|
StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
|
||||||
|
"BLCKSZ has to be a multiple of sizeof(size_t)");
|
||||||
|
|
||||||
extern void PageInit(Page page, Size pageSize, Size specialSize);
|
extern void PageInit(Page page, Size pageSize, Size specialSize);
|
||||||
extern bool PageIsVerified(Page page, BlockNumber blkno);
|
extern bool PageIsVerified(Page page, BlockNumber blkno);
|
||||||
extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
|
extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
|
||||||
|
|
Loading…
Reference in New Issue