Skip to content

Commit 04557ca

Browse files
committed
Transfer PR pybind#4329 from master to smart_holder branch, STEP 1.
The patch .rej below are resolved, but THIS STATE DOES NOT BUILD: ``` clang++ -o pybind11/tests/test_constants_and_functions.os -c -std=c++17 -fPIC -fvisibility=hidden -O0 -g -Wall -Wextra -Wconversion -Wcast-qual -Wdeprecated -Wundef -Wnon-virtual-dtor -Wunused-result -Werror -isystem /usr/include/python3.10 -isystem /usr/include/eigen3 -DPYBIND11_STRICT_ASSERTS_CLASS_HOLDER_VS_TYPE_CASTER_MIX -DPYBIND11_ENABLE_TYPE_CASTER_ODR_GUARD_IF_AVAILABLE -DPYBIND11_TEST_BOOST -Ipybind11/include -I/usr/local/google/home/rwgk/forked/pybind11/include -I/usr/local/google/home/rwgk/clone/pybind11/include /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp In file included from /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp:11: In file included from /usr/local/google/home/rwgk/forked/pybind11/tests/pybind11_tests.h:3: In file included from /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/eval.h:14: /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/pybind11.h:1781:9: error: static_assert failed due to requirement '!holder_is_smart_holder == type_caster_type_is_type_caster_base_subtype' "py::class_ holder vs type_caster mismatch: missing PYBIND11_TYPE_CASTER_BASE_HOLDER(T, ...) or collision with custom py::detail::type_caster<T>?" static_assert(!holder_is_smart_holder == type_caster_type_is_type_caster_base_subtype, ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/local/google/home/rwgk/forked/pybind11/include/pybind11/pybind11.h:2460:11: note: in instantiation of function template specialization 'pybind11::class_<MyEnum>::class_<>' requested here : class_<Type>(scope, name, extra...), m_base(*this, scope) { ^ /usr/local/google/home/rwgk/forked/pybind11/tests/test_constants_and_functions.cpp:106:5: note: in instantiation of function template specialization 'pybind11::enum_<MyEnum>::enum_<>' requested here py::enum_<MyEnum>(m, "MyEnum") ^ 1 error generated. ``` ________ ``` rwgk.c.googlers.com:~/forked/pybind11 $ patch -p 1 < ~/native_enum_git_diff_master_2022-11-19+131942.patch patching file .github/workflows/python312.yml patching file CMakeLists.txt Hunk #1 FAILED at 111. Hunk #2 succeeded at 138 (offset 5 lines). 1 out of 2 hunks FAILED -- saving rejects to file CMakeLists.txt.rej patching file include/pybind11/cast.h Hunk #1 FAILED at 12. Hunk #2 succeeded at 78 (offset 30 lines). Hunk #3 succeeded at 1173 (offset 41 lines). 1 out of 3 hunks FAILED -- saving rejects to file include/pybind11/cast.h.rej patching file include/pybind11/detail/abi_platform_id.h patching file include/pybind11/detail/cross_extension_shared_state.h patching file include/pybind11/detail/internals.h Hunk #1 FAILED at 16. Hunk #2 succeeded at 109 (offset 1 line). Hunk #3 FAILED at 203. Hunk #4 succeeded at 398 (offset 11 lines). Hunk #5 succeeded at 457 (offset 11 lines). 2 out of 5 hunks FAILED -- saving rejects to file include/pybind11/detail/internals.h.rej patching file include/pybind11/detail/native_enum_data.h patching file include/pybind11/detail/type_map.h patching file include/pybind11/embed.h patching file include/pybind11/native_enum.h patching file include/pybind11/pybind11.h Hunk #1 FAILED at 12. Hunk #2 succeeded at 1269 (offset 1 line). Hunk #3 succeeded at 2457 (offset 255 lines). 1 out of 3 hunks FAILED -- saving rejects to file include/pybind11/pybind11.h.rej patching file include/pybind11/pytypes.h patching file tests/CMakeLists.txt Hunk #1 succeeded at 160 (offset 18 lines). patching file tests/conftest.py patching file tests/extra_python_package/test_files.py Hunk #2 FAILED at 47. 1 out of 2 hunks FAILED -- saving rejects to file tests/extra_python_package/test_files.py.rej patching file tests/test_embed/test_interpreter.cpp patching file tests/test_enum.cpp patching file tests/test_enum.py patching file tests/test_native_enum.cpp patching file tests/test_native_enum.py ```
1 parent d095a9b commit 04557ca

