gh-146175: Soft-deprecate outdated macros; convert internal usage (GH-146178)

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Petr Viktorin 2026-03-23 12:42:09 +01:00 committed by GitHub
parent 90f9991abb
commit 91cd2e5806
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 160 additions and 47 deletions

View file

@ -526,14 +526,26 @@ to the C language.
Outdated macros
---------------
The following macros have been used to features that have been standardized
in C11.
The following :term:`soft deprecated` macros have been used to features that
have been standardized in C11 (or previous standards).
.. c:macro:: Py_ALIGNED(num)
Specify alignment to *num* bytes on compilers that support it.
On some GCC-like compilers, specify alignment to *num* bytes.
This does nothing on other compilers.
Consider using the C11 standard ``_Alignas`` specifier over this macro.
Use the standard ``alignas`` specifier rather than this macro.
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. c:macro:: PY_FORMAT_SIZE_T
The :c:func:`printf` formatting modifier for :c:type:`size_t`.
Use ``"z"`` directly instead.
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. c:macro:: Py_LL(number)
Py_ULL(number)
@ -546,6 +558,38 @@ in C11.
Consider using the C99 standard suffixes ``LL`` and ``LLU`` directly.
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. c:macro:: PY_LONG_LONG
PY_INT32_T
PY_UINT32_T
PY_INT64_T
PY_UINT64_T
Aliases for the types :c:type:`!long long`, :c:type:`!int32_t`,
:c:type:`!uint32_t`. :c:type:`!int64_t` and :c:type:`!uint64_t`,
respectively.
Historically, these types needed compiler-specific extensions.
.. deprecated:: next
These macros are :term:`soft deprecated`.
.. c:macro:: PY_LLONG_MIN
PY_LLONG_MAX
PY_ULLONG_MAX
PY_SIZE_MAX
Aliases for the values :c:macro:`!LLONG_MIN`, :c:macro:`!LLONG_MAX`,
:c:macro:`!ULLONG_MAX`, and :c:macro:`!SIZE_MAX`, respectively.
Use these standard names instead.
The required header, ``<limits.h>``,
:ref:`is included <capi-system-includes>` in ``Python.h``.
.. deprecated:: next
These macros are :term:`soft deprecated`.
.. c:macro:: Py_MEMCPY(dest, src, n)
This is a :term:`soft deprecated` alias to :c:func:`!memcpy`.
@ -554,6 +598,25 @@ in C11.
.. deprecated:: 3.14
The macro is :term:`soft deprecated`.
.. c:macro:: Py_UNICODE_SIZE
Size of the :c:type:`!wchar_t` type.
Use ``sizeof(wchar_t)`` or ``WCHAR_WIDTH/8`` instead.
The required header for the latter, ``<limits.h>``,
:ref:`is included <capi-system-includes>` in ``Python.h``.
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. c:macro:: Py_UNICODE_WIDE
Defined if ``wchar_t`` can hold a Unicode character (UCS-4).
Use ``sizeof(wchar_t) >= 4`` instead
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. c:macro:: Py_VA_COPY
This is a :term:`soft deprecated` alias to the C99-standard ``va_copy``
@ -564,6 +627,9 @@ in C11.
.. versionchanged:: 3.6
This is now an alias to ``va_copy``.
.. deprecated:: next
The macro is :term:`soft deprecated`.
.. _api-objects:

View file

@ -7,8 +7,6 @@ Pending removal in Python 3.15
Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project
<https://github.com/python/pythoncapi-compat/>`__ can be used to get
:c:func:`PyWeakref_GetRef` on Python 3.12 and older.
* :c:type:`Py_UNICODE` type and the :c:macro:`!Py_UNICODE_WIDE` macro:
Use :c:type:`wchar_t` instead.
* :c:func:`!PyUnicode_AsDecodedObject`:
Use :c:func:`PyCodec_Decode` instead.
* :c:func:`!PyUnicode_AsDecodedUnicode`:

View file

