diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e301e9b083..eb1199893c 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1042,6 +1042,7 @@ struct return_value_policy_override< void>> { static return_value_policy policy(return_value_policy p) { return !std::is_lvalue_reference::value && !std::is_pointer::value + && p != return_value_policy::_clif_automatic ? return_value_policy::move : p; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 04b747d705..d958a8c5ca 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -167,6 +167,7 @@ set(PYBIND11_TEST_FILES test_operator_overloading test_pickling test_pytypes + test_return_value_policy_override test_sequences_and_iterators test_smart_ptr test_stl diff --git a/tests/test_return_value_policy_override.cpp b/tests/test_return_value_policy_override.cpp new file mode 100644 index 0000000000..130f990555 --- /dev/null +++ b/tests/test_return_value_policy_override.cpp @@ -0,0 +1,82 @@ +#include "pybind11_tests.h" + +namespace test_return_value_policy_override { + +struct some_type {}; + +} // namespace test_return_value_policy_override + +using test_return_value_policy_override::some_type; + +namespace pybind11 { +namespace detail { + +const char *return_value_policy_name(return_value_policy policy) { + switch (policy) { + case return_value_policy::automatic: + return "automatic"; + case return_value_policy::automatic_reference: + return "automatic_reference"; + case return_value_policy::take_ownership: + return "take_ownership"; + case return_value_policy::copy: + return "copy"; + case return_value_policy::move: + return "move"; + case return_value_policy::reference: + return "reference"; + case return_value_policy::reference_internal: + return "reference_internal"; + case return_value_policy::_return_as_bytes: + return "_return_as_bytes"; + case return_value_policy::_clif_automatic: + return "_clif_automatic"; + default: + return "Expected to be unreachable."; + } +}; + +template <> +struct type_caster : type_caster_base { + + static handle cast(some_type &&, return_value_policy policy, handle /*parent*/) { + return str(std::string(return_value_policy_name(policy))).release().ptr(); + } + + static handle cast(some_type *, return_value_policy policy, handle /*parent*/) { + return str(std::string(return_value_policy_name(policy))).release().ptr(); + } +}; + +} // namespace detail +} // namespace pybind11 + +TEST_SUBMODULE(return_value_policy_override, m) { + m.def("return_value_with_default_policy", []() { return some_type(); }); + m.def( + "return_value_with_policy_copy", + []() { return some_type(); }, + py::return_value_policy::copy); + m.def( + "return_value_with_policy_clif_automatic", + []() { return some_type(); }, + py::return_value_policy::_clif_automatic); + m.def("return_pointer_with_default_policy", []() { + static some_type value; + return &value; + }); + m.def( + "return_pointer_with_policy_move", + []() { + static some_type value; + return &value; + }, + py::return_value_policy::move); + m.def( + "return_pointer_with_policy_clif_automatic", + []() { + static some_type value; + return &value; + }, + py::return_value_policy::_clif_automatic); +} diff --git a/tests/test_return_value_policy_override.py b/tests/test_return_value_policy_override.py new file mode 100644 index 0000000000..36cb5bbf0b --- /dev/null +++ b/tests/test_return_value_policy_override.py @@ -0,0 +1,13 @@ +from pybind11_tests import return_value_policy_override as m + + +def test_return_value(): + assert m.return_value_with_default_policy() == "move" + assert m.return_value_with_policy_copy() == "move" + assert m.return_value_with_policy_clif_automatic() == "_clif_automatic" + + +def test_return_pointer(): + assert m.return_pointer_with_default_policy() == "automatic" + assert m.return_pointer_with_policy_move() == "move" + assert m.return_pointer_with_policy_clif_automatic() == "_clif_automatic"