Skip to content

Commit 5edd13b

Browse files
committed
Fix Py_BUILD_ASSERT on non-constant expression
1 parent 15fbd53 commit 5edd13b

File tree

13 files changed

+83
-28
lines changed

13 files changed

+83
-28
lines changed

Include/cpython/pyatomic_msc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <intrin.h>
1717

1818
#define _Py_atomic_ASSERT_ARG_TYPE(TYPE) \
19-
Py_BUILD_ASSERT(sizeof(*obj) == sizeof(TYPE))
19+
static_assert(sizeof(*obj) == sizeof(TYPE), "")
2020

2121

2222
// --- _Py_atomic_add --------------------------------------------------------

Include/internal/pycore_bitutils.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ _Py_bswap16(uint16_t word)
3636
#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap16)
3737
return __builtin_bswap16(word);
3838
#elif defined(_MSC_VER)
39-
Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned short));
39+
static_assert(sizeof(word) == sizeof(unsigned short), "");
4040
return _byteswap_ushort(word);
4141
#else
4242
// Portable implementation which doesn't rely on circular bit shift
@@ -51,7 +51,7 @@ _Py_bswap32(uint32_t word)
5151
#if defined(_PY_HAVE_BUILTIN_BSWAP) || _Py__has_builtin(__builtin_bswap32)
5252
return __builtin_bswap32(word);
5353
#elif defined(_MSC_VER)
54-
Py_BUILD_ASSERT(sizeof(word) == sizeof(unsigned long));
54+
static_assert(sizeof(word) == sizeof(unsigned long), "");
5555
return _byteswap_ulong(word);
5656
#else
5757
// Portable implementation which doesn't rely on circular bit shift
@@ -97,12 +97,12 @@ _Py_popcount32(uint32_t x)
9797
#if (defined(__clang__) || defined(__GNUC__))
9898

9999
#if SIZEOF_INT >= 4
100-
Py_BUILD_ASSERT(sizeof(x) <= sizeof(unsigned int));
100+
static_assert(sizeof(x) <= sizeof(unsigned int), "");
101101
return __builtin_popcount(x);
102102
#else
103103
// The C standard guarantees that unsigned long will always be big enough
104104
// to hold a uint32_t value without losing information.
105-
Py_BUILD_ASSERT(sizeof(x) <= sizeof(unsigned long));
105+
static_assert(sizeof(x) <= sizeof(unsigned long), "");
106106
return __builtin_popcountl(x);
107107
#endif
108108

@@ -156,7 +156,7 @@ _Py_bit_length(unsigned long x)
156156
}
157157
#elif defined(_MSC_VER)
158158
// _BitScanReverse() is documented to search 32 bits.
159-
Py_BUILD_ASSERT(sizeof(unsigned long) <= 4);
159+
static_assert(sizeof(unsigned long) <= 4, "");
160160
unsigned long msb;
161161
if (_BitScanReverse(&msb, x)) {
162162
return (int)msb + 1;

Include/internal/pycore_pyhash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ static inline Py_hash_t
1010
_Py_HashPointerRaw(const void *ptr)
1111
{
1212
uintptr_t x = (uintptr_t)ptr;
13-
Py_BUILD_ASSERT(sizeof(x) == sizeof(ptr));
13+
static_assert(sizeof(x) == sizeof(ptr), "");
1414

1515
// Bottom 3 or 4 bits are likely to be 0; rotate x by 4 to the right
1616
// to avoid excessive hash collisions for dicts and sets.
1717
x = (x >> 4) | (x << (8 * sizeof(uintptr_t) - 4));
1818

19-
Py_BUILD_ASSERT(sizeof(x) == sizeof(Py_hash_t));
19+
static_assert(sizeof(x) == sizeof(Py_hash_t), "");
2020
return (Py_hash_t)x;
2121
}
2222

Include/pymacro.h

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@
4040
by "__LINE__". */
4141
#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x)
4242

43+
#define _Py_CONCAT(x, y) x##y
44+
45+
/* Concatenate the arguments. An indirection is required for expanding
46+
arguments once. For example Py_CONCAT(name, __LINE__) is replaced by name
47+
followed by the line number, not by "__LINE__". */
48+
#define Py_CONCAT(x, y) _Py_CONCAT(x, y)
49+
4350
/* Get the size of a structure member in bytes */
4451
#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
4552

@@ -56,13 +63,44 @@
5663
#define foo_to_char(foo) \
5764
((char *)(foo) \
5865
+ Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
66+
Originaly written by Rusty Russell, public domain, http://ccodearchive.net/
67+
Modified to prohibit variable-length arrays(VLA). */
68+
#if defined(__cplusplus)
69+
template<typename T>
70+
struct _Py_BUILD_ASSERT_EXPR_prohibit_vla {
71+
static_assert(sizeof(T) == 1,
72+
"Py_BUILD_ASSERT_EXPR can only be used with constant "
73+
"expression of value true");
74+
};
75+
# define Py_BUILD_ASSERT_EXPR(cond) \
76+
(!sizeof(_Py_BUILD_ASSERT_EXPR_prohibit_vla<char[1 - 2 * !(cond)]>))
77+
#elif defined(_MSC_VER)
78+
# define Py_BUILD_ASSERT_EXPR(cond) \
79+
(!sizeof( \
80+
__pragma(warning(push)) \
81+
__pragma(warning(suppress: 4116)) \
82+
enum { \
83+
Py_CONCAT(_Py_BUILD_ASSERT_EXPR_prohibit_vla_,__LINE__) = \
84+
sizeof(char[1 - 2 * !(cond)]) \
85+
} \
86+
__pragma(warning(pop)) \
87+
))
88+
#else
89+
# define Py_BUILD_ASSERT_EXPR(cond) \
90+
(!sizeof( \
91+
enum { \
92+
Py_CONCAT(_Py_BUILD_ASSERT_EXPR_prohibit_vla_,__LINE__) = \
93+
sizeof(char[1 - 2 * !(cond)]) \
94+
} \
95+
))
96+
#endif
5997

60-
Written by Rusty Russell, public domain, http://ccodearchive.net/ */
61-
#define Py_BUILD_ASSERT_EXPR(cond) \
62-
(sizeof(char [1 - 2*!(cond)]) - 1)
63-
64-
#define Py_BUILD_ASSERT(cond) do { \
65-
(void)Py_BUILD_ASSERT_EXPR(cond); \
98+
/* Deprecated, use static_assert instead. */
99+
#define Py_BUILD_ASSERT(cond) do { \
100+
Py_DEPRECATED(3.13) \
101+
int _Py_BUILD_ASSERT_is_deprecated_use_static_assert_instead = 0; \
102+
_Py_BUILD_ASSERT_is_deprecated_use_static_assert_instead; \
103+
static_assert(cond, ""); \
66104
} while(0)
67105

68106
/* Get the number of elements in a visible array
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Deprecates :c:macro:`Py_BUILD_ASSERT`. Passing non-constant expression to
2+
:c:macro:`Py_BUILD_ASSERT` or :c:macro:`Py_BUILD_ASSERT_EXPR` now makes
3+
compilation failed.

Modules/_ctypes/_ctypes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2750,7 +2750,7 @@ unique_key(CDataObject *target, Py_ssize_t index)
27502750
char *cp = string;
27512751
size_t bytes_left;
27522752

2753-
Py_BUILD_ASSERT(sizeof(string) - 1 > sizeof(Py_ssize_t) * 2);
2753+
static_assert(sizeof(string) - 1 > sizeof(Py_ssize_t) * 2, "");
27542754
cp += sprintf(cp, "%x", Py_SAFE_DOWNCAST(index, Py_ssize_t, int));
27552755
while (target->b_base) {
27562756
bytes_left = sizeof(string) - (cp - string) - 1;

Modules/_ssl.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3620,7 +3620,7 @@ static PyObject *
36203620
get_options(PySSLContext *self, void *c)
36213621
{
36223622
uint64_t options = SSL_CTX_get_options(self->ctx);
3623-
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options));
3623+
static_assert(sizeof(unsigned long long) >= sizeof(options), "");
36243624
return PyLong_FromUnsignedLongLong(options);
36253625
}
36263626

@@ -3642,7 +3642,7 @@ set_options(PySSLContext *self, PyObject *arg, void *c)
36423642
if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) {
36433643
return -1;
36443644
}
3645-
Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg));
3645+
static_assert(sizeof(new_opts) >= sizeof(new_opts_arg), "");
36463646
new_opts = (uint64_t)new_opts_arg;
36473647

36483648
opts = SSL_CTX_get_options(self->ctx);
@@ -6062,7 +6062,7 @@ sslmodule_init_socketapi(PyObject *module)
60626062
static int
60636063
sslmodule_add_option(PyObject *m, const char *name, uint64_t value)
60646064
{
6065-
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value));
6065+
static_assert(sizeof(unsigned long long) >= sizeof(value), "");
60666066
return PyModule_Add(m, name, PyLong_FromUnsignedLongLong(value));
60676067
}
60686068

Modules/_testcapi/hash.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ hash_pointer(PyObject *Py_UNUSED(module), PyObject *arg)
5454
}
5555

5656
Py_hash_t hash = Py_HashPointer(ptr);
57-
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(hash));
57+
static_assert(sizeof(long long) >= sizeof(hash), "");
5858
return PyLong_FromLongLong(hash);
5959
}
6060

@@ -64,7 +64,7 @@ object_generichash(PyObject *Py_UNUSED(module), PyObject *arg)
6464
{
6565
NULLABLE(arg);
6666
Py_hash_t hash = PyObject_GenericHash(arg);
67-
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(hash));
67+
static_assert(sizeof(long long) >= sizeof(hash), "");
6868
return PyLong_FromLongLong(hash);
6969
}
7070

Modules/_testcapi/time.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pytime_from_nanoseconds(PyTime_t *tp, PyObject *obj)
1515
return -1;
1616
}
1717

18-
Py_BUILD_ASSERT(sizeof(long long) == sizeof(PyTime_t));
18+
static_assert(sizeof(long long) == sizeof(PyTime_t), "");
1919
*tp = (PyTime_t)nsec;
2020
return 0;
2121
}
@@ -98,7 +98,7 @@ _PyTestCapi_Init_Time(PyObject *m)
9898
if (PyModule_AddFunctions(m, test_methods) < 0) {
9999
return -1;
100100
}
101-
Py_BUILD_ASSERT(sizeof(long long) == sizeof(PyTime_t));
101+
static_assert(sizeof(long long) == sizeof(PyTime_t), "");
102102
if (PyModule_AddObject(m, "PyTime_MIN", PyLong_FromLongLong(PyTime_MIN)) < 0) {
103103
return 1;
104104
}

Modules/_testcapimodule.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2905,8 +2905,22 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
29052905

29062906
// static_assert(), Py_BUILD_ASSERT()
29072907
static_assert(1 == 1, "bug");
2908+
// Py_BUILD_ASSERT is now deprecated
2909+
#if defined(__GNUC__) || defined(__clang__)
2910+
# pragma GCC diagnostic push
2911+
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2912+
# pragma GCC diagnostic ignored "-Wunused-value"
2913+
#elif defined(_MSC_VER)
2914+
# pragma warning(push)
2915+
# pragma warning(disable:4996)
2916+
# pragma warning(disable:4555)
2917+
#endif
29082918
Py_BUILD_ASSERT(1 == 1);
2909-
2919+
#if defined(__GNUC__)
2920+
# pragma GCC diagnostic pop
2921+
#elif defined(_MSC_VER)
2922+
# pragma warning(pop)
2923+
#endif
29102924

29112925
// Py_MIN(), Py_MAX(), Py_ABS()
29122926
assert(Py_MIN(5, 11) == 5);

Modules/_testinternalcapi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1931,7 +1931,7 @@ static PyObject *
19311931
get_py_thread_id(PyObject *self, PyObject *Py_UNUSED(ignored))
19321932
{
19331933
uintptr_t tid = _Py_ThreadId();
1934-
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(tid));
1934+
static_assert(sizeof(unsigned long long) >= sizeof(tid), "");
19351935
return PyLong_FromUnsignedLongLong(tid);
19361936
}
19371937
#endif

Modules/timemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ time_clockid_converter(PyObject *obj, clockid_t *p)
198198
}
199199

200200
// Make sure that we picked the right type (check sizes type)
201-
Py_BUILD_ASSERT(sizeof(clk_id) == sizeof(*p));
201+
static_assert(sizeof(clk_id) == sizeof(*p), "");
202202
*p = (clockid_t)clk_id;
203203
return 1;
204204
}

Python/pytime.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ py_win_perf_counter_frequency(_PyTimeFraction *base, int raise_exc)
10461046
// Since Windows XP, frequency cannot be zero.
10471047
assert(frequency >= 1);
10481048

1049-
Py_BUILD_ASSERT(sizeof(PyTime_t) == sizeof(frequency));
1049+
static_assert(sizeof(PyTime_t) == sizeof(frequency), "");
10501050
PyTime_t denom = (PyTime_t)frequency;
10511051

10521052
// Known QueryPerformanceFrequency() values:
@@ -1113,8 +1113,8 @@ py_mach_timebase_info(_PyTimeFraction *base, int raise_exc)
11131113
// PyTime_t. In practice, timebase uses uint32_t, so casting cannot
11141114
// overflow. At the end, only make sure that the type is uint32_t
11151115
// (PyTime_t is 64-bit long).
1116-
Py_BUILD_ASSERT(sizeof(timebase.numer) <= sizeof(PyTime_t));
1117-
Py_BUILD_ASSERT(sizeof(timebase.denom) <= sizeof(PyTime_t));
1116+
static_assert(sizeof(timebase.numer) <= sizeof(PyTime_t), "");
1117+
static_assert(sizeof(timebase.denom) <= sizeof(PyTime_t), "");
11181118
PyTime_t numer = (PyTime_t)timebase.numer;
11191119
PyTime_t denom = (PyTime_t)timebase.denom;
11201120

0 commit comments

Comments
 (0)