From: Petr Viktorin Date: Tue, 26 Aug 2025 09:14:35 +0000 (+0200) Subject: gh-138143: Allow anonymous unions in public headers, using `_Py_ANONYMOUS` (GH-137283) X-Git-Tag: v3.15.0a1~590 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ce1a877a3882acf50f1162e4a823ce0abf2d8525;p=thirdparty%2FPython%2Fcpython.git gh-138143: Allow anonymous unions in public headers, using `_Py_ANONYMOUS` (GH-137283) We already use an anonymous union for PyObject. This makes the workarounds available in all public headers: - MSVC: `__pragma(warning(disable: 4201))` (with push/pop). Warning 4201 is specifically for anonymous unions, so let's disable for all of `` - GCC/clang, pedantic old C standards: define `_Py_ANONYMOUS` as `__extension__` - otherwise, define `_Py_ANONYMOUS` as nothing (Note that this is only for public headers -- CPython internals use C11, which has anonymous structs/unions.) C API WG vote: https://github.com/capi-workgroup/decisions/issues/74 --- diff --git a/Include/Python.h b/Include/Python.h index b6ee500aada7..261b4d316bdf 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -60,6 +60,15 @@ # endif #endif // Py_GIL_DISABLED +#ifdef _MSC_VER +// Ignore MSC warning C4201: "nonstandard extension used: nameless +// struct/union". (Only generated for C standard versions less than C11, which +// we don't *officially* support.) +__pragma(warning(push)) +__pragma(warning(disable: 4201)) +#endif + + // Include Python header files #include "pyport.h" #include "pymacro.h" @@ -139,4 +148,8 @@ #include "cpython/pyfpe.h" #include "cpython/tracemalloc.h" +#ifdef _MSC_VER +__pragma(warning(pop)) // warning(disable: 4201) +#endif + #endif /* !Py_PYTHON_H */ diff --git a/Include/object.h b/Include/object.h index 8979ac7dd095..064904b733d1 100644 --- a/Include/object.h +++ b/Include/object.h @@ -123,18 +123,7 @@ whose size is determined when the object is allocated. /* PyObject is opaque */ #elif !defined(Py_GIL_DISABLED) struct _object { -#if (defined(__GNUC__) || defined(__clang__)) \ - && !(defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) - // On C99 and older, anonymous union is a GCC and clang extension - __extension__ -#endif -#ifdef _MSC_VER - // Ignore MSC warning C4201: "nonstandard extension used: - // nameless struct/union" - __pragma(warning(push)) - __pragma(warning(disable: 4201)) -#endif - union { + _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 */ struct { @@ -153,9 +142,6 @@ struct _object { #endif _Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, char) _aligner; }; -#ifdef _MSC_VER - __pragma(warning(pop)) -#endif PyTypeObject *ob_type; }; diff --git a/Include/pymacro.h b/Include/pymacro.h index b2886ddac5d1..857cdf12db9b 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -86,6 +86,28 @@ # endif #endif + +// _Py_ANONYMOUS: modifier for declaring an anonymous union. +// Usage: _Py_ANONYMOUS union { ... }; +// Standards/compiler support: +// - C++ allows anonymous unions, but not structs +// - C11 and above allows anonymous unions and structs +// - MSVC has warning(disable: 4201) "nonstandard extension used : nameless +// struct/union". This is specific enough that we disable it for all of +// Python.h. +// - GCC & clang needs __extension__ before C11 +// To allow unsupported platforms which need other spellings, we use a +// predefined value of _Py_ANONYMOUS if it exists. +#ifndef _Py_ANONYMOUS +# if (defined(__GNUC__) || defined(__clang__)) \ + && !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) +# define _Py_ANONYMOUS __extension__ +# else +# define _Py_ANONYMOUS +# endif +#endif + + /* Minimum value between x and y */ #define Py_MIN(x, y) (((x) > (y)) ? (y) : (x))