-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extension type from documentation doesn't compile in C++20 mode #99202
Comments
C++20 supports designated initializers. However, it doesn't allow mixing of named and unnamed initialization. As we need to use the PyVarObject_HEAD_INIT() macro, which doesn't name the attributes it sets, we have to downgrade the compiler to C++17, so designated initializers are handled as compiler extension, which will allow the mixing that occurs here. See also: python/cpython#99202
C++20 supports designated initializers. However, it doesn't allow mixing of named and unnamed initialization. As we need to use the PyVarObject_HEAD_INIT() macro, which doesn't name the attributes it sets, we have to downgrade the compiler to C++17, so designated initializers are handled as compiler extension, which will allow the mixing that occurs here. See also: python/cpython#99202
C++20 supports designated initializers. However, it doesn't allow mixing of named and unnamed initialization. As we need to use the PyVarObject_HEAD_INIT() macro, which doesn't name the attributes it sets, we have to downgrade the compiler to C++17, so designated initializers are handled as compiler extension, which will allow the mixing that occurs here. See also: python/cpython#99202
C++20 supports designated initializers. However, it doesn't allow mixing of named and unnamed initialization. As we need to use the PyVarObject_HEAD_INIT() macro, which doesn't name the attributes it sets, we have to downgrade the compiler to C++17, so designated initializers are handled as compiler extension, which will allow the mixing that occurs here. See also: python/cpython#99202
One option would be to use designed initializers in HEAD macros (ex: PyObject_HEAD) when using C++ 20 or newer. I added // Static inline functions should use _Py_NULL rather than using directly NULL
// to prevent C++ compiler warnings. On C++11 and newer, _Py_NULL is defined as
// nullptr.
#if defined(__cplusplus) && __cplusplus >= 201103
# define _Py_NULL nullptr
#else
# define _Py_NULL NULL
#endif
// Macro to use C++ static_cast<> in the Python C API.
#ifdef __cplusplus
# define _Py_STATIC_CAST(type, expr) static_cast<type>(expr)
#else
# define _Py_STATIC_CAST(type, expr) ((type)(expr))
#endif
#define _Py_CAST(type, expr) ((type)(expr)) |
That would mean projects that list all the fields would now break in C++20. |
We should be able to use the preprocessor to provide |
I really hate defining a structure without naming members. If we have to chose, I propose to move away from that. Nobody likes that, and the majority of code creating structures in Python... just name the members with comments (which are hard to write and maintain because of indentation, trying to align text, etc.). "Random" example:
It's made of 3 parts:
I would prefer to convert all PyTypeObject definition in Python to only use designed initializers. Static types converted to heap types use designed initializers and it's so way readable, since most fields use the default value (0/NULL)! So it's way shorter. By the way, it's a little bit surprising for me that |
FYI I got it as a warning with older C++ versions. I tried to fix them by using designed initializers in HEAD macros, but I get issues and I gave up. My attempt was to build C++ extensions in "strict mode" (turn on all warnings, treat warnings as errors) in test_cppext. |
@vstinner, I agree that using designated initializers consistently in the CPython code base would be a great improvement in readability. I would be in favour of such a change. |
Also seeing on openSUSE/SLE 15.4 gcc-12.2.1
|
The problem with this is that it's backward incompatible with code which is currently valid in C++20! Code using designed initializers like
PR #102518 is backward compatible. |
Well, there are two parts. Part 1: outer level, code using INIT macros:
Part 2: INIT macro declares
PR #102518 fix part 1, it leaves the part 2 unchanged (unfixed?). The current status is that test_cppext builds a C++ extension for C++03 and C++11. The test fails if the compiler emits warnings, but doesn't pass any specific compiler flags. The pythoncapi-compat project has a similar test with stricter compiler flags:
So far, I failed to use |
Bug report
C++20 added support for designated initializers and fails to compile if you mix named and unnamed initializers.
For demonstration I'll use the example from the documentation section "Defining Extension Types: Tutorial" with
.tp_doc
removed fromCustomType
so it builds on Python 3.10.When building with C++ compiler in C++20 mode using
g++ $(python3-config --cflags) -std=c++20 -Wall -Wextra -Wno-missing-field-initializers -c pymod.cc
it fails with the following message:
The problem is the macros that produce non-designated initializers here.
Additional information
The following compiles work flawlessly:
GNU C compiler:
gcc $(python3-config --cflags) -Wall -Wextra -Wno-missing-field-initializers -c pymod.cc
GNU C++ compiler with no C++ version specified:
g++ $(python3-config --cflags) -Wall -Wextra -Wno-missing-field-initializers -c pymod.cc
GNU C++ Compiler in C++17 mode:
g++ $(python3-config --cflags) -std=c++17 -Wall -Wextra -Wno-missing-field-initializers -c pymod.cc
Your environment
python-devel
,gcc
andgcc-c++
installedThe issue leading up to this was our build failing in C++20 mode on at least RHEL 7/8/9, Fedora 34 to 37, SLES 12, SLES 15, Debian 10/11, Ubuntu 16 to 22.
So I guess building with pretty much every GNU C++ compiler will break if you turn on C++20.
pymod.cc:
Linked PRs
The text was updated successfully, but these errors were encountered: