Static assertions cleanup
authorPeter Eisentraut <[email protected]>
Thu, 8 Dec 2022 13:30:01 +0000 (14:30 +0100)
committerPeter Eisentraut <[email protected]>
Thu, 15 Dec 2022 09:10:32 +0000 (10:10 +0100)
Because we added StaticAssertStmt() first before StaticAssertDecl(),
some uses as well as the instructions in c.h are now a bit backwards
from the "native" way static assertions are meant to be used in C.
This updates the guidance and moves some static assertions to better
places.

Specifically, since the addition of StaticAssertDecl(), we can put
static assertions at the file level.  This moves a number of static
assertions out of function bodies, where they might have been stuck
out of necessity, to perhaps better places at the file level or in
header files.

Also, when the static assertion appears in a position where a
declaration is allowed, then using StaticAssertDecl() is more native
than StaticAssertStmt().

Reviewed-by: John Naylor <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/941a04e7-dd6f-c0e4-8cdf-a33b3338cbda%40enterprisedb.com

29 files changed:
src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtutils.c
src/backend/access/transam/clog.c
src/backend/access/transam/xlog.c
src/backend/backup/basebackup.c
src/backend/catalog/dependency.c
src/backend/executor/execExprInterp.c
src/backend/libpq/auth-scram.c
src/backend/libpq/hba.c
src/backend/port/atomics.c
src/backend/storage/lmgr/lwlock.c
src/backend/storage/page/itemptr.c
src/backend/utils/adt/numeric.c
src/backend/utils/adt/tsginidx.c
src/backend/utils/adt/xid8funcs.c
src/backend/utils/cache/syscache.c
src/backend/utils/mmgr/aset.c
src/backend/utils/mmgr/generation.c
src/backend/utils/mmgr/slab.c
src/common/checksum_helper.c
src/common/controldata_utils.c
src/common/encnames.c
src/include/access/gin.h
src/include/access/htup_details.h
src/include/access/nbtree.h
src/include/c.h
src/include/catalog/pg_control.h
src/include/common/int128.h
src/include/storage/lwlock.h

index 747db50376154e737707347fe717660b64f1501d..42756a9e6df8d72a6c5f84fa3b7763dd594cc52e 100644 (file)
@@ -5783,10 +5783,6 @@ heap_finish_speculative(Relation relation, ItemPointer tid)
 
    htup = (HeapTupleHeader) PageGetItem(page, lp);
 
-   /* SpecTokenOffsetNumber should be distinguishable from any real offset */
-   StaticAssertStmt(MaxOffsetNumber < SpecTokenOffsetNumber,
-                    "invalid speculative token constant");
-
    /* NO EREPORT(ERROR) from here till changes are logged */
    START_CRIT_SECTION();
 
@@ -7921,7 +7917,7 @@ index_delete_sort(TM_IndexDeleteOp *delstate)
    const int   gaps[9] = {1968, 861, 336, 112, 48, 21, 7, 3, 1};
 
    /* Think carefully before changing anything here -- keep swaps cheap */
