diff --git a/example/issues.cpp b/example/issues.cpp index bb773faef..a4622149a 100644 --- a/example/issues.cpp +++ b/example/issues.cpp @@ -21,7 +21,7 @@ void init_issues(py::module &m) { // #70 compilation issue if operator new is not public class NonConstructible { private: void *operator new(size_t bytes) throw(); }; py::class_(m, "Foo"); - m.def("getstmt", []() -> NonConstructible * { return nullptr; }, + m2.def("getstmt", []() -> NonConstructible * { return nullptr; }, py::return_value_policy::reference); #endif @@ -101,4 +101,7 @@ void init_issues(py::module &m) { list.append(py::cast(e)); return list; }); -}; + + // (no id): should not be able to pass 'None' to a reference argument + m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; }); +} diff --git a/example/issues.py b/example/issues.py index 2dfd0591a..de417696f 100644 --- a/example/issues.py +++ b/example/issues.py @@ -7,7 +7,7 @@ from example.issues import print_cchar, print_char from example.issues import DispatchIssue, dispatch_issue_go from example.issues import Placeholder, return_vec_of_reference_wrapper from example.issues import iterator_passthrough -from example.issues import ElementList, ElementA +from example.issues import ElementList, ElementA, print_element import gc print_cchar("const char *") @@ -42,3 +42,8 @@ gc.collect() for i, v in enumerate(el.get()): print("%i==%i, " % (i, v.value()), end='') print() + +try: + print_element(None) +except Exception as e: + print("Failed as expected: " + str(e)) diff --git a/example/issues.ref b/example/issues.ref index 13bafc220..2d34f4220 100644 --- a/example/issues.ref +++ b/example/issues.ref @@ -5,3 +5,6 @@ Yay.. [Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]] [3, 5, 7, 9, 11, 13, 15] 0==0, 1==1, 2==2, 3==3, 4==4, 5==5, 6==6, 7==7, 8==8, 9==9, +Failed as expected: Incompatible function arguments. The following argument types are supported: + 1. (example.issues.ElementA) -> NoneType + diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index ffb489357..64e6eeea4 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -225,6 +225,8 @@ using cast_op_type = typename std::conditional::type>::type, typename std::add_lvalue_reference::type>::type>::type; +/// Thrown then trying to cast a null pointer into a reference argument +class invalid_reference_cast : public std::exception { }; /// Generic type caster for objects stored on the heap template class type_caster_base : public type_caster_generic { @@ -254,7 +256,7 @@ public: template using cast_op_type = pybind11::detail::cast_op_type; operator type*() { return (type *) value; } - operator type&() { return *((type *) value); } + operator type&() { if (!value) throw invalid_reference_cast(); return *((type *) value); } protected: typedef void *(*Constructor)(const void *stream); diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ea67f7e39..264646c4c 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -409,8 +409,13 @@ protected: } } } - if (kwargs_consumed == nkwargs) - result = it->impl(it, args_, parent); + + try { + if (kwargs_consumed == nkwargs) + result = it->impl(it, args_, parent); + } catch (detail::invalid_reference_cast &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) break;