Don't allow mixed static/non-static overloads

We currently fail at runtime when trying to call a method that is
overloaded with both static and non-static methods.  This is something
python won't allow: the object is either a function or an instance, and
can't be both.
This commit is contained in:
Jason Rhinelander 2017-04-16 22:31:13 -04:00
parent 90bac96321
commit d355f2fcca
3 changed files with 44 additions and 0 deletions

View File

@ -318,6 +318,15 @@ protected:
m_ptr = rec->sibling.ptr();
inc_ref();
chain_start = chain;
if (chain->is_method != rec->is_method)
pybind11_fail("overloading a method with both static and instance methods is not supported; "
#if defined(NDEBUG)
"compile in debug mode for more details"
#else
"error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " +
std::string(pybind11::str(rec->scope.attr("__name__"))) + "." + std::string(rec->name) + signature
#endif
);
while (chain->next)
chain = chain->next;
chain->next = rec;

View File

@ -59,6 +59,8 @@ public:
py::str overloaded(int, int) const { return "(int, int) const"; }
py::str overloaded(float, float) const { return "(float, float) const"; }
static py::str overloaded() { return "static"; }
int value = 0;
};
@ -206,6 +208,17 @@ test_initializer methods_and_attributes([](py::module &m) {
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
#endif
// Raise error if trying to mix static/non-static overloads on the same name:
.def_static("add_mixed_overloads1", []() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA"));
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
.def_static("overload_mixed1", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded));
})
.def_static("add_mixed_overloads2", []() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA"));
emna.def_static("overload_mixed2", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded))
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
})
.def("__str__", &ExampleMandA::toString)
.def_readwrite("value", &ExampleMandA::value);

View File

@ -148,6 +148,28 @@ def test_metaclass_override():
assert isinstance(MetaclassOverride.__dict__["readonly"], int)
def test_no_mixed_overloads():
from pybind11_tests import debug_enabled
with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads1()
assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else
"error while attempting to bind static method ExampleMandA.overload_mixed1"
"() -> str")
)
with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads2()
assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else
"error while attempting to bind instance method ExampleMandA.overload_mixed2"
"(self: pybind11_tests.ExampleMandA, arg0: int, arg1: int) -> str")
)
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
def test_property_return_value_policies(access):
from pybind11_tests import TestPropRVP