diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 76d998a3ba..4349dffd34 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2013,10 +2013,16 @@ struct property_cpp_function_sh_raw_ptr_member { // This prevents disowning of the Python object owning the member. template struct property_cpp_function_sh_member_held_by_value { + static bool use_smart_holder_member_aliasing() { + type_info *tinfo = get_type_info(typeid(D), /*throw_if_missing=*/true); + return tinfo->holder_enum_v == holder_enum_t::smart_holder; + } + template = 0> static cpp_function readonly(PM pm, const handle &hdl) { type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); - if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + if (tinfo->holder_enum_v == holder_enum_t::smart_holder + && use_smart_holder_member_aliasing()) { return cpp_function( [pm](handle c_hdl) -> std::shared_ptr::type> { std::shared_ptr c_sp @@ -2033,7 +2039,8 @@ struct property_cpp_function_sh_member_held_by_value { template = 0> static cpp_function read(PM pm, const handle &hdl) { type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true); - if (tinfo->holder_enum_v == holder_enum_t::smart_holder) { + if (tinfo->holder_enum_v == holder_enum_t::smart_holder + && use_smart_holder_member_aliasing()) { return cpp_function( [pm](handle c_hdl) -> std::shared_ptr { std::shared_ptr c_sp 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