]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-91731: Replace Py_BUILD_ASSERT() with static_assert() (#91730)
authorVictor Stinner <vstinner@python.org>
Wed, 20 Apr 2022 17:26:40 +0000 (19:26 +0200)
committerGitHub <noreply@github.com>
Wed, 20 Apr 2022 17:26:40 +0000 (19:26 +0200)
Python 3.11 now uses C11 standard which adds static_assert()
to <assert.h>.

* In pytime.c, replace Py_BUILD_ASSERT() with preprocessor checks on
  SIZEOF_TIME_T with #error.
* On macOS, py_mach_timebase_info() now accepts timebase members with
  the same size than _PyTime_t.
* py_get_monotonic_clock() now saturates GetTickCount64() to
  _PyTime_MAX: GetTickCount64() is unsigned, whereas _PyTime_t is
  signed.

Modules/_datetimemodule.c
Modules/_pickle.c
Modules/_testcapimodule.c
Modules/posixmodule.c
Modules/pyexpat.c
Objects/longobject.c
Objects/sliceobject.c
Python/fileutils.c
Python/initconfig.c
Python/pytime.c

index fc766c3c94360329d32417fc300b9cd11293bdbb..a35c72395ec95384d805c72883ae7a111ed0ea35 100644 (file)
@@ -6637,19 +6637,19 @@ _datetime_exec(PyObject *module)
     /* A 4-year cycle has an extra leap day over what we'd get from
      * pasting together 4 single years.
      */
-    Py_BUILD_ASSERT(DI4Y == 4 * 365 + 1);
+    static_assert(DI4Y == 4 * 365 + 1, "DI4Y");
     assert(DI4Y == days_before_year(4+1));
 
     /* Similarly, a 400-year cycle has an extra leap day over what we'd
      * get from pasting together 4 100-year cycles.
      */
-    Py_BUILD_ASSERT(DI400Y == 4 * DI100Y + 1);
+    static_assert(DI400Y == 4 * DI100Y + 1, "DI400Y");
     assert(DI400Y == days_before_year(400+1));
 
     /* OTOH, a 100-year cycle has one fewer leap day than we'd get from
      * pasting together 25 4-year cycles.
      */
-    Py_BUILD_ASSERT(DI100Y == 25 * DI4Y - 1);
+    static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
     assert(DI100Y == days_before_year(100+1));
 
     us_per_ms = PyLong_FromLong(1000);
index a5595eb10c8f10bc0a071768c08c3219335fa252..7a8c9ed7243c348aa09c380c940aff0b94a3668f 100644 (file)
@@ -964,7 +964,7 @@ _write_size64(char *out, size_t value)
 {
     size_t i;
 
-    Py_BUILD_ASSERT(sizeof(size_t) <= 8);
+    static_assert(sizeof(size_t) <= 8, "size_t is larger than 64-bit");
 
     for (i = 0; i < sizeof(size_t); i++) {
         out[i] = (unsigned char)((value >> (8 * i)) & 0xff);
index 23af0d36b6ceb4e7f3e0f2964bace80be9703e27..6bd73e8f45379999e173e414a1da8f6d9a3ed933 100644 (file)
@@ -5157,7 +5157,8 @@ dict_get_version(PyObject *self, PyObject *args)
 
     version = dict->ma_version_tag;
 
-    Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(version));
+    static_assert(sizeof(unsigned long long) >= sizeof(version),
+                  "version is larger than unsigned long long");
     return PyLong_FromUnsignedLongLong((unsigned long long)version);
 }
 
index 700cbd2617ad88910e1b7a1d01b1b6bcece581c6..345ed710248f9bb992c294370c23143ef56328c0 100644 (file)
@@ -2381,7 +2381,8 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
         return NULL;
 
     PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
-    Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(st->st_ino));
+    static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
+                  "stat.st_ino is larger than unsigned long long");
     PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
 #ifdef MS_WINDOWS
     PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
@@ -2396,7 +2397,8 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
     PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
     PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
 #endif
