diff --git a/include/pybind11/detail/smart_holder_type_casters.h b/include/pybind11/detail/smart_holder_type_casters.h index c5fe9cd0..0b30eb8a 100644 --- a/include/pybind11/detail/smart_holder_type_casters.h +++ b/include/pybind11/detail/smart_holder_type_casters.h @@ -746,7 +746,7 @@ struct smart_holder_type_caster : smart_holder_type_caster_load, static handle cast(T &&src, return_value_policy /*policy*/, handle parent) { // type_caster_base BEGIN - return cast(&src, return_value_policy::move, parent); + return cast(std::addressof(src), return_value_policy::move, parent); // type_caster_base END } diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index b2329643..7c1c309a 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -1120,7 +1120,7 @@ class type_caster_base : public type_caster_generic { } static handle cast(itype &&src, return_value_policy, handle parent) { - return cast(&src, return_value_policy::move, parent); + return cast(std::addressof(src), return_value_policy::move, parent); } // Returns a (pointer, type_info) pair taking care of necessary type lookup for a diff --git a/tests/pybind11_tests.h b/tests/pybind11_tests.h index a7c00c2f..ec1fc21f 100644 --- a/tests/pybind11_tests.h +++ b/tests/pybind11_tests.h @@ -3,6 +3,8 @@ #include #include +#include + namespace py = pybind11; using namespace pybind11::literals; @@ -52,6 +54,15 @@ union IntFloat { float f; }; +class UnusualOpRef { +public: + using NonTrivialType = std::shared_ptr; // Almost any non-trivial type will do. + NonTrivialType operator&() { return non_trivial_member; } // UNUSUAL operator. + +private: + NonTrivialType non_trivial_member; +}; + /// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast /// context. Used to test recursive casters (e.g. std::tuple, stl containers). struct RValueCaster {}; diff --git a/tests/test_class_sh_basic.cpp b/tests/test_class_sh_basic.cpp index a294f7bb..fb939518 100644 --- a/tests/test_class_sh_basic.cpp +++ b/tests/test_class_sh_basic.cpp @@ -129,12 +129,17 @@ struct SharedPtrStash { void Add(const std::shared_ptr &obj) { stash.push_back(obj); } }; +class LocalUnusualOpRef : UnusualOpRef {}; // To avoid clashing with `py::class_`. +py::object CastUnusualOpRefConstRef(const LocalUnusualOpRef &cref) { return py::cast(cref); } +py::object CastUnusualOpRefMovable(LocalUnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); } + } // namespace class_sh_basic } // namespace pybind11_tests PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::atyp) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::uconsumer) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::SharedPtrStash) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_basic::LocalUnusualOpRef) namespace pybind11_tests { namespace class_sh_basic { @@ -227,6 +232,12 @@ TEST_SUBMODULE(class_sh_basic, m) { "rtrn_uq_automatic_reference", []() { return std::unique_ptr(new atyp("rtrn_uq_automatic_reference")); }, pybind11::return_value_policy::automatic_reference); + + py::classh(m, "LocalUnusualOpRef"); + m.def("CallCastUnusualOpRefConstRef", + []() { return CastUnusualOpRefConstRef(LocalUnusualOpRef()); }); + m.def("CallCastUnusualOpRefMovable", + []() { return CastUnusualOpRefMovable(LocalUnusualOpRef()); }); } } // namespace class_sh_basic diff --git a/tests/test_class_sh_basic.py b/tests/test_class_sh_basic.py index c7ff82c8..dbb8f9b9 100644 --- a/tests/test_class_sh_basic.py +++ b/tests/test_class_sh_basic.py @@ -216,3 +216,9 @@ def test_function_signatures(doc): def test_unique_ptr_return_value_policy_automatic_reference(): assert m.get_mtxt(m.rtrn_uq_automatic_reference()) == "rtrn_uq_automatic_reference" + + +def test_unusual_op_ref(): + # Merely to test that this still exists and built successfully. + assert m.CallCastUnusualOpRefConstRef().__class__.__name__ == "LocalUnusualOpRef" + assert m.CallCastUnusualOpRefMovable().__class__.__name__ == "LocalUnusualOpRef" diff --git a/tests/test_copy_move.cpp b/tests/test_copy_move.cpp index 087b4852..1291a133 100644 --- a/tests/test_copy_move.cpp +++ b/tests/test_copy_move.cpp @@ -157,6 +157,13 @@ struct type_caster { PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(pybind11) +namespace { + +py::object CastUnusualOpRefConstRef(const UnusualOpRef &cref) { return py::cast(cref); } +py::object CastUnusualOpRefMovable(UnusualOpRef &&mvbl) { return py::cast(std::move(mvbl)); } + +} // namespace + TEST_SUBMODULE(copy_move_policies, m) { // test_lacking_copy_ctor py::class_(m, "lacking_copy_ctor") @@ -295,6 +302,11 @@ TEST_SUBMODULE(copy_move_policies, m) { // Make sure that cast from pytype rvalue to other pytype works m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast(); }); + py::class_(m, "UnusualOpRef"); + m.def("CallCastUnusualOpRefConstRef", + []() { return CastUnusualOpRefConstRef(UnusualOpRef()); }); + m.def("CallCastUnusualOpRefMovable", []() { return CastUnusualOpRefMovable(UnusualOpRef()); }); + // Mimic situation generated by PyCLIF-pybind11. // Requires `case return_value_policy::_clif_automatic` in `type_caster_base`. struct PyCastUsingClifAutomaticTestType {}; diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py index 16f7dd5e..7cac8d43 100644 --- a/tests/test_copy_move.py +++ b/tests/test_copy_move.py @@ -132,6 +132,12 @@ def test_pytype_rvalue_cast(): assert value == 1 +def test_unusual_op_ref(): + # Merely to test that this still exists and built successfully. + assert m.CallCastUnusualOpRefConstRef().__class__.__name__ == "UnusualOpRef" + assert m.CallCastUnusualOpRefMovable().__class__.__name__ == "UnusualOpRef" + + def test_py_cast_using_clif_automatic(): obj = m.py_cast_using_clif_automatic() assert obj.__class__.__name__ == "PyCastUsingClifAutomaticTestType"