diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index cd7e87f845..64e371db4c 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -334,6 +334,7 @@ inline void enable_try_inc_ref(PyObject *obj) { #endif inline bool register_instance_impl(void *ptr, instance *self) { + assert(ptr); #ifdef Py_GIL_DISABLED enable_try_inc_ref(reinterpret_cast(self)); #endif @@ -341,6 +342,7 @@ inline bool register_instance_impl(void *ptr, instance *self) { return true; // unused, but gives the same signature as the deregister func } inline bool deregister_instance_impl(void *ptr, instance *self) { + assert(ptr); return with_instance_map(ptr, [&](instance_map &instances) { auto range = instances.equal_range(ptr); for (auto it = range.first; it != range.second; ++it) { diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 23d9407350..a95cb1ab64 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -657,9 +657,8 @@ handle smart_holder_from_shared_ptr(const std::shared_ptr &src, return none().release(); } - auto src_raw_ptr = src.get(); + void *src_raw_void_ptr = const_cast(st.first); assert(st.second != nullptr); - void *src_raw_void_ptr = static_cast(src_raw_ptr); const detail::type_info *tinfo = st.second; if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { // PYBIND11:REMINDER: MISSING: Enforcement of consistency with existing smart_holder. @@ -673,8 +672,7 @@ handle smart_holder_from_shared_ptr(const std::shared_ptr &src, void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); valueptr = src_raw_void_ptr; - auto smhldr - = smart_holder::from_shared_ptr(std::shared_ptr(src, const_cast(st.first))); + auto smhldr = smart_holder::from_shared_ptr(std::shared_ptr(src, src_raw_void_ptr)); tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); if (policy == return_value_policy::reference_internal) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 34b22a57ae..6ec7de51cd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -171,6 +171,7 @@ set(PYBIND11_TEST_FILES test_scoped_critical_section test_sequences_and_iterators test_smart_ptr + test_animal_cat_tiger test_stl test_stl_binders test_tagbased_polymorphic diff --git a/tests/test_animal_cat_tiger.cpp b/tests/test_animal_cat_tiger.cpp new file mode 100644 index 0000000000..be3a4d003b --- /dev/null +++ b/tests/test_animal_cat_tiger.cpp @@ -0,0 +1,71 @@ +#include "pybind11_tests.h" + +#include + +namespace pybind11_tests { +namespace class_animal { + +template // Using int as a trick to easily generate a series of types. +struct Multi { + + class Animal { + public: + Animal() = default; + Animal(const Animal &) = default; + Animal &operator=(const Animal &) = default; + virtual std::shared_ptr clone() const = 0; + virtual ~Animal() = default; + }; + + class Cat : virtual public Animal { + public: + Cat() = default; + Cat(const Cat &) = default; + Cat &operator=(const Cat &) = default; + ~Cat() override = default; + }; + + class Tiger : virtual public Cat { + public: + Tiger() = default; + Tiger(const Tiger &) = default; + Tiger &operator=(const Tiger &) = default; + ~Tiger() override = default; + std::shared_ptr clone() const override { return std::make_shared(*this); } + }; +}; + +namespace py = pybind11; + +void bind_using_shared_ptr(py::module_ &m) { + using M = Multi<0>; + + py::class_>(m, "AnimalSP"); + + py::class_>(m, "CatSP"); + + py::class_>( + m, "TigerSP", py::multiple_inheritance()) + .def(py::init<>()) + .def("clone", &M::Tiger::clone); +} + +void bind_using_smart_holder(py::module_ &m) { + using M = Multi<1>; + + py::class_(m, "AnimalSH"); + + py::class_(m, "CatSH"); + + py::class_(m, "TigerSH", py::multiple_inheritance()) + .def(py::init<>()) + .def("clone", &M::Tiger::clone); +} + +TEST_SUBMODULE(class_animal, m) { + bind_using_shared_ptr(m); + bind_using_smart_holder(m); +} + +} // namespace class_animal +} // namespace pybind11_tests diff --git a/tests/test_animal_cat_tiger.py b/tests/test_animal_cat_tiger.py new file mode 100644 index 0000000000..a377025676 --- /dev/null +++ b/tests/test_animal_cat_tiger.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +import pytest + +from pybind11_tests import class_animal as m + + +@pytest.mark.parametrize("tiger_type", [m.TigerSP, m.TigerSH]) +def test_clone(tiger_type): + tiger = tiger_type() + cloned = tiger.clone() + assert isinstance(cloned, tiger_type)