diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1c4973b748..05aef0e993 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1021,7 +1021,19 @@ struct copyable_holder_caster< return smart_holder_type_caster_support::smart_holder_from_shared_ptr( src, policy, parent, srcs.result); } - return type_caster_base::cast_holder(srcs, &src); + + auto *tinfo = srcs.result.tinfo; + if (tinfo != nullptr && tinfo->holder_enum_v == holder_enum_t::std_shared_ptr) { + return type_caster_base::cast_holder(srcs, &src); + } + + if (parent) { + return type_caster_base::cast( + srcs, return_value_policy::reference_internal, parent); + } + + throw cast_error("Unable to convert std::shared_ptr to Python when the bound type " + "does not use std::shared_ptr or py::smart_holder as its holder type"); } // This function will succeed even if the `responsible_parent` does not own the diff --git a/tests/test_class_sh_property.cpp b/tests/test_class_sh_property.cpp index 8863ad7d7b..93981ff8d0 100644 --- a/tests/test_class_sh_property.cpp +++ b/tests/test_class_sh_property.cpp @@ -43,6 +43,23 @@ struct WithConstCharPtrMember { const char *const_char_ptr_member = "ConstChar*"; }; +enum class TinyLevel { + A = 0, + B = 1, +}; + +struct HolderWithEnum { + TinyLevel level = TinyLevel::A; +}; + +struct LegacyThing { + int value = 7; +}; + +struct HolderWithLegacyMember { + LegacyThing legacy; +}; + } // namespace test_class_sh_property TEST_SUBMODULE(class_sh_property, m) { @@ -91,4 +108,18 @@ TEST_SUBMODULE(class_sh_property, m) { py::classh(m, "WithConstCharPtrMember") .def(py::init<>()) .def_readonly("const_char_ptr_member", &WithConstCharPtrMember::const_char_ptr_member); + + py::enum_(m, "TinyLevel").value("A", TinyLevel::A).value("B", TinyLevel::B); + + py::classh(m, "HolderWithEnum") + .def(py::init<>()) + .def_readwrite("level", &HolderWithEnum::level); + + py::class_(m, "LegacyThing") + .def(py::init<>()) + .def_readwrite("value", &LegacyThing::value); + + py::classh(m, "HolderWithLegacyMember") + .def(py::init<>()) + .def_readwrite("legacy", &HolderWithLegacyMember::legacy); } diff --git a/tests/test_class_sh_property.py b/tests/test_class_sh_property.py index 0250a7f78e..2644de0a56 100644 --- a/tests/test_class_sh_property.py +++ b/tests/test_class_sh_property.py @@ -164,3 +164,20 @@ def test_readonly_char6_member(): def test_readonly_const_char_ptr_member(): obj = m.WithConstCharPtrMember() assert obj.const_char_ptr_member == "ConstChar*" + + +def test_enum_member_with_smart_holder_def_readwrite(): + obj = m.HolderWithEnum() + assert obj.level == m.TinyLevel.A + for _ in range(100): + v = obj.level + assert v == m.TinyLevel.A + del v + + +def test_non_smart_holder_member_type_with_smart_holder_owner(): + obj = m.HolderWithLegacyMember() + for _ in range(1000): + v = obj.legacy + assert v.value == 7 + del v