diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 376a679544..9a971704e4 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1009,6 +1009,8 @@ struct return_value_policy_override< // Basic python -> C++ casting; throws if casting fails template type_caster &load_type(type_caster &conv, const handle &handle) { + static_assert(!detail::is_pyobject::value, + "Internal error: type_caster should only be used for C++ types"); if (!conv.load(handle, true)) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error("Unable to cast Python instance to C++ type (#define " @@ -1099,21 +1101,30 @@ detail::enable_if_t::value, T> move(object &&obj) { // - If both movable and copyable, check ref count: if 1, move; otherwise copy // - Otherwise (not movable), copy. template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_always::value, T> +cast(object &&object) { return move(std::move(object)); } template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_if_unreferenced::value, T> +cast(object &&object) { if (object.ref_count() > 1) { return cast(object); } return move(std::move(object)); } template -detail::enable_if_t::value, T> cast(object &&object) { +detail::enable_if_t::value && detail::move_never::value, T> +cast(object &&object) { return cast(object); } +// pytype rvalue -> pytype (calls converting constructor) +template +detail::enable_if_t::value, T> cast(object &&object) { + return T(std::move(object)); +} + template T object::cast() const & { return pybind11::cast(*this); diff --git a/tests/test_copy_move.cpp b/tests/test_copy_move.cpp index 6e1bdd8568..28c2445644 100644 --- a/tests/test_copy_move.cpp +++ b/tests/test_copy_move.cpp @@ -289,4 +289,7 @@ TEST_SUBMODULE(copy_move_policies, m) { py::return_value_policy::move); m.def( "get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move); + + // Make sure that cast from pytype rvalue to other pytype works + m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast(); }); } diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py index f2c0cdceb1..9fef089339 100644 --- a/tests/test_copy_move.py +++ b/tests/test_copy_move.py @@ -123,3 +123,10 @@ def test_move_fallback(): assert m1.value == 1 m2 = m.get_moveissue2(2) assert m2.value == 2 + + +def test_pytype_rvalue_cast(): + """Make sure that cast from pytype rvalue to other pytype works""" + + value = m.get_pytype_rvalue_castissue(1.0) + assert value == 1