diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ecba736c2..9e6c3a06f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -418,7 +418,8 @@ protected: detail::function_record *chain = nullptr, *chain_start = rec; if (rec->sibling) { if (PyCFunction_Check(rec->sibling.ptr())) { - auto rec_capsule = reinterpret_borrow(PyCFunction_GET_SELF(rec->sibling.ptr())); + auto *self = PyCFunction_GET_SELF(rec->sibling.ptr()); + capsule rec_capsule = isinstance(self) ? reinterpret_borrow(self) : capsule(self); chain = (detail::function_record *) rec_capsule; /* Never append a method to an overload chain of a parent class; instead, hide the parent's overloads in this case */ diff --git a/tests/test_class.cpp b/tests/test_class.cpp index 7f4f373df..cf33b1680 100644 --- a/tests/test_class.cpp +++ b/tests/test_class.cpp @@ -66,10 +66,25 @@ TEST_SUBMODULE(class_, m) { } ~NoConstructor() { print_destroyed(this); } }; + struct NoConstructorNew { + NoConstructorNew() = default; + NoConstructorNew(const NoConstructorNew &) = default; + NoConstructorNew(NoConstructorNew &&) = default; + static NoConstructorNew *new_instance() { + auto *ptr = new NoConstructorNew(); + print_created(ptr, "via new_instance"); + return ptr; + } + ~NoConstructorNew() { print_destroyed(this); } + }; py::class_(m, "NoConstructor") .def_static("new_instance", &NoConstructor::new_instance, "Return an instance"); + py::class_(m, "NoConstructorNew") + .def(py::init([](NoConstructorNew *self) { return self; })) // Need a NOOP __init__ + .def_static("__new__", [](const py::object *) { return NoConstructorNew::new_instance(); } ); + // test_inheritance class Pet { public: diff --git a/tests/test_class.py b/tests/test_class.py index 85d453199..caafe2068 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -25,6 +25,14 @@ def test_instance(msg): assert cstats.alive() == 0 +def test_instance_new(msg): + instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__) + cstats = ConstructorStats.get(m.NoConstructorNew) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + def test_type(): assert m.check_type(1) == m.DerivedClass1 with pytest.raises(RuntimeError) as execinfo: