Skip to content

Commit 587388f

Browse files
authored
gh-118124: Use static_assert() in Py_BUILD_ASSERT() on C11 (#118398)
Use static_assert() in Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR() on C11 and newer and C++11 and newer. Add tests to test_cext and test_cppext.
1 parent 6999d68 commit 587388f

File tree

4 files changed

+45
-16
lines changed

4 files changed

+45
-16
lines changed

Include/pymacro.h

+33-16
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,41 @@
4646
/* Argument must be a char or an int in [-128, 127] or [0, 255]. */
4747
#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff))
4848

49-
/* Assert a build-time dependency, as an expression.
50-
51-
Your compile will fail if the condition isn't true, or can't be evaluated
52-
by the compiler. This can be used in an expression: its value is 0.
53-
54-
Example:
55-
56-
#define foo_to_char(foo) \
57-
((char *)(foo) \
58-
+ Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
59-
60-
Written by Rusty Russell, public domain, http://ccodearchive.net/ */
61-
#define Py_BUILD_ASSERT_EXPR(cond) \
49+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
50+
# define Py_BUILD_ASSERT_EXPR(cond) \
51+
((void)sizeof(struct { int dummy; _Static_assert(cond, #cond); }), \
52+
0)
53+
#else
54+
/* Assert a build-time dependency, as an expression.
55+
*
56+
* Your compile will fail if the condition isn't true, or can't be evaluated
57+
* by the compiler. This can be used in an expression: its value is 0.
58+
*
59+
* Example:
60+
*
61+
* #define foo_to_char(foo) \
62+
* ((char *)(foo) \
63+
* + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
64+
*
65+
* Written by Rusty Russell, public domain, http://ccodearchive.net/
66+
*/
67+
# define Py_BUILD_ASSERT_EXPR(cond) \
6268
(sizeof(char [1 - 2*!(cond)]) - 1)
69+
#endif
6370

64-
#define Py_BUILD_ASSERT(cond) do { \
65-
(void)Py_BUILD_ASSERT_EXPR(cond); \
66-
} while(0)
71+
#if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
72+
|| (defined(__cplusplus) && __cplusplus >= 201103L))
73+
// Use static_assert() on C11 and newer
74+
# define Py_BUILD_ASSERT(cond) \
75+
do { \
76+
static_assert((cond), #cond); \
77+
} while (0)
78+
#else
79+
# define Py_BUILD_ASSERT(cond) \
80+
do { \
81+
(void)Py_BUILD_ASSERT_EXPR(cond); \
82+
} while(0)
83+
#endif
6784

6885
/* Get the number of elements in a visible array
6986

Lib/test/test_cext/extension.c

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ _testcext_exec(PyObject *module)
4444
return -1;
4545
}
4646
#endif
47+
48+
// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
49+
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
50+
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);
51+
4752
return 0;
4853
}
4954

Lib/test/test_cppext/extension.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ _testcppext_exec(PyObject *module)
225225
if (!result) return -1;
226226
Py_DECREF(result);
227227

228+
// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
229+
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
230+
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);
231+
228232
return 0;
229233
}
230234

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :c:macro:`Py_BUILD_ASSERT` and :c:macro:`Py_BUILD_ASSERT_EXPR` for
2+
non-constant expressions: use ``static_assert()`` on C11 and newer.
3+
Patch by Victor Stinner.

0 commit comments

Comments
 (0)