20 files changed

+1207
-166
lines changed

.github/workflows/python312.yml

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
name: Python312
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
7+
concurrency:
8+
group: python312-${{ github.ref }}
9+
cancel-in-progress: false
10+
11+
env:
12+
PYTEST_TIMEOUT: 300
13+
14+
jobs:
15+
standard:
16+
name: "🐍 3.12 latest • ubuntu-latest • x64"
17+
runs-on: ubuntu-latest
18+
# if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
19+
20+
steps:
21+
- name: Show env
22+
run: env
23+
24+
- uses: actions/checkout@v3
25+
26+
- name: Setup Python 3.12
27+
uses: actions/setup-python@v4
28+
with:
29+
python-version: "3.12-dev"
30+
31+
- name: Setup Boost
32+
run: sudo apt-get install libboost-dev
33+
34+
- name: Update CMake
35+
uses: jwlawson/[email protected]
36+
37+
- name: Run pip installs
38+
run: |
39+
python -m pip install --upgrade pip
40+
python -m pip install --prefer-binary -r tests/requirements.txt
41+
python -m pip install --prefer-binary numpy
42+
# python -m pip install --prefer-binary scipy
43+
44+
- name: Show platform info
45+
run: python -m platform
46+
47+
- name: Show CMake version
48+
run: cmake --version
49+
50+
# FIRST BUILD
51+
- name: Configure C++11
52+
run: >
53+
cmake -S . -B build11
54+
-DCMAKE_VERBOSE_MAKEFILE=ON
55+
-DPYBIND11_WERROR=ON
56+
-DDOWNLOAD_CATCH=ON
57+
-DDOWNLOAD_EIGEN=ON
58+
-DCMAKE_CXX_STANDARD=11
59+
-DCMAKE_BUILD_TYPE=Debug
60+
61+
- name: Build C++11
62+
run: cmake --build build11 -j 2
63+
64+
- name: Python tests C++11
65+
run: cmake --build build11 --target pytest -j 2
66+
67+
- name: C++ tests C++11
68+
run: cmake --build build11 --target cpptest -j 2
69+
70+
- name: Interface test C++11
71+
run: cmake --build build11 --target test_cmake_build
72+
73+
- name: Clean directory
74+
run: git clean -fdx
75+
76+
# SECOND BUILD
77+
- name: Configure C++17
78+
run: >
79+
cmake -S . -B build17
80+
-DCMAKE_VERBOSE_MAKEFILE=ON
81+
-DPYBIND11_WERROR=ON
82+
-DDOWNLOAD_CATCH=ON
83+
-DDOWNLOAD_EIGEN=ON
84+
-DCMAKE_CXX_STANDARD=17
85+
-DCMAKE_BUILD_TYPE=Debug
86+
87+
- name: Build C++17
88+
run: cmake --build build17 -j 2
89+
90+
- name: Python tests C++17
91+
run: cmake --build build17 --target pytest
92+
93+
- name: C++ tests C++17
94+
run: cmake --build build17 --target cpptest
95+
96+
- name: Interface test C++17
97+
run: cmake --build build17 --target test_cmake_build
98+
99+
- name: Clean directory
100+
run: git clean -fdx
101+
102+
# THIRD BUILD
103+
- name: Configure C++17 max DPYBIND11_INTERNALS_VERSION
104+
run: >
105+
cmake -S . -B build17max
106+
-DCMAKE_VERBOSE_MAKEFILE=ON
107+
-DPYBIND11_WERROR=ON
108+
-DDOWNLOAD_CATCH=ON
109+
-DDOWNLOAD_EIGEN=ON
110+
-DCMAKE_CXX_STANDARD=17
111+
-DCMAKE_BUILD_TYPE=Debug
112+
-DPYBIND11_INTERNALS_VERSION=10000000
113+
114+
- name: Build C++17 max DPYBIND11_INTERNALS_VERSION
115+
run: cmake --build build17max -j 2
116+
117+
- name: Python tests C++17 max DPYBIND11_INTERNALS_VERSION
118+
run: cmake --build build17max --target pytest
119+
120+
- name: C++ tests C++17 max DPYBIND11_INTERNALS_VERSION
121+
run: cmake --build build17max --target cpptest
122+
123+
- name: Interface test C++17 max DPYBIND11_INTERNALS_VERSION
124+
run: cmake --build build17max --target test_cmake_build
125+
126+
# Ensure the setup_helpers module can build packages using setuptools
127+
- name: Setuptools helpers test
128+
run: pytest tests/extra_setuptools
129+
130+
- name: Clean directory
131+
run: git clean -fdx

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,21 @@ cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" OFF
111111

