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.
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index cdf5f1a..c1bc673 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -318,6 +318,15 @@
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;
diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp
index 8ce25b6..e11bdf2 100644
--- a/tests/test_methods_and_attributes.cpp
+++ b/tests/test_methods_and_attributes.cpp
@@ -59,6 +59,8 @@
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 @@
.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);
diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py
index 18bf8d9..0eaef9c 100644
--- a/tests/test_methods_and_attributes.py
+++ b/tests/test_methods_and_attributes.py
@@ -148,6 +148,28 @@
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