-   StaticAssertStmt(sizeof(TM_IndexDelete) <= 8,
+   StaticAssertDecl(sizeof(TM_IndexDelete) <= 8,
                     "element size exceeds 8 bytes");
 
    for (int g = 0; g < lengthof(gaps); g++)
index ff260c393ab7fffc2a5f3e7ca4a76bd1ab3c5032..10f13e6d415758df02acc521500a141835283cc1 100644 (file)
@@ -2486,13 +2486,6 @@ _bt_check_natts(Relation rel, bool heapkeyspace, Page page, OffsetNumber offnum)
    Assert(offnum >= FirstOffsetNumber &&
           offnum <= PageGetMaxOffsetNumber(page));
 
-   /*
-    * Mask allocated for number of keys in index tuple must be able to fit
-    * maximum possible number of index attributes
-    */
-   StaticAssertStmt(BT_OFFSET_MASK >= INDEX_MAX_KEYS,
-                    "BT_OFFSET_MASK can't fit INDEX_MAX_KEYS");
-
    itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
    tupnatts = BTreeTupleGetNAtts(itup, rel);
 
index 77d9894dab3cd1c4feb66b8fa3c1aa3fb9e01b90..8832efc7c11a69d6d327e6662a8d862143e94c73 100644 (file)
@@ -275,7 +275,7 @@ TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
                           bool all_xact_same_page)
 {
    /* Can't use group update when PGPROC overflows. */
-   StaticAssertStmt(THRESHOLD_SUBTRANS_CLOG_OPT <= PGPROC_MAX_CACHED_SUBXIDS,
+   StaticAssertDecl(THRESHOLD_SUBTRANS_CLOG_OPT <= PGPROC_MAX_CACHED_SUBXIDS,
                     "group clog threshold less than PGPROC cached subxids");
 
    /*
index a31fbbff78dac988198d08d3e6cda9b01eb1a8d7..91473b00d90c5c05e618f294676ef8a4a6b16815 100644 (file)
@@ -3883,15 +3883,6 @@ WriteControlFile(void)
    int         fd;
    char        buffer[PG_CONTROL_FILE_SIZE];   /* need not be aligned */
 
-   /*
-    * Ensure that the size of the pg_control data structure is sane.  See the
-    * comments for these symbols in pg_control.h.
-    */
-   StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
-                    "pg_control is too large for atomic disk writes");
-   StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
-                    "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
-
    /*
     * Initialize version and compatibility-check fields
     */
index 7aa5f6e44d141db077adff654b83199878f99829..c00ac14c0bee671184489818f0f551ac2adb24f9 100644 (file)
@@ -370,7 +370,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
            else
            {
                /* Properly terminate the tarfile. */
-               StaticAssertStmt(2 * TAR_BLOCK_SIZE <= BLCKSZ,
+               StaticAssertDecl(2 * TAR_BLOCK_SIZE <= BLCKSZ,
                                 "BLCKSZ too small for 2 tar blocks");
                memset(sink->bbs_buffer, 0, 2 * TAR_BLOCK_SIZE);
                bbsink_archive_contents(sink, 2 * TAR_BLOCK_SIZE);
@@ -1745,7 +1745,7 @@ _tarWriteHeader(bbsink *sink, const char *filename, const char *linktarget,
         * large enough to fit an entire tar block. We double-check by means
         * of these assertions.
         */
-       StaticAssertStmt(TAR_BLOCK_SIZE <= BLCKSZ,
+       StaticAssertDecl(TAR_BLOCK_SIZE <= BLCKSZ,
                         "BLCKSZ too small for tar block");
        Assert(sink->bbs_buffer_length >= TAR_BLOCK_SIZE);
 
index 7f3e64b5ae610cd1fddb2c81a4c5ca311b9f36de..30394dccf560f501a83978826cec887946caddbb 100644 (file)
@@ -191,6 +191,12 @@ static const Oid object_classes[] = {
    TransformRelationId         /* OCLASS_TRANSFORM */
 };
 
+/*
+ * Make sure object_classes is kept up to date with the ObjectClass enum.
+ */
+StaticAssertDecl(lengthof(object_classes) == LAST_OCLASS + 1,
+                "object_classes[] must cover all ObjectClasses");
+
 
 static void findDependentObjects(const ObjectAddress *object,
                                 int objflags,
@@ -2550,12 +2556,6 @@ add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
 {
    ObjectAddress *item;
 
-   /*
-    * Make sure object_classes is kept up to date with the ObjectClass enum.
-    */
-   StaticAssertStmt(lengthof(object_classes) == LAST_OCLASS + 1,
-                    "object_classes[] must cover all ObjectClasses");
-
    /* enlarge array if needed */
    if (addrs->numrefs >= addrs->maxrefs)
    {
index be48886511e4bd63987de578caae7c795efc94c4..957406ae6973213b27eb78b2ca4cd0c2d3d4cdfe 100644 (file)
@@ -496,7 +496,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
        &&CASE_EEOP_LAST
    };
 
-   StaticAssertStmt(lengthof(dispatch_table) == EEOP_LAST + 1,
+   StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
                     "dispatch_table out of whack with ExprEvalOp");
 
    if (unlikely(state == NULL))
index ee7f52218ab33bc23184b77d2d52e822309271d4..c9bab85e82fcd90a97ff7a539f0a385455aaa219 100644 (file)
@@ -1443,7 +1443,7 @@ scram_mock_salt(const char *username)
     * not larger than the SHA256 digest length.  If the salt is smaller, the
     * caller will just ignore the extra data.)
     */
-   StaticAssertStmt(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN,
+   StaticAssertDecl(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN,
                     "salt length greater than SHA256 digest length");
 
    ctx = pg_cryptohash_create(PG_SHA256);
index 46e91441ac5d4db662f599589687f45b856e25be..870b9076970fbacbfefd44359dd37e232e7b55fb 100644 (file)
@@ -127,6 +127,12 @@ static const char *const UserAuthName[] =
    "peer"
 };
 
+/*
+ * Make sure UserAuthName[] tracks additions to the UserAuth enum
+ */
+StaticAssertDecl(lengthof(UserAuthName) == USER_AUTH_LAST + 1,
+                "UserAuthName[] must match the UserAuth enum");
+
 
 static List *tokenize_expand_file(List *tokens, const char *outer_filename,
                                  const char *inc_filename, int elevel,
@@ -3117,11 +3123,5 @@ hba_getauthmethod(hbaPort *port)
 const char *
 hba_authname(UserAuth auth_method)
 {
-   /*
-    * Make sure UserAuthName[] tracks additions to the UserAuth enum
-    */
-   StaticAssertStmt(lengthof(UserAuthName) == USER_AUTH_LAST + 1,
-                    "UserAuthName[] must match the UserAuth enum");
-
    return UserAuthName[auth_method];
 }
index ba274bed931f4cb4af9771a02e40521bda9a3c42..ff4771ae370e17bfefb077ba3b0483cc8bd46470 100644 (file)
@@ -54,7 +54,7 @@ pg_extern_compiler_barrier(void)
 void
 pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr)
 {
-   StaticAssertStmt(sizeof(ptr->sema) >= sizeof(slock_t),
+   StaticAssertDecl(sizeof(ptr->sema) >= sizeof(slock_t),
                     "size mismatch of atomic_flag vs slock_t");
 
 #ifndef HAVE_SPINLOCKS
@@ -105,7 +105,7 @@ pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr)
 void
 pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_)
 {
-   StaticAssertStmt(sizeof(ptr->sema) >= sizeof(slock_t),
+   StaticAssertDecl(sizeof(ptr->sema) >= sizeof(slock_t),
                     "size mismatch of atomic_uint32 vs slock_t");
 
    /*
@@ -181,7 +181,7 @@ pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
 void
 pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_)
 {
-   StaticAssertStmt(sizeof(ptr->sema) >= sizeof(slock_t),
+   StaticAssertDecl(sizeof(ptr->sema) >= sizeof(slock_t),
                     "size mismatch of atomic_uint64 vs slock_t");
 
    /*
index a5ad36ca7808e051f133298f1225046f3060c935..528b2e964383aa6910b7b10b5b0d472ac7f911c7 100644 (file)
@@ -108,6 +108,9 @@ extern slock_t *ShmemLock;
 /* Must be greater than MAX_BACKENDS - which is 2^23-1, so we're fine. */
 #define LW_SHARED_MASK             ((uint32) ((1 << 24)-1))
 
+StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
+                "MAX_BACKENDS too big for lwlock.c");
+
 /*
  * There are three sorts of LWLock "tranches":
  *
@@ -466,12 +469,6 @@ LWLockShmemSize(void)
 void
 CreateLWLocks(void)
 {
-   StaticAssertStmt(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
-                    "MAX_BACKENDS too big for lwlock.c");
-
-   StaticAssertStmt(sizeof(LWLock) <= LWLOCK_PADDED_SIZE,
-                    "Miscalculated LWLock padding");
-
    if (!IsUnderPostmaster)
    {
        Size        spaceLocks = LWLockShmemSize();
index 9011337aa81a1b57b6278298f4f054157a838791..5c98a5ec2b8b6f6544e1e14131d1f657d49ce395 100644 (file)
 #include "storage/itemptr.h"
 
 
+/*
+ * We really want ItemPointerData to be exactly 6 bytes.
+ */
+StaticAssertDecl(sizeof(ItemPointerData) == 3 * sizeof(uint16),
+                "ItemPointerData struct is improperly padded");
+
 /*
  * ItemPointerEquals
  * Returns true if both item pointers point to the same item,
 bool
 ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
 {
-   /*
-    * We really want ItemPointerData to be exactly 6 bytes.  This is rather a
-    * random place to check, but there is no better place.
-    */
-   StaticAssertStmt(sizeof(ItemPointerData) == 3 * sizeof(uint16),
-                    "ItemPointerData struct is improperly padded");
-
    if (ItemPointerGetBlockNumber(pointer1) ==
        ItemPointerGetBlockNumber(pointer2) &&
        ItemPointerGetOffsetNumber(pointer1) ==
index c024928bc8d6039bd2efd010efd08e6729490665..152e1b7e0c4c5be9cb11d64d01007647d533ac52 100644 (file)
@@ -4187,7 +4187,8 @@ int64_div_fast_to_numeric(int64 val1, int log10val2)
    {
        static int  pow10[] = {1, 10, 100, 1000};
 
-       StaticAssertStmt(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
+       StaticAssertDecl(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
+
        if (unlikely(pg_mul_s64_overflow(val1, pow10[DEC_DIGITS - m], &val1)))
        {
            /*
index e272fca0756ff47aa7be82d9d72bdca519d67177..cf23aeb5ead9d37fb62b570a85950277d6d1d6b9 100644 (file)
@@ -236,8 +236,6 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS)
         * query.
         */
        gcv.first_item = GETQUERY(query);
-       StaticAssertStmt(sizeof(GinTernaryValue) == sizeof(bool),
-                        "sizes of GinTernaryValue and bool are not equal");
        gcv.check = (GinTernaryValue *) check;
        gcv.map_item_operand = (int *) (extra_data[0]);
 
index 2093776809f1a3c225573fea0ec84e95146018da..3baf5f7d903969429d32b374720d655f0773a166 100644 (file)
@@ -74,6 +74,14 @@ typedef struct
 #define PG_SNAPSHOT_MAX_NXIP \
    ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
 
+/*
+ * Compile-time limits on the procarray (MAX_BACKENDS processes plus
+ * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
+ */
+StaticAssertDecl(MAX_BACKENDS * 2 <= PG_SNAPSHOT_MAX_NXIP,
+                "possible overflow in pg_current_snapshot()");
+
+
 /*
  * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
  *
@@ -402,13 +410,6 @@ pg_current_snapshot(PG_FUNCTION_ARGS)
    if (cur == NULL)
        elog(ERROR, "no active snapshot set");
 
-   /*
-    * Compile-time limits on the procarray (MAX_BACKENDS processes plus
-    * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
-    */
-   StaticAssertStmt(MAX_BACKENDS * 2 <= PG_SNAPSHOT_MAX_NXIP,
-                    "possible overflow in pg_current_snapshot()");
-
    /* allocate */
    nxip = cur->xcnt;
    snap = palloc(PG_SNAPSHOT_SIZE(nxip));
index 8b3596835396642f7e840709faf940a20a5415ac..5f17047047bec924548737d4f6f735dbb73d7f79 100644 (file)
@@ -1040,6 +1040,9 @@ static const struct cachedesc cacheinfo[] = {
    }
 };
 
+StaticAssertDecl(lengthof(cacheinfo) == SysCacheSize,
+                "SysCacheSize does not match syscache.c's array");
+
 static CatCache *SysCache[SysCacheSize];
 
 static bool CacheInitialized = false;
@@ -1068,9 +1071,6 @@ InitCatalogCache(void)
 {
    int         cacheId;
 
-   StaticAssertStmt(lengthof(cacheinfo) == SysCacheSize,
-                    "SysCacheSize does not match syscache.c's array");
-
    Assert(!CacheInitialized);
 
    SysCacheRelationOidSize = SysCacheSupportingRelOidSize = 0;
index b6a8bbcd596230750a862480202c10d387503cc9..b45a34abcee0728fbe1ae3b7cb5841abe678042e 100644 (file)
@@ -306,7 +306,7 @@ AllocSetFreeIndex(Size size)
                    tsize;
 
        /* Statically assert that we only have a 16-bit input value. */
-       StaticAssertStmt(ALLOC_CHUNK_LIMIT < (1 << 16),
+       StaticAssertDecl(ALLOC_CHUNK_LIMIT < (1 << 16),
                         "ALLOC_CHUNK_LIMIT must be less than 64kB");
 
        tsize = size - 1;
@@ -358,10 +358,10 @@ AllocSetContextCreateInternal(MemoryContext parent,
    AllocBlock  block;
 
    /* ensure MemoryChunk's size is properly maxaligned */
-   StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
+   StaticAssertDecl(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
                     "sizeof(MemoryChunk) is not maxaligned");
    /* check we have enough space to store the freelist link */
-   StaticAssertStmt(sizeof(AllocFreeListLink) <= (1 << ALLOC_MINBITS),
+   StaticAssertDecl(sizeof(AllocFreeListLink) <= (1 << ALLOC_MINBITS),
                     "sizeof(AllocFreeListLink) larger than minimum allocation size");
 
    /*
index b432a92be31fa40f79c68aaf6c17406bdd338ed0..1f17905b5a3a9f03791fe0fc6dc898b1c43b07cf 100644 (file)
@@ -167,7 +167,7 @@ GenerationContextCreate(MemoryContext parent,
    GenerationBlock *block;
 
    /* ensure MemoryChunk's size is properly maxaligned */
-   StaticAssertStmt(Generation_CHUNKHDRSZ == MAXALIGN(Generation_CHUNKHDRSZ),
+   StaticAssertDecl(Generation_CHUNKHDRSZ == MAXALIGN(Generation_CHUNKHDRSZ),
                     "sizeof(MemoryChunk) is not maxaligned");
 
    /*
index 6df0839b6acdc25e83382fa1d5143b8138ff68d3..c2f9bb6ad34bef6d58e191662ea264aa3be3600d 100644 (file)
@@ -151,7 +151,7 @@ SlabContextCreate(MemoryContext parent,
    int         i;
 
    /* ensure MemoryChunk's size is properly maxaligned */
-   StaticAssertStmt(Slab_CHUNKHDRSZ == MAXALIGN(Slab_CHUNKHDRSZ),
+   StaticAssertDecl(Slab_CHUNKHDRSZ == MAXALIGN(Slab_CHUNKHDRSZ),
                     "sizeof(MemoryChunk) is not maxaligned");
    Assert(MAXALIGN(chunkSize) <= MEMORYCHUNK_MAX_VALUE);
 
index 74d0cf0a2e2d239cb2ccf78f64aeb751d3e4aa7e..8948df4da1a82fc80854f5a5d70a28edfb0f5217 100644 (file)
@@ -177,15 +177,15 @@ pg_checksum_final(pg_checksum_context *context, uint8 *output)
 {
    int         retval = 0;
 
-   StaticAssertStmt(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH,
+   StaticAssertDecl(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH,
                     "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH");
-   StaticAssertStmt(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+   StaticAssertDecl(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
                     "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH");
-   StaticAssertStmt(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+   StaticAssertDecl(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
                     "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH");
-   StaticAssertStmt(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+   StaticAssertDecl(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
                     "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH");
-   StaticAssertStmt(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
+   StaticAssertDecl(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
                     "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH");
 
    switch (context->type)
index 2d1f35bbd188d60e17406b739929679aa067aa34..5c654746fae5c8c319e241348f591164d50b5ea2 100644 (file)
@@ -149,14 +149,6 @@ update_controlfile(const char *DataDir,
    char        buffer[PG_CONTROL_FILE_SIZE];
    char        ControlFilePath[MAXPGPATH];
 
-   /*
-    * Apply the same static assertions as in backend's WriteControlFile().
-    */
-   StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
-                    "pg_control is too large for atomic disk writes");
-   StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
-                    "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
-
    /* Update timestamp  */
    ControlFile->time = (pg_time_t) time(NULL);
 
index 596a23b64da845988816ff3179940def8cbdd079..2329db572bc0efa61e11064d6b9edeb5af58f2a4 100644 (file)
@@ -451,6 +451,9 @@ static const char *const pg_enc2icu_tbl[] =
    "KOI8-U",                   /* PG_KOI8U */
 };
 
+StaticAssertDecl(lengthof(pg_enc2icu_tbl) == PG_ENCODING_BE_LAST + 1,
+                "pg_enc2icu_tbl incomplete");
+
 
 /*
  * Is this encoding supported by ICU?
@@ -469,9 +472,6 @@ is_encoding_supported_by_icu(int encoding)
 const char *
 get_encoding_name_for_icu(int encoding)
 {
-   StaticAssertStmt(lengthof(pg_enc2icu_tbl) == PG_ENCODING_BE_LAST + 1,
-                    "pg_enc2icu_tbl incomplete");
-
    if (!PG_VALID_BE_ENCODING(encoding))
        return NULL;
    return pg_enc2icu_tbl[encoding];
index fff861e2192cca4355cdbbbe7e41b4804d58aaa4..119ed685bb48bab1debbb0ac847f573876b77407 100644 (file)
@@ -57,6 +57,9 @@ typedef struct GinStatsData
  */
 typedef char GinTernaryValue;
 
+StaticAssertDecl(sizeof(GinTernaryValue) == sizeof(bool),
+                "sizes of GinTernaryValue and bool are not equal");
+
 #define GIN_FALSE      0       /* item is not present / does not match */
 #define GIN_TRUE       1       /* item is present / matches */
 #define GIN_MAYBE      2       /* don't know if item is present / don't know
index 9561c835f210698192fa998c95c31d7d207c5306..c1af814e8d007575131748324761930da6cdfd61 100644 (file)
@@ -426,6 +426,9 @@ do { \
    (tup)->t_choice.t_heap.t_field3.t_xvac = (xid); \
 } while (0)
 
+StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
+                "invalid speculative token constant");
+
 #define HeapTupleHeaderIsSpeculative(tup) \
 ( \
    (ItemPointerGetOffsetNumberNoCheck(&(tup)->t_ctid) == SpecTokenOffsetNumber) \
index 8e4f6864e595b190d6fbb1a4c18d5811c9af6cc0..7d5a6fa558eb9a65f33e642f8e19efa0d755d567 100644 (file)
@@ -466,6 +466,13 @@ typedef struct BTVacState
 #define BT_PIVOT_HEAP_TID_ATTR     0x1000
 #define BT_IS_POSTING              0x2000
 
+/*
+ * Mask allocated for number of keys in index tuple must be able to fit
+ * maximum possible number of index attributes
+ */
+StaticAssertDecl(BT_OFFSET_MASK >= INDEX_MAX_KEYS,
+                "BT_OFFSET_MASK can't fit INDEX_MAX_KEYS");
+
 /*
  * Note: BTreeTupleIsPivot() can have false negatives (but not false
  * positives) when used with !heapkeyspace indexes
index 98cdd285dd987368e8b0bdb67d1bbeb76861758c..bd6d8e5bf53243593b4bf47443b70d14e4067ab5 100644 (file)
@@ -847,47 +847,50 @@ extern void ExceptionalCondition(const char *conditionName,
  * 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 there are bizarre syntactic
- * placement restrictions.  Macros StaticAssertStmt() and StaticAssertExpr()
+ * C11 has _Static_assert(), and most C99 compilers already support that.  For
+ * portability, we wrap it into StaticAssertDecl().  _Static_assert() is a
+ * "declaration", and so it must be placed where for example a variable
+ * declaration would be valid.  As long as we compile with
+ * -Wno-declaration-after-statement, that also means it cannot be placed after
+ * statements in a function.  Macros StaticAssertStmt() and StaticAssertExpr()
  * 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
- * 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.
+ * For compilers without _Static_assert(), 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.
  */
 #ifndef __cplusplus
 #ifdef HAVE__STATIC_ASSERT
+#define StaticAssertDecl(condition, errmessage) \
+   _Static_assert(condition, errmessage)
 #define StaticAssertStmt(condition, errmessage) \
    do { _Static_assert(condition, errmessage); } while(0)
 #define StaticAssertExpr(condition, errmessage) \
    ((void) ({ StaticAssertStmt(condition, errmessage); true; }))
-#define StaticAssertDecl(condition, errmessage) \
-   _Static_assert(condition, errmessage)
 #else                          /* !HAVE__STATIC_ASSERT */
+#define StaticAssertDecl(condition, errmessage) \
+   extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
 #define StaticAssertStmt(condition, errmessage) \
    ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
 #define StaticAssertExpr(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 */
 #else                          /* C++ */
 #if defined(__cpp_static_assert) && __cpp_static_assert >= 200410
+#define StaticAssertDecl(condition, errmessage) \
+   static_assert(condition, errmessage)
 #define StaticAssertStmt(condition, errmessage) \
    static_assert(condition, errmessage)
 #define StaticAssertExpr(condition, errmessage) \
    ({ static_assert(condition, errmessage); })
-#define StaticAssertDecl(condition, errmessage) \
-   static_assert(condition, errmessage)
 #else                          /* !__cpp_static_assert */
+#define StaticAssertDecl(condition, errmessage) \
+   extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
 #define StaticAssertStmt(condition, errmessage) \
    do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0)
 #define StaticAssertExpr(condition, errmessage) \
    ((void) ({ StaticAssertStmt(condition, errmessage); }))
-#define StaticAssertDecl(condition, errmessage) \
-   extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
 #endif                         /* __cpp_static_assert */
 #endif                         /* C++ */
 
index 06368e236678690464fcdebf4ed5d22c9a7e3c9b..1b648b7196eee94a0cddb7d810116ff9aeda63f6 100644 (file)
@@ -247,4 +247,12 @@ typedef struct ControlFileData
  */
 #define PG_CONTROL_FILE_SIZE       8192
 
+/*
+ * Ensure that the size of the pg_control data structure is sane.
+ */
+StaticAssertDecl(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
+                "pg_control is too large for atomic disk writes");
+StaticAssertDecl(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
+                "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
+
 #endif                         /* PG_CONTROL_H */
index 8f035cf4cb24806e81cdbcbfbd79c0f660f070b8..4b17aa9689ef81356991138deb1907de76002a10 100644 (file)
@@ -177,7 +177,7 @@ static inline void
 int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
 {
    /* INT64_AU32 must use arithmetic right shift */
-   StaticAssertStmt(((int64) -1 >> 1) == (int64) -1,
+   StaticAssertDecl(((int64) -1 >> 1) == (int64) -1,
                     "arithmetic right shift is needed");
 
    /*----------
index a494cb598ff07dd3d2d7fc7d61a5c199aced39e5..dd818e16abc8ead5df1698a9dfd6320f0a37c986 100644 (file)
@@ -59,6 +59,9 @@ typedef struct LWLock
  */
 #define LWLOCK_PADDED_SIZE PG_CACHE_LINE_SIZE
 
+StaticAssertDecl(sizeof(LWLock) <= LWLOCK_PADDED_SIZE,
+                "Miscalculated LWLock padding");
+
 /* LWLock, padded to a full cache line size */
 typedef union LWLockPadded
 {