@ -1874,6 +1874,24 @@ Deprecated C APIs
use the C11 standard ``<math.h>`` :c:macro:`!INFINITY` instead.
(Contributed by Sergey B Kirpichev in :gh:`141004`.)
* The following macros are :term:`soft deprecated`:
- :c:macro:`Py_ALIGNED`: Prefer ``alignas`` instead.
- :c:macro:`PY_FORMAT_SIZE_T`: Use ``"z"`` directly.
- :c:macro:`Py_LL` & :c:macro:`Py_ULL`:
Use standard suffixes, ``LL`` & ``ULL``.
- :c:macro:`PY_LONG_LONG`, :c:macro:`PY_LLONG_MIN`, :c:macro:`PY_LLONG_MAX`,
:c:macro:`PY_ULLONG_MAX`, :c:macro:`PY_INT32_T`, :c:macro:`PY_UINT32_T`,
:c:macro:`PY_INT64_T`, :c:macro:`PY_UINT64_T`, :c:macro:`PY_SIZE_MAX`:
Use C99 types/limits.
- :c:macro:`Py_UNICODE_SIZE`: Use ``sizeof(wchar_t)`` directly.
- :c:macro:`Py_VA_COPY`: Use ``va_copy`` directly.
The macro :c:macro:`Py_UNICODE_WIDE`, which was scheduled for removal,
is :term:`soft deprecated` instead.
(Contributed by Petr Viktorin in :gh:`146175`.)
* :c:macro:`!Py_MATH_El` and :c:macro:`!Py_MATH_PIl` are deprecated
since 3.15 and will be removed in 3.20.
(Contributed by Sergey B Kirpichev in :gh:`141004`.)

View file

@ -144,7 +144,7 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
new_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
}
# if SIZEOF_VOID_P > 4
op->ob_refcnt = (PY_UINT32_T)new_refcnt;
op->ob_refcnt = (uint32_t)new_refcnt;
# else
op->ob_refcnt = new_refcnt;
# endif

View file

