diff --git a/clif/pybind11/function_lib.py b/clif/pybind11/function_lib.py index 6c91ce64..53a81222 100644 --- a/clif/pybind11/function_lib.py +++ b/clif/pybind11/function_lib.py @@ -216,7 +216,9 @@ def generate_return_value_policy_for_type( if param_type.lang_type == 'bytes': return 'py::return_value_policy::_return_as_bytes' elif is_callable_arg: - return 'py::return_value_policy::automatic_reference' + if param_type.lang_type == 'object': + return 'py::return_value_policy::automatic_reference' + return 'py::return_value_policy::_clif_automatic' elif reference_internal: return 'py::return_value_policy::reference_internal' else: diff --git a/clif/testing/callback.h b/clif/testing/callback.h index 16f70d89..acc34321 100644 --- a/clif/testing/callback.h +++ b/clif/testing/callback.h @@ -20,8 +20,11 @@ #include #include +#include #include +#include "clif/testing/copy_move_types_library.h" + namespace cliff { namespace testing { typedef std::function&, std::vector*)> @@ -91,4 +94,20 @@ inline int CallCallbackPassIntReturnInt(const std::function& cb, return cb(val); } +#define LOCAL_HELPER(CMLType) \ + inline std::string CallCallbackPassConstPtr##CMLType( \ + const std::function& cb) { \ + clif_testing::copy_move_types_library::CMLType obj; \ + std::string cb_trace = cb(&obj); \ + return obj.GetTrace() + "@" + cb_trace; \ + } + +LOCAL_HELPER(CopyMoveType) +LOCAL_HELPER(CopyOnlyType) +LOCAL_HELPER(MoveOnlyType) +LOCAL_HELPER(StayPutType) + +#undef LOCAL_HELPER + #endif // CLIF_TESTING_CALLBACK_H_ diff --git a/clif/testing/python/callback.clif b/clif/testing/python/callback.clif index 9b6ea3d3..51e1b300 100644 --- a/clif/testing/python/callback.clif +++ b/clif/testing/python/callback.clif @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from "clif/testing/python/copy_move_types_library_clif.h" import * + from "clif/testing/callback.h": def `FunctionNewStyleCallbackConstRef` as NewStyleCallbackConstRef( input:list, @@ -36,3 +38,10 @@ from "clif/testing/callback.h": def PyObjectCallback(cb: () -> object) -> object def CallCallbackPassIntReturnInt(cb: (val: int) -> int, val: int) -> int + + def CallCallbackPassConstPtrCopyMoveType(cb: (obj: CopyMoveType) -> str) -> str + def CallCallbackPassConstPtrCopyOnlyType(cb: (obj: CopyOnlyType) -> str) -> str + # TODO: Uncomment additional tests. + # These fail to build with PyCLIF-C-API, but only fail at runtime with PyCLIF-pybind11. + # def CallCallbackPassConstPtrMoveOnlyType(cb: (obj: MoveOnlyType) -> str) -> str + # def CallCallbackPassConstPtrStayPutType(cb: (obj: StayPutType) -> str) -> str diff --git a/clif/testing/python/callback_test.py b/clif/testing/python/callback_test.py index edc2ff07..c986511a 100644 --- a/clif/testing/python/callback_test.py +++ b/clif/testing/python/callback_test.py @@ -50,6 +50,10 @@ def RaisingCallback(): raise ValueError('raised a value error') +def ObjCopyMoveTraceCallback(obj): + return obj.trace + + class CallbackTest(parameterized.TestCase): def CallbackMethod(self, data): @@ -155,6 +159,28 @@ def Cb(val): 'ValueError: Positive value: 5', ) + @parameterized.parameters( + callback.CallCallbackPassConstPtrCopyMoveType, + callback.CallCallbackPassConstPtrCopyOnlyType, + ) + def testCallCallbackPassConstPtrCopyableType(self, call_cb): + trace = call_cb(ObjCopyMoveTraceCallback) + self.assertEqual(trace, 'DefaultCtor@DefaultCtor_CpCtor') + + @parameterized.parameters('MoveOnlyType', 'StayPutType') + def testCallCallbackPassConstPtrMoveOnlyType(self, cml_type): + call_cb_fn_name = f'CallCallbackPassConstPtr{cml_type}' + call_cb = getattr(callback, call_cb_fn_name, None) + if call_cb is None: + self.skipTest(f'Unavailable: {call_cb_fn_name}') + # TODO: Uncomment in callback.clif + expected_error = ( + 'return_value_policy = copy, but type ' + f'clif_testing::copy_move_types_library::{cml_type} is non-copyable!' + ) + with self.assertRaisesWithLiteralMatch(RuntimeError, expected_error): + call_cb(ObjCopyMoveTraceCallback) + if __name__ == '__main__': absltest.main()