112112
# NB: when adding a header don't forget to also add it to setup.py
113113
set(PYBIND11_HEADERS
114+
include/pybind11/detail/abi_platform_id.h
114115
include/pybind11/detail/class.h
115116
include/pybind11/detail/common.h
117+
include/pybind11/detail/cross_extension_shared_state.h
116118
include/pybind11/detail/descr.h
117119
include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h
118120
include/pybind11/detail/init.h
119121
include/pybind11/detail/internals.h
122+
include/pybind11/detail/native_enum_data.h
120123
include/pybind11/detail/smart_holder_poc.h
121124
include/pybind11/detail/smart_holder_sfinae_hooks_only.h
122125
include/pybind11/detail/smart_holder_type_casters.h
123126
include/pybind11/detail/type_caster_base.h
124127
include/pybind11/detail/type_caster_odr_guard.h
128+
include/pybind11/detail/type_map.h
125129
include/pybind11/detail/typeid.h
126130
include/pybind11/attr.h
127131
include/pybind11/buffer_info.h
@@ -138,6 +142,7 @@ set(PYBIND11_HEADERS
138142
include/pybind11/gil.h
139143
include/pybind11/iostream.h
140144
include/pybind11/functional.h
145+
include/pybind11/native_enum.h
141146
include/pybind11/numpy.h
142147
include/pybind11/operators.h
143148
include/pybind11/pybind11.h

include/pybind11/cast.h

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "detail/common.h"
1414
#include "detail/descr.h"
15+
#include "detail/native_enum_data.h"
1516
#include "detail/smart_holder_sfinae_hooks_only.h"
1617
#include "detail/type_caster_base.h"
1718
#include "detail/type_caster_odr_guard.h"
@@ -78,6 +79,101 @@ cast_op(make_caster<T> &&caster) {
7879
template cast_op_type<typename std::add_rvalue_reference<T>::type>();
7980
}
8081

82+
template <typename EnumType>
83+
class type_caster_enum_type {
84+
private:
85+
using Underlying = typename std::underlying_type<EnumType>::type;
86+
87+
public:
88+
static constexpr auto name = const_name<EnumType>();
89+
90+
template <typename SrcType>
91+
static handle cast(SrcType &&src, return_value_policy, handle parent) {
92+
auto const &natives = cross_extension_shared_states::native_enum_type_map::get();
93+
auto found = natives.find(std::type_index(typeid(EnumType)));
94+
if (found != natives.end()) {
95+
return handle(found->second)(static_cast<Underlying>(src)).release();
96+
}
97+
return type_caster_base<EnumType>::cast(
98+
std::forward<SrcType>(src),
99+
// Fixes https://github.com/pybind/pybind11/pull/3643#issuecomment-1022987818:
100+
return_value_policy::copy,
101+
parent);
102+
}
103+
104+
bool load(handle src, bool convert) {
105+
auto const &natives = cross_extension_shared_states::native_enum_type_map::get();
106+
auto found = natives.find(std::type_index(typeid(EnumType)));
107+
if (found != natives.end()) {
108+
if (!isinstance(src, found->second)) {
109+
return false;
110+
}
111+
type_caster<Underlying> underlying_caster;
112+
if (!underlying_caster.load(src.attr("value"), convert)) {
113+
pybind11_fail("native_enum internal consistency failure.");
114+
}
115+
value = static_cast<EnumType>(static_cast<Underlying>(underlying_caster));
116+
return true;
117+
}
118+
if (!pybind11_enum_) {
119+
pybind11_enum_.reset(new type_caster_base<EnumType>());
120+
}
121+
return pybind11_enum_->load(src, convert);
122+
}
123+
124+
template <typename T>
125+
using cast_op_type = detail::cast_op_type<T>;
126+
127+
// NOLINTNEXTLINE(google-explicit-constructor)
128+
operator EnumType *() {
129+
if (!pybind11_enum_) {
130+
return &value;
131+
}
132+
return pybind11_enum_->operator EnumType *();
133+
}
134+
135+
// NOLINTNEXTLINE(google-explicit-constructor)
136+
operator EnumType &() {
137+
if (!pybind11_enum_) {
138+
return value;
139+
}
140+
return pybind11_enum_->operator EnumType &();
141+
}
142+
143+
private:
144+
std::unique_ptr<type_caster_base<EnumType>> pybind11_enum_;
145+
EnumType value;
146+
};
147+
148+
template <typename EnumType, typename SFINAE = void>
149+
struct type_caster_enum_type_enabled : std::true_type {};
150+
151+
template <typename EnumType>
152+
class type_caster<EnumType,
153+
detail::enable_if_t<std::is_enum<EnumType>::value
154+
&& type_caster_enum_type_enabled<EnumType>::value>>
155+
: public type_caster_enum_type<EnumType> {};
156+
157+
template <typename T, detail::enable_if_t<std::is_enum<T>::value, int> = 0>
158+
bool isinstance_native_enum_impl(handle obj, const std::type_info &tp) {
159+
auto const &natives = cross_extension_shared_states::native_enum_type_map::get();
160+
auto found = natives.find(tp);
161+
if (found == natives.end()) {
162+
return false;
163+
}
164+
return isinstance(obj, found->second);
165+
}
166+
167+
template <typename T, detail::enable_if_t<!std::is_enum<T>::value, int> = 0>
168+
bool isinstance_native_enum_impl(handle, const std::type_info &) {
169+
return false;
170+
}
171+
172+
template <typename T>
173+
bool isinstance_native_enum(handle obj, const std::type_info &tp) {
174+
return isinstance_native_enum_impl<intrinsic_t<T>>(obj, tp);
175+
}
176+
81177
template <typename type>
82178
class type_caster<std::reference_wrapper<type>> {
83179
private:
@@ -1078,8 +1174,19 @@ PYBIND11_NAMESPACE_END(detail)
10781174
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
10791175
T cast(const handle &handle) {
10801176
using namespace detail;
1081-
static_assert(!cast_is_temporary_value_reference<T>::value,
1177+
constexpr bool is_enum_cast
1178+
= std::is_base_of<type_caster_enum_type<intrinsic_t<T>>, make_caster<T>>::value;
1179+
static_assert(!cast_is_temporary_value_reference<T>::value || is_enum_cast,
10821180
"Unable to cast type to reference: value is local to type caster");
1181+
#ifndef NDEBUG
1182+
if (is_enum_cast) {
1183+
if (cross_extension_shared_states::native_enum_type_map::get().count(
1184+
std::type_index(typeid(intrinsic_t<T>)))
1185+
!= 0) {
1186+
pybind11_fail("Unable to cast native enum type to reference");
1187+
}
1188+
}
1189+
#endif
10831190
return cast_op<T>(load_type<T>(handle));
10841191
}
10851192

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) 2022 The pybind Community.
2+
// All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include "common.h"
8+
9+
/// On MSVC, debug and release builds are not ABI-compatible!
10+
#if defined(_MSC_VER) && defined(_DEBUG)
11+
# define PYBIND11_BUILD_TYPE "_debug"
12+
#else
13+
# define PYBIND11_BUILD_TYPE ""
14+
#endif
15+
16+
/// Let's assume that different compilers are ABI-incompatible.
17+
/// A user can manually set this string if they know their
18+
/// compiler is compatible.
19+
#ifndef PYBIND11_COMPILER_TYPE
20+
# if defined(_MSC_VER)
21+
# define PYBIND11_COMPILER_TYPE "_msvc"
22+
# elif defined(__INTEL_COMPILER)
23+
# define PYBIND11_COMPILER_TYPE "_icc"
24+
# elif defined(__clang__)
25+
# define PYBIND11_COMPILER_TYPE "_clang"
26+
# elif defined(__PGI)
27+
# define PYBIND11_COMPILER_TYPE "_pgi"
28+
# elif defined(__MINGW32__)
29+
# define PYBIND11_COMPILER_TYPE "_mingw"
30+
# elif defined(__CYGWIN__)
31+
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
32+
# elif defined(__GNUC__)
33+
# define PYBIND11_COMPILER_TYPE "_gcc"
34+
# else
35+
# define PYBIND11_COMPILER_TYPE "_unknown"
36+
# endif
37+
#endif
38+
39+
/// Also standard libs
40+
#ifndef PYBIND11_STDLIB
41+
# if defined(_LIBCPP_VERSION)
42+
# define PYBIND11_STDLIB "_libcpp"
43+
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
44+
# define PYBIND11_STDLIB "_libstdcpp"
45+
# else
46+
# define PYBIND11_STDLIB ""
47+
# endif
48+
#endif
49+
50+
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
51+
#ifndef PYBIND11_BUILD_ABI
52+
# if defined(__GXX_ABI_VERSION)
53+
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
54+
# else
55+
# define PYBIND11_BUILD_ABI ""
56+
# endif
57+
#endif
58+
59+
#ifndef PYBIND11_INTERNALS_KIND
60+
# if defined(WITH_THREAD)
61+
# define PYBIND11_INTERNALS_KIND ""
62+
# else
63+
# define PYBIND11_INTERNALS_KIND "_without_thread"
64+
# endif
65+
#endif
66+
67+
/// See README_smart_holder.rst:
68+
/// Classic / Conservative / Progressive cross-module compatibility
69+
#ifndef PYBIND11_INTERNALS_SH_DEF
70+
# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT)
71+
# define PYBIND11_INTERNALS_SH_DEF ""
72+
# else
73+
# define PYBIND11_INTERNALS_SH_DEF "_sh_def"
74+
# endif
75+
#endif
76+
77+
/* NOTE - ATTENTION - WARNING - EXTREME CAUTION
78+
Changing this will break compatibility with `PYBIND11_INTERNALS_VERSION 4`
79+
See pybind11/detail/type_map.h for more information.
80+
*/
81+
#define PYBIND11_PLATFORM_ABI_ID_V4 \
82+
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
83+
PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF
84+
85+
/// LEGACY "ABI-breaking" APPROACH, ORIGINAL COMMENT
86+
/// ------------------------------------------------
87+
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
88+
///
89+
/// Some portions of the code use an ABI that is conditional depending on this
90+
/// version number. That allows ABI-breaking changes to be "pre-implemented".
91+
/// Once the default version number is incremented, the conditional logic that
92+
/// no longer applies can be removed. Additionally, users that need not
93+
/// maintain ABI compatibility can increase the version number in order to take
94+
/// advantage of any functionality/efficiency improvements that depend on the
95+
/// newer ABI.
96+
///
97+
/// WARNING: If you choose to manually increase the ABI version, note that
98+
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
99+
/// further ABI-incompatible changes may be made before the ABI is officially
100+
/// changed to the new version.
101+
#ifndef PYBIND11_INTERNALS_VERSION
102+
# define PYBIND11_INTERNALS_VERSION 4
103+
#endif

0 commit comments

Comments
 (0)