diff --git a/example/issues.cpp b/example/issues.cpp index 1a4fc31a0..c9f9e8b07 100644 --- a/example/issues.cpp +++ b/example/issues.cpp @@ -9,7 +9,25 @@ #include "example.h" +struct Base { + virtual void dispatch(void) const = 0; +}; +struct DispatchIssue : Base { + virtual void dispatch(void) const { + PYBIND11_OVERLOAD_PURE(void, Base, dispatch); + } +}; + +void dispatch_issue_go(const Base * b) { b->dispatch(); } + +PYBIND11_PLUGIN(mytest) +{ + pybind11::module m("mytest", "A test"); + + + return m.ptr(); +} void init_issues(py::module &m) { py::module m2 = m.def_submodule("issues"); @@ -18,4 +36,12 @@ void init_issues(py::module &m) { // #150: char bindings broken m2.def("print_char", [](char c) { std::cout << c << std::endl; }); + + // #159: virtual function dispatch has problems with similar-named functions + pybind11::class_ base(m2, "DispatchIssue"); + base.alias() + .def(pybind11::init<>()) + .def("dispatch", &Base::dispatch); + + m2.def("dispatch_issue_go", &dispatch_issue_go); } diff --git a/example/issues.py b/example/issues.py index 8628439e7..84752b0d3 100644 --- a/example/issues.py +++ b/example/issues.py @@ -4,6 +4,25 @@ import sys sys.path.append('.') from example.issues import print_cchar, print_char +from example.issues import DispatchIssue, dispatch_issue_go print_cchar("const char *") print_char('c') + + +class PyClass1(DispatchIssue): + def dispatch(self): + print("Yay..") + + +class PyClass2(DispatchIssue): + def dispatch(self): + try: + super(PyClass2, self).dispatch() + except Exception as e: + print("Failed as expected: " + str(e)) + p = PyClass1() + dispatch_issue_go(p) + +b = PyClass2() +dispatch_issue_go(b) diff --git a/example/issues.ref b/example/issues.ref index 4e021217f..55cbdda1d 100644 --- a/example/issues.ref +++ b/example/issues.ref @@ -1,2 +1,4 @@ const char * c +Failed as expected: Tried to call pure virtual function "dispatch" +Yay.. diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 03ff737ca..6c51e1881 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1032,8 +1032,8 @@ inline function get_overload(const void *this_ptr, const char *name) { handle type = py_object.get_type(); auto key = std::make_pair(type.ptr(), name); - /* Cache functions that aren't overloaded in python to avoid - many costly dictionary lookups in Python */ + /* Cache functions that aren't overloaded in Python to avoid + many costly Python dictionary lookups below */ auto &cache = detail::get_internals().inactive_overload_cache; if (cache.find(key) != cache.end()) return function(); @@ -1044,10 +1044,16 @@ inline function get_overload(const void *this_ptr, const char *name) { return function(); } + /* Don't call dispatch code if invoked from overridden function */ PyFrameObject *frame = PyThreadState_Get()->frame; - pybind11::str caller = pybind11::handle(frame->f_code->co_name).str(); - if ((std::string) caller == name) - return function(); + if ((std::string) pybind11::handle(frame->f_code->co_name).str() == name && + frame->f_code->co_argcount > 0) { + PyFrame_FastToLocals(frame); + PyObject *self_caller = PyDict_GetItem( + frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); + if (self_caller == py_object.ptr()) + return function(); + } return overload; }