Skip to content

Commit 43df8a4

Browse files
wangxf123456rwgk
andauthored
Extend return_value_policy_pack support to py::cast() and trampolines (google#30015)
* Follow up of return_value_policy_pack * Add cast_tuple_str_bytes tests. * Systematically ensure PYBIND11_TYPE_CASTER_RVPP is used in stl.h * PYBIND11_WARNING_DISABLE_GCC("-Wfree-nonheap-object") * Move PYBIND11_WARNING_DISABLE_GCC("-Wfree-nonheap-object") to test_return_value_policy_pack.cpp * Use `static auto *o = new ...` to escape the CUDA and MINGW compiler warnings. * Very minor enhancement: Avoid need for lambda `[=]` by using `static constexpr` for `return_value_policy` shortcuts. * Add comprehensive tests for PYBIND11_OVERRIDE_PURE_NAME_RVPP, PYBIND11_OVERRIDE_NAME_RVPP * Remove redundant `virtual` Resolves clang-tidy errors: `'virtual' is redundant since the function is already declared 'override'` * Move PYBIND11_OVERRIDE_.*NAME_RVPP macros up to be close to the non-RVPP versions (no other changes). * Alternative PYBIND11_OVERRIDE_.*NAME_RVPP implementations that do not rely on __VA_OPT__ __VA_OPT__ is a C++20 feature that is supported only by some pre-C++20 compilers but not all. The dangling commas (/* no arguments */) in the PYBIND11_OVERRIDE_.*NAME_RVPP invocations need to be removed. * Explict VirtualBase copy ctor for compatibility with clang 3.6, 3.7, 3.9 * Work around non-standard MSVC preprocessor behavior (all MSVC versions, even the newest). * Fix g++ 12.2.0 C++11 failure unrelated to the rvpp work, noticed in passing while testing locally. * Generalize PYBIND11_OVERRIDE_IMPL so that it can be reused for the new PYBIND11_OVERRIDE.*_NAME_RVPP macros. * Introduce PYBIND11_OVERRIDE_PURE_NAME_IMPL for reuse from PYBIND11_OVERRIDE_PURE_NAME, PYBIND11_OVERRIDE_PURE_NAME_RVPP --------- Co-authored-by: Ralf W. Grosse-Kunstleve <rwgk@google.com>
1 parent ca53626 commit 43df8a4

File tree

6 files changed

+322
-32
lines changed

6 files changed

+322
-32
lines changed

include/pybind11/cast.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,20 +1234,23 @@ T cast(const handle &handle) {
12341234
// C++ type -> py::object
12351235
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
12361236
object cast(T &&value,
1237-
return_value_policy policy = return_value_policy::automatic_reference,
1237+
const return_value_policy_pack &rvpp = return_value_policy::automatic_reference,
12381238
handle parent = handle()) {
12391239
using no_ref_T = typename std::remove_reference<T>::type;
1240-
if (policy == return_value_policy::automatic) {
1241-
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership
1242-
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
1243-
: return_value_policy::move;
1244-
} else if (policy == return_value_policy::automatic_reference) {
1245-
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::reference
1246-
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
1247-
: return_value_policy::move;
1240+
return_value_policy_pack rvpp_local = rvpp;
1241+
if (rvpp.policy == return_value_policy::automatic) {
1242+
auto policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership
1243+
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
1244+
: return_value_policy::move;
1245+
rvpp_local = rvpp_local.override_policy(policy);
1246+
} else if (rvpp.policy == return_value_policy::automatic_reference) {
1247+
auto policy = std::is_pointer<no_ref_T>::value ? return_value_policy::reference
1248+
: std::is_lvalue_reference<T>::value ? return_value_policy::copy
1249+
: return_value_policy::move;
1250+
rvpp_local = rvpp_local.override_policy(policy);
12481251
}
12491252
return reinterpret_steal<object>(
1250-
detail::make_caster<T>::cast(std::forward<T>(value), policy, parent));
1253+
detail::make_caster<T>::cast(std::forward<T>(value), rvpp_local, parent));
12511254
}
12521255

12531256
template <typename T>

include/pybind11/pybind11.h

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,13 +3053,13 @@ function get_override(const T *this_ptr, const char *name) {
30533053
return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();
30543054
}
30553055

3056-
#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \
3056+
#define PYBIND11_OVERRIDE_IMPL(override_call, ret_type, cname, name, ...) \
30573057
do { \
30583058
pybind11::gil_scoped_acquire gil; \
30593059
pybind11::function override \
30603060
= pybind11::get_override(static_cast<const cname *>(this), name); \
30613061
if (override) { \
3062-
auto o = override(__VA_ARGS__); \
3062+
auto o = override_call(__VA_ARGS__); \
30633063
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
30643064
static pybind11::detail::override_caster_t<ret_type> caster; \
30653065
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
@@ -3088,20 +3088,46 @@ function get_override(const T *this_ptr, const char *name) {
30883088
\endrst */
30893089
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
30903090
do { \
3091-
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
3091+
PYBIND11_OVERRIDE_IMPL( \
3092+
override, PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
30923093
return cname::fn(__VA_ARGS__); \
30933094
} while (false)
30943095

3096+
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
3097+
// Not using `#if defined(_MSC_VER)` here to have only one implementation to test and debug.
3098+
#define PYBIND11_PP_EXPAND(x) x
3099+
#define PYBIND11_STRIP_FIRST_ARG_IMPL(A, ...) __VA_ARGS__
3100+
#define PYBIND11_STRIP_FIRST_ARG(...) \
3101+
PYBIND11_PP_EXPAND(PYBIND11_STRIP_FIRST_ARG_IMPL(__VA_ARGS__))
3102+
3103+
#define PYBIND11_OVERRIDE_NAME_RVPP(ret_type, cname, name, fn, ...) \
3104+
do { \
3105+
PYBIND11_OVERRIDE_IMPL(override.call_with_policies, \
3106+
PYBIND11_TYPE(ret_type), \
3107+
PYBIND11_TYPE(cname), \
3108+
name, \
3109+
__VA_ARGS__); \
3110+
return cname::fn(PYBIND11_STRIP_FIRST_ARG(__VA_ARGS__)); \
3111+
} while (false)
3112+
3113+
#define PYBIND11_OVERRIDE_PURE_NAME_IMPL(override_call, ret_type, cname, name, fn, ...) \
3114+
do { \
3115+
PYBIND11_OVERRIDE_IMPL( \
3116+
override_call, PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
3117+
pybind11::pybind11_fail( \
3118+
"Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
3119+
} while (false)
3120+
30953121
/** \rst
30963122
Macro for pure virtual functions, this function is identical to
30973123
:c:macro:`PYBIND11_OVERRIDE_NAME`, except that it throws if no override can be found.
30983124
\endrst */
30993125
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
3100-
do { \
3101-
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
3102-
pybind11::pybind11_fail( \
3103-
"Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
3104-
} while (false)
3126+
PYBIND11_OVERRIDE_PURE_NAME_IMPL(override, ret_type, cname, name, fn, __VA_ARGS__)
3127+
3128+
#define PYBIND11_OVERRIDE_PURE_NAME_RVPP(ret_type, cname, name, fn, ...) \
3129+
PYBIND11_OVERRIDE_PURE_NAME_IMPL( \
3130+
override.call_with_policies, ret_type, cname, name, fn, __VA_ARGS__)
31053131

31063132
/** \rst
31073133
Macro to populate the virtual method in the trampoline class. This macro tries to look up the
@@ -3153,7 +3179,8 @@ inline function get_overload(const T *this_ptr, const char *name) {
31533179
}
31543180

31553181
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
3156-
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
3182+
PYBIND11_OVERRIDE_IMPL( \
3183+
override, PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
31573184
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
31583185
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)
31593186
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \

include/pybind11/stl.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ struct set_caster {
102102
return s.release();
103103
}
104104

105-
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
105+
PYBIND11_TYPE_CASTER_RVPP(type, const_name("Set[") + key_conv::name + const_name("]"));
106106
};
107107

108108
template <typename Type, typename Key, typename Value>
@@ -158,9 +158,9 @@ struct map_caster {
158158
return d.release();
159159
}
160160

161-
PYBIND11_TYPE_CASTER(Type,
162-
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
163-
+ const_name("]"));
161+
PYBIND11_TYPE_CASTER_RVPP(Type,
162+
const_name("Dict[") + key_conv::name + const_name(", ")
163+
+ value_conv::name + const_name("]"));
164164
};
165165

166166
template <typename Type, typename Value>

tests/test_class_sh_property_stl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
namespace test_class_sh_property_stl {
99

1010
struct Field {
11+
Field(int wrapped_int) : wrapped_int{wrapped_int} {}
1112
int wrapped_int = 100;
1213
};
1314

1415
struct FieldHolder {
16+
FieldHolder(const Field &fld) : fld{fld} {}
1517
Field fld = Field{200};
1618
};
1719

0 commit comments

Comments
 (0)