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.
This commit is contained in:
Victor Stinner 2024-04-30 22:29:48 +02:00 committed by GitHub
parent 6999d68d28
commit 587388ff22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 16 deletions

View file

@ -46,24 +46,41 @@
/* Argument must be a char or an int in [-128, 127] or [0, 255]. */
#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff))
/* Assert a build-time dependency, as an expression.
Your compile will fail if the condition isn't true, or can't be evaluated
by the compiler. This can be used in an expression: its value is 0.
Example:
#define foo_to_char(foo) \
((char *)(foo) \
+ Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
Written by Rusty Russell, public domain, http://ccodearchive.net/ */
#define Py_BUILD_ASSERT_EXPR(cond) \
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define Py_BUILD_ASSERT_EXPR(cond) \
((void)sizeof(struct { int dummy; _Static_assert(cond, #cond); }), \
0)
#else
/* Assert a build-time dependency, as an expression.
*
* Your compile will fail if the condition isn't true, or can't be evaluated
* by the compiler. This can be used in an expression: its value is 0.
*
* Example:
*
* #define foo_to_char(foo) \
* ((char *)(foo) \
* + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0))
*
* Written by Rusty Russell, public domain, http://ccodearchive.net/
*/
# define Py_BUILD_ASSERT_EXPR(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
#endif
#define Py_BUILD_ASSERT(cond) do { \
(void)Py_BUILD_ASSERT_EXPR(cond); \
} while(0)
#if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|| (defined(__cplusplus) && __cplusplus >= 201103L))
// Use static_assert() on C11 and newer
# define Py_BUILD_ASSERT(cond) \
do { \
static_assert((cond), #cond); \
} while (0)
#else
# define Py_BUILD_ASSERT(cond) \
do { \
(void)Py_BUILD_ASSERT_EXPR(cond); \
} while(0)
#endif
/* Get the number of elements in a visible array

View file

@ -44,6 +44,11 @@ _testcext_exec(PyObject *module)
return -1;
}
#endif
// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);
return 0;
}

View file

@ -225,6 +225,10 @@ _testcppext_exec(PyObject *module)
if (!result) return -1;
Py_DECREF(result);
// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);
return 0;
}

View file

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