@ -127,7 +127,7 @@ whose size is determined when the object is allocated.
struct _object {
_Py_ANONYMOUS union {
#if SIZEOF_VOID_P > 4
PY_INT64_T ob_refcnt_full; /* This field is needed for efficient initialization with Clang on ARM */
int64_t ob_refcnt_full; /* This field is needed for efficient initialization with Clang on ARM */
struct {
# if PY_BIG_ENDIAN
uint16_t ob_flags;

View file

@ -446,7 +446,9 @@ extern "C" {
/*
* Specify alignment on compilers that support it.
*/
#if defined(__GNUC__) && __GNUC__ >= 3
#ifdef Py_BUILD_CORE
// always use _Py_ALIGNED_DEF instead
#elif defined(__GNUC__) && __GNUC__ >= 3
#define Py_ALIGNED(x) __attribute__((aligned(x)))
#else
#define Py_ALIGNED(x)

View file

@ -126,7 +126,7 @@ static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
return (_Py_atomic_load_uint32_relaxed(&op->ob_ref_local) ==
_Py_IMMORTAL_REFCNT_LOCAL);
#elif SIZEOF_VOID_P > 4
return _Py_CAST(PY_INT32_T, op->ob_refcnt) < 0;
return _Py_CAST(int32_t, op->ob_refcnt) < 0;
#else
return op->ob_refcnt >= _Py_IMMORTAL_MINIMUM_REFCNT;
#endif
@ -164,7 +164,7 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
}
#ifndef Py_GIL_DISABLED
#if SIZEOF_VOID_P > 4
ob->ob_refcnt = (PY_UINT32_T)refcnt;
ob->ob_refcnt = (uint32_t)refcnt;
#else
ob->ob_refcnt = refcnt;
#endif
@ -278,7 +278,7 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
_Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT));
}
#elif SIZEOF_VOID_P > 4
PY_UINT32_T cur_refcnt = op->ob_refcnt;
uint32_t cur_refcnt = op->ob_refcnt;
if (cur_refcnt >= _Py_IMMORTAL_INITIAL_REFCNT) {
// the object is immortal
_Py_INCREF_IMMORTAL_STAT_INC();
@ -387,7 +387,7 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
#if SIZEOF_VOID_P > 4
/* If an object has been freed, it will have a negative full refcnt
* If it has not it been freed, will have a very large refcnt */
if (op->ob_refcnt_full <= 0 || op->ob_refcnt > (((PY_UINT32_T)-1) - (1<<20))) {
if (op->ob_refcnt_full <= 0 || op->ob_refcnt > (((uint32_t)-1) - (1<<20))) {
#else
if (op->ob_refcnt <= 0) {
#endif

View file

@ -64,13 +64,9 @@ Copyright (c) Corporation for National Research Initiatives.
#error Must define SIZEOF_WCHAR_T
#endif
/* Soft-deprecated defines */
#define Py_UNICODE_SIZE SIZEOF_WCHAR_T
/* If wchar_t can be used for UCS-4 storage, set Py_UNICODE_WIDE.
Otherwise, Unicode strings are stored as UCS-2 (with limited support
for UTF-16) */
#if Py_UNICODE_SIZE >= 4
#if SIZEOF_WCHAR_T >= 4
#define Py_UNICODE_WIDE
#endif

View file

@ -0,0 +1,12 @@
The following macros are :term:`soft deprecated`:
:c:macro:`Py_ALIGNED`,
:c:macro:`PY_FORMAT_SIZE_T`,
:c:macro:`Py_LL`, :c:macro:`Py_ULL`,
:c:macro:`PY_LONG_LONG`, :c:macro:`PY_LLONG_MIN`, :c:macro:`PY_LLONG_MAX`,
:c:macro:`PY_ULLONG_MAX`, :c:macro:`PY_INT32_T`, :c:macro:`PY_UINT32_T`,
:c:macro:`PY_INT64_T`, :c:macro:`PY_UINT64_T`, :c:macro:`PY_SIZE_MAX`,
:c:macro:`Py_UNICODE_SIZE`,
:c:macro:`Py_VA_COPY`.
The macro :c:macro:`Py_UNICODE_WIDE`, which was scheduled for removal, is
:term:`soft deprecated` instead.

View file

@ -111,7 +111,7 @@ resize_buffer(stringio *self, size_t size)
alloc = size + 1;
}
if (alloc > PY_SIZE_MAX / sizeof(Py_UCS4))
if (alloc > SIZE_MAX / sizeof(Py_UCS4))
goto overflow;
new_buf = (Py_UCS4 *)PyMem_Realloc(self->buf, alloc * sizeof(Py_UCS4));
if (new_buf == NULL) {

View file

@ -2607,6 +2607,41 @@ create_managed_weakref_nogc_type(PyObject *self, PyObject *Py_UNUSED(args))
}
static PyObject*
test_soft_deprecated_macros(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
{
// Test soft-deprecated macros
Py_ALIGNED(64) char buf[4];
#ifdef __GNUC__
// Py_ALIGNED must compile everywhere, but only does something
// on "supported" compilers, i.e. GCC
Py_BUILD_ASSERT(__extension__ __alignof__(buf) >= 64);
#endif
assert(strcmp(PY_FORMAT_SIZE_T, "z") == 0);
Py_BUILD_ASSERT(Py_LL(123) == 123LL);
Py_BUILD_ASSERT(sizeof(Py_LL(123)) == sizeof(long long));
Py_BUILD_ASSERT(sizeof(Py_ULL(123)) == sizeof(unsigned long long));
Py_BUILD_ASSERT(sizeof(PY_LONG_LONG) == sizeof(long long));
Py_BUILD_ASSERT(sizeof(PY_INT32_T) == sizeof(int32_t));
Py_BUILD_ASSERT(sizeof(PY_UINT32_T) == sizeof(uint32_t));
Py_BUILD_ASSERT(sizeof(PY_INT64_T) == sizeof(int64_t));
Py_BUILD_ASSERT(sizeof(PY_UINT64_T) == sizeof(uint64_t));
Py_BUILD_ASSERT(PY_LLONG_MIN == LLONG_MIN);
Py_BUILD_ASSERT(PY_LLONG_MAX == LLONG_MAX);
Py_BUILD_ASSERT(PY_ULLONG_MAX == ULLONG_MAX);
Py_BUILD_ASSERT(PY_SIZE_MAX == SIZE_MAX);
Py_BUILD_ASSERT(PY_LLONG_MIN == LLONG_MIN);
Py_MEMCPY(buf, "abc", 4);
assert(strcmp(buf, "abc") == 0);
Py_BUILD_ASSERT(Py_UNICODE_SIZE == sizeof(wchar_t));
#ifdef Py_UNICODE_WIDE
Py_BUILD_ASSERT(sizeof(wchar_t) >= 4);
#else
Py_BUILD_ASSERT(sizeof(wchar_t) < 4);
#endif
Py_RETURN_NONE;
}
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
@ -2704,6 +2739,7 @@ static PyMethodDef TestMethods[] = {
{"toggle_reftrace_printer", toggle_reftrace_printer, METH_O},
{"create_managed_weakref_nogc_type",
create_managed_weakref_nogc_type, METH_NOARGS},
{"test_soft_deprecated_macros", test_soft_deprecated_macros, METH_NOARGS},
{NULL, NULL} /* sentinel */
};

View file

@ -2760,11 +2760,9 @@ array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags)
view->internal = NULL;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
view->format = (char *)self->ob_descr->formats;
#ifdef Py_UNICODE_WIDE
if (self->ob_descr->typecode == 'u') {
if (sizeof(wchar_t) >= 4 && self->ob_descr->typecode == 'u') {
view->format = "w";
}
#endif
}
self->ob_exports++;

View file

@ -78,7 +78,7 @@ get_binascii_state(PyObject *module)
/* Align to 64 bytes for L1 cache line friendliness */
static const unsigned char table_a2b_base64[] Py_ALIGNED(64) = {
static const _Py_ALIGNED_DEF(64, unsigned char) table_a2b_base64[] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
@ -110,7 +110,7 @@ static const unsigned char table_a2b_base64[] Py_ALIGNED(64) = {
*/
/* Align to 64 bytes for L1 cache line friendliness */
static const unsigned char table_b2a_base64[] Py_ALIGNED(64) =
static const _Py_ALIGNED_DEF(64, unsigned char) table_b2a_base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Encode 3 bytes into 4 base64 characters. */
@ -189,7 +189,7 @@ base64_decode_fast(const unsigned char *in, Py_ssize_t in_len,
}
static const unsigned char table_a2b_base85[] Py_ALIGNED(64) = {
static const _Py_ALIGNED_DEF(64, unsigned char) table_a2b_base85[] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,62,-1,63, 64,65,66,-1, 67,68,69,70, -1,71,-1,-1,
@ -209,7 +209,7 @@ static const unsigned char table_a2b_base85[] Py_ALIGNED(64) = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
};
static const unsigned char table_a2b_base85_a85[] Py_ALIGNED(64) = {
static const _Py_ALIGNED_DEF(64, unsigned char) table_a2b_base85_a85[] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
@ -229,11 +229,11 @@ static const unsigned char table_a2b_base85_a85[] Py_ALIGNED(64) = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
};
static const unsigned char table_b2a_base85[] Py_ALIGNED(64) =
static const _Py_ALIGNED_DEF(64, unsigned char) table_b2a_base85[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
static const unsigned char table_b2a_base85_a85[] Py_ALIGNED(64) =
static const _Py_ALIGNED_DEF(64, unsigned char) table_b2a_base85_a85[] =
"!\"#$%&\'()*+,-./0123456789:;<=>?@" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu";
@ -245,7 +245,7 @@ static const unsigned char table_b2a_base85_a85[] Py_ALIGNED(64) =
#define BASE85_A85_Y 0x20202020
static const unsigned char table_a2b_base32[] Py_ALIGNED(64) = {
static const _Py_ALIGNED_DEF(64, unsigned char) table_a2b_base32[] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
@ -265,7 +265,7 @@ static const unsigned char table_a2b_base32[] Py_ALIGNED(64) = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
};
static const unsigned char table_b2a_base32[] Py_ALIGNED(64) =
static const _Py_ALIGNED_DEF(64, unsigned char) table_b2a_base32[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
#define BASE32_PAD '='

View file

@ -6262,7 +6262,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
gethostbyaddr_r is 8-byte aligned, which at least llvm-gcc
does not ensure. The attribute below instructs the compiler
to maintain this alignment. */
char buf[16384] Py_ALIGNED(8);
_Py_ALIGNED_DEF(8, char) buf[16384];
int buf_len = (sizeof buf) - 1;
int errnop;
#endif

View file

@ -5580,15 +5580,14 @@ _Py_EncodeUTF8Ex(const wchar_t *text, char **str, size_t *error_pos,
Py_ssize_t ch_pos = i;
Py_UCS4 ch = text[i];
i++;
#if Py_UNICODE_SIZE == 2
if (Py_UNICODE_IS_HIGH_SURROGATE(ch)
if (sizeof(wchar_t) == 2
&& Py_UNICODE_IS_HIGH_SURROGATE(ch)
&& i < len
&& Py_UNICODE_IS_LOW_SURROGATE(text[i]))
{
ch = Py_UNICODE_JOIN_SURROGATES(ch, text[i]);
i++;
}
#endif
if (ch < 0x80) {
/* Encode ASCII */

View file

@ -28,19 +28,7 @@ PyExpat_CAPSULE_NAME
# pyport.h
PYLONG_BITS_IN_DIGIT
PY_DWORD_MAX
PY_FORMAT_SIZE_T
PY_INT32_T
PY_INT64_T
PY_LLONG_MAX
PY_LLONG_MIN
PY_LONG_LONG
PY_SIZE_MAX
PY_UINT32_T
PY_UINT64_T
PY_ULLONG_MAX
PY_BIG_ENDIAN
# unicodeobject.h
Py_UNICODE_SIZE
# cpython/methodobject.h
PyCFunction_GET_CLASS
# cpython/compile.h