-    Py_BUILD_ASSERT(sizeof(long long) >= sizeof(st->st_size));
+    static_assert(sizeof(long long) >= sizeof(st->st_size),
+                  "stat.st_size is larger than long long");
     PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));
 
 #if defined(HAVE_STAT_TV_NSEC)
@@ -13761,10 +13763,12 @@ _Py_COMP_DIAG_POP
         self->win32_file_index = stat.st_ino;
         self->got_file_index = 1;
     }
-    Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->win32_file_index));
+    static_assert(sizeof(unsigned long long) >= sizeof(self->win32_file_index),
+                  "DirEntry.win32_file_index is larger than unsigned long long");
     return PyLong_FromUnsignedLongLong(self->win32_file_index);
 #else /* POSIX */
-    Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->d_ino));
+    static_assert(sizeof(unsigned long long) >= sizeof(self->d_ino),
+                  "DirEntry.d_ino is larger than unsigned long long");
     return PyLong_FromUnsignedLongLong(self->d_ino);
 #endif
 }
index 7a26fe24e7592d0047af2363dd648815b59c449a..ad8148adae98beb76fb20a731787cd50d89fbc5f 100644 (file)
@@ -745,6 +745,8 @@ pyexpat_xmlparser_Parse_impl(xmlparseobject *self, PyTypeObject *cls,
         slen = view.len;
     }
 
+    static_assert(MAX_CHUNK_SIZE <= INT_MAX,
+                  "MAX_CHUNK_SIZE is larger than INT_MAX");
     while (slen > MAX_CHUNK_SIZE) {
         rc = XML_Parse(self->itself, s, MAX_CHUNK_SIZE, 0);
         if (!rc)
@@ -752,7 +754,7 @@ pyexpat_xmlparser_Parse_impl(xmlparseobject *self, PyTypeObject *cls,
         s += MAX_CHUNK_SIZE;
         slen -= MAX_CHUNK_SIZE;
     }
-    Py_BUILD_ASSERT(MAX_CHUNK_SIZE <= INT_MAX);
+
     assert(slen <= INT_MAX);
     rc = XML_Parse(self->itself, s, (int)slen, isfinal);
 
index 660824f90659fbbd4f382df9fedbcf85d6cf4030..e805dac1209e71c19cc45b69488f49305b878dbe 100644 (file)
@@ -771,7 +771,10 @@ _PyLong_Sign(PyObject *vv)
 static int
 bit_length_digit(digit x)
 {
-    Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8);
+    // digit can be larger than unsigned long, but only PyLong_SHIFT bits
+    // of it will be ever used.
+    static_assert(PyLong_SHIFT <= sizeof(unsigned long) * 8,
+                  "digit is larger than unsigned long");
     return _Py_bit_length((unsigned long)x);
 }
 
@@ -5647,7 +5650,7 @@ popcount_digit(digit d)
 {
     // digit can be larger than uint32_t, but only PyLong_SHIFT bits
     // of it will be ever used.
-    Py_BUILD_ASSERT(PyLong_SHIFT <= 32);
+    static_assert(PyLong_SHIFT <= 32, "digit is larger than uint32_t");
     return _Py_popcount32((uint32_t)d);
 }
 
