Skip to content

Commit ce1a877

Browse files
authored
pythongh-138143: Allow anonymous unions in public headers, using _Py_ANONYMOUS (pythonGH-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 `<Python.h>` - 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: capi-workgroup/decisions#74
1 parent 73fb155 commit ce1a877

File tree

3 files changed

+36
-15
lines changed

3 files changed

+36
-15
lines changed

Include/Python.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@
6060
# endif
6161
#endif // Py_GIL_DISABLED
6262

63+
#ifdef _MSC_VER
64+
// Ignore MSC warning C4201: "nonstandard extension used: nameless
65+
// struct/union". (Only generated for C standard versions less than C11, which
66+
// we don't *officially* support.)
67+
__pragma(warning(push))
68+
__pragma(warning(disable: 4201))
69+
#endif
70+
71+
6372
// Include Python header files
6473
#include "pyport.h"
6574
#include "pymacro.h"
@@ -139,4 +148,8 @@
139148
#include "cpython/pyfpe.h"
140149
#include "cpython/tracemalloc.h"
141150

151+
#ifdef _MSC_VER
152+
__pragma(warning(pop)) // warning(disable: 4201)
153+
#endif
154+
142155
#endif /* !Py_PYTHON_H */

Include/object.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,7 @@ whose size is determined when the object is allocated.
123123
/* PyObject is opaque */
124124
#elif !defined(Py_GIL_DISABLED)
125125
struct _object {
126-
#if (defined(__GNUC__) || defined(__clang__)) \
127-
&& !(defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L)
128-
// On C99 and older, anonymous union is a GCC and clang extension
129-
__extension__
130-
#endif
131-
#ifdef _MSC_VER
132-
// Ignore MSC warning C4201: "nonstandard extension used:
133-
// nameless struct/union"
134-
__pragma(warning(push))
135-
__pragma(warning(disable: 4201))
136-
#endif
137-
union {
126+
_Py_ANONYMOUS union {
138127
#if SIZEOF_VOID_P > 4
139128
PY_INT64_T ob_refcnt_full; /* This field is needed for efficient initialization with Clang on ARM */
140129
struct {
@@ -153,9 +142,6 @@ struct _object {
153142
#endif
154143
_Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, char) _aligner;
155144
};
156-
#ifdef _MSC_VER
157-
__pragma(warning(pop))
158-
#endif
159145

160146
PyTypeObject *ob_type;
161147
};

Include/pymacro.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,28 @@
8686
# endif
8787
#endif
8888

89+
90+
// _Py_ANONYMOUS: modifier for declaring an anonymous union.
91+
// Usage: _Py_ANONYMOUS union { ... };
92+
// Standards/compiler support:
93+
// - C++ allows anonymous unions, but not structs
94+
// - C11 and above allows anonymous unions and structs
95+
// - MSVC has warning(disable: 4201) "nonstandard extension used : nameless
96+
// struct/union". This is specific enough that we disable it for all of
97+
// Python.h.
98+
// - GCC & clang needs __extension__ before C11
99+
// To allow unsupported platforms which need other spellings, we use a
100+
// predefined value of _Py_ANONYMOUS if it exists.
101+
#ifndef _Py_ANONYMOUS
102+
# if (defined(__GNUC__) || defined(__clang__)) \
103+
&& !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
104+
# define _Py_ANONYMOUS __extension__
105+
# else
106+
# define _Py_ANONYMOUS
107+
# endif
108+
#endif
109+
110+
89111
/* Minimum value between x and y */
90112
#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x))
91113

0 commit comments

Comments
 (0)