index 22fb7c61c354f9a9296707edecf5f761c4631f2b..713829da574d50a7711d515fca52c8e0be625e6e 100644 (file)
@@ -206,7 +206,8 @@ PySlice_Unpack(PyObject *_r,
     PySliceObject *r = (PySliceObject*)_r;
     /* this is harder to get right than you might think */
 
-    Py_BUILD_ASSERT(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX);
+    static_assert(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX,
+                  "-PY_SSIZE_T_MAX < PY_SSIZE_T_MIN + 1");
 
     if (r->step == Py_None) {
         *step = 1;
index 582c6bafd801abaef12856956ced39c0b7a464d4..4f7f8944a72da5ccc060ebce81891e0f91d1bfb8 100644 (file)
@@ -956,7 +956,7 @@ static wchar_t *
 _Py_ConvertWCharForm(const wchar_t *source, Py_ssize_t size,
                      const char *tocode, const char *fromcode)
 {
-    Py_BUILD_ASSERT(sizeof(wchar_t) == 4);
+    static_assert(sizeof(wchar_t) == 4, "wchar_t must be 32-bit");
 
     /* Ensure we won't overflow the size. */
     if (size > (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(wchar_t))) {
index d2e74f5878a5132a85cfe0e44cf3fc0144231dca..729f7f393a39b59590ebdbd4df424d516df141f7 100644 (file)
@@ -1507,9 +1507,11 @@ config_get_xoption_value(const PyConfig *config, wchar_t *name)
 static PyStatus
 config_init_hash_seed(PyConfig *config)
 {
+    static_assert(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc),
+                  "_Py_HashSecret_t has wrong size");
+
     const char *seed_text = config_get_env(config, "PYTHONHASHSEED");
 
-    Py_BUILD_ASSERT(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc));
     /* Convert a text seed to a numeric one */
     if (seed_text && strcmp(seed_text, "random") != 0) {
         const char *endptr = seed_text;
index aff20c6e5f1d45000db005c7f8da70d7c11be4bd..f49a25bf7bce7cefc1b870d5fd4c05baa8098359 100644 (file)
@@ -162,12 +162,11 @@ time_t
 _PyLong_AsTime_t(PyObject *obj)
 {
 #if SIZEOF_TIME_T == SIZEOF_LONG_LONG
-    long long val;
-    val = PyLong_AsLongLong(obj);
+    long long val = PyLong_AsLongLong(obj);
+#elif SIZEOF_TIME_T <= SIZEOF_LONG
+    long val = PyLong_AsLong(obj);
 #else
-    long val;
-    Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long));
-    val = PyLong_AsLong(obj);
+#   error "unsupported time_t size"
 #endif
     if (val == -1 && PyErr_Occurred()) {
         if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
@@ -184,9 +183,10 @@ _PyLong_FromTime_t(time_t t)
 {
 #if SIZEOF_TIME_T == SIZEOF_LONG_LONG
     return PyLong_FromLongLong((long long)t);
-#else
-    Py_BUILD_ASSERT(sizeof(time_t) <= sizeof(long));
+#elif SIZEOF_TIME_T <= SIZEOF_LONG
     return PyLong_FromLong((long)t);
+#else
+#   error "unsupported time_t size"
 #endif
 }
 
@@ -386,10 +386,10 @@ _PyTime_t
 _PyTime_FromSeconds(int seconds)
 {
     /* ensure that integer overflow cannot happen, int type should have 32
-       bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_MS takes 30
+       bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_NS takes 30
        bits). */
-    Py_BUILD_ASSERT(INT_MAX <= _PyTime_MAX / SEC_TO_NS);
-    Py_BUILD_ASSERT(INT_MIN >= _PyTime_MIN / SEC_TO_NS);
+    static_assert(INT_MAX <= _PyTime_MAX / SEC_TO_NS, "_PyTime_t overflow");
+    static_assert(INT_MIN >= _PyTime_MIN / SEC_TO_NS, "_PyTime_t underflow");
 
     _PyTime_t t = (_PyTime_t)seconds;
     assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS)
@@ -416,7 +416,8 @@ _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
         return -1;
     }
 
-    Py_BUILD_ASSERT(sizeof(long long) == sizeof(_PyTime_t));
+    static_assert(sizeof(long long) == sizeof(_PyTime_t),
+                  "_PyTime_t is not long long");
     long long nsec = PyLong_AsLongLong(obj);
     if (nsec == -1 && PyErr_Occurred()) {
         if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
@@ -437,7 +438,8 @@ pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise_exc)
 {
     _PyTime_t t, tv_nsec;
 
-    Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
+    static_assert(sizeof(ts->tv_sec) <= sizeof(_PyTime_t),
+                  "timespec.tv_sec is larger than _PyTime_t");
     t = (_PyTime_t)ts->tv_sec;
 
     int res1 = pytime_mul(&t, SEC_TO_NS);
@@ -466,7 +468,8 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
 static int
 pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise_exc)
 {
-    Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
+    static_assert(sizeof(tv->tv_sec) <= sizeof(_PyTime_t),
+                  "timeval.tv_sec is larger than _PyTime_t");
     _PyTime_t t = (_PyTime_t)tv->tv_sec;
 
     int res1 = pytime_mul(&t, SEC_TO_NS);
@@ -537,7 +540,8 @@ pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round,
             return -1;
         }
 
-        Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
+        static_assert(sizeof(long long) <= sizeof(_PyTime_t),
+                      "_PyTime_t is smaller than long long");
         _PyTime_t ns = (_PyTime_t)sec;
         if (pytime_mul(&ns, unit_to_ns) < 0) {
             pytime_overflow();
@@ -589,7 +593,8 @@ PyObject *
 _PyTime_AsNanosecondsObject(_PyTime_t t)
 {
     _PyTime_t ns =  pytime_as_nanoseconds(t);
-    Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t));
+    static_assert(sizeof(long long) >= sizeof(_PyTime_t),
+                  "_PyTime_t is larger than long long");
     return PyLong_FromLongLong((long long)ns);
 }
 
@@ -984,15 +989,17 @@ py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise)
        _PyTime_t. In practice, timebase uses uint32_t, so casting cannot
        overflow. At the end, only make sure that the type is uint32_t
        (_PyTime_t is 64-bit long). */
-    Py_BUILD_ASSERT(sizeof(timebase.numer) < sizeof(_PyTime_t));
-    Py_BUILD_ASSERT(sizeof(timebase.denom) < sizeof(_PyTime_t));
+    static_assert(sizeof(timebase.numer) <= sizeof(_PyTime_t),
+                  "timebase.numer is larger than _PyTime_t");
+    static_assert(sizeof(timebase.denom) <= sizeof(_PyTime_t),
+                  "timebase.denom is larger than _PyTime_t");
 
-    /* Make sure that (ticks * timebase.numer) cannot overflow in
-       _PyTime_MulDiv(), with ticks < timebase.denom.
+    /* Make sure that _PyTime_MulDiv(ticks, timebase_numer, timebase_denom)
+       cannot overflow.
 
        Known time bases:
 
-       * always (1, 1) on Intel
+       * (1, 1) on Intel
        * (1000000000, 33333335) or (1000000000, 25000000) on PowerPC
 
        None of these time bases can overflow with 64-bit _PyTime_t, but
@@ -1019,8 +1026,17 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
 
 #if defined(MS_WINDOWS)
     ULONGLONG ticks = GetTickCount64();
-    Py_BUILD_ASSERT(sizeof(ticks) <= sizeof(_PyTime_t));
-    _PyTime_t t = (_PyTime_t)ticks;
+    static_assert(sizeof(ticks) <= sizeof(_PyTime_t),
+                  "ULONGLONG is larger than _PyTime_t");
+    _PyTime_t t;
+    if (ticks <= (ULONGLONG)_PyTime_MAX) {
+        t = (_PyTime_t)ticks;
+    }
+    else {
+        // GetTickCount64() maximum is larger than _PyTime_t maximum:
+        // ULONGLONG is unsigned, whereas _PyTime_t is signed.
+        t = _PyTime_MAX;
+    }
 
     int res = pytime_mul(&t, MS_TO_NS);
     *tp = t;
@@ -1211,7 +1227,8 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
     /* Make sure that casting LONGLONG to _PyTime_t cannot overflow,
        both types are signed */
     _PyTime_t ticks;
-    Py_BUILD_ASSERT(sizeof(ticksll) <= sizeof(ticks));
+    static_assert(sizeof(ticksll) <= sizeof(ticks),
+                  "LONGLONG is larger than _PyTime_t");
     ticks = (_PyTime_t)ticksll;
 
     _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency);