Skip to content

Commit 1dc46e8

Browse files
[cppyy] Fix type conversion for polymorphic classes (#19374)
1 parent 2e90627 commit 1dc46e8

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

bindings/pyroot/cppyy/CPyCppyy/src/Converters.cxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,10 +2192,9 @@ template <bool ISCONST>
21922192
PyObject* CPyCppyy::InstancePtrConverter<ISCONST>::FromMemory(void* address)
21932193
{
21942194
// construct python object from C++ instance read at <address>
2195-
Cppyy::TCppScope_t actual_class = Cppyy::GetActualClass(fClass, *(void**)address);
21962195
if (ISCONST)
2197-
return BindCppObject(*(void**)address, actual_class); // by pointer value
2198-
return BindCppObject(address, actual_class, CPPInstance::kIsReference); // modifiable
2196+
return BindCppObject(*(void**)address, fClass); // by pointer value
2197+
return BindCppObject(address, fClass, CPPInstance::kIsReference); // modifiable
21992198
}
22002199

22012200
//----------------------------------------------------------------------------

bindings/pyroot/cppyy/CPyCppyy/src/ProxyWrappers.cxx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -927,19 +927,24 @@ PyObject* CPyCppyy::BindCppObject(Cppyy::TCppObject_t address,
927927
// successful, no down-casting is attempted?
928928
// TODO: optimize for final classes
929929
unsigned new_flags = flags;
930-
if (!isRef && (gPinnedTypes.empty() || gPinnedTypes.find(klass) == gPinnedTypes.end())) {
931-
Cppyy::TCppType_t clActual = Cppyy::GetActualClass(klass, address);
932-
933-
if (clActual) {
934-
if (clActual != klass) {
935-
intptr_t offset = Cppyy::GetBaseOffset(
936-
clActual, klass, address, -1 /* down-cast */, true /* report errors */);
937-
if (offset != -1) { // may fail if clActual not fully defined
938-
address = (void*)((intptr_t)address + offset);
939-
klass = clActual;
930+
if (gPinnedTypes.empty() || gPinnedTypes.find(klass) == gPinnedTypes.end()) {
931+
if (!isRef) {
932+
Cppyy::TCppType_t clActual = Cppyy::GetActualClass(klass, address);
933+
934+
if (clActual) {
935+
if (clActual != klass) {
936+
intptr_t offset = Cppyy::GetBaseOffset(
937+
clActual, klass, address, -1 /* down-cast */, true /* report errors */);
938+
if (offset != -1) { // may fail if clActual not fully defined
939+
address = (void*)((intptr_t)address + offset);
940+
klass = clActual;
941+
}
940942
}
943+
new_flags |= CPPInstance::kIsActual;
941944
}
942-
new_flags |= CPPInstance::kIsActual;
945+
} else {
946+
Cppyy::TCppType_t clActual = Cppyy::GetActualClass(klass, *(void**)address);
947+
klass = clActual;
943948
}
944949
}
945950

bindings/pyroot/cppyy/cppyy/test/test_datatypes.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,41 @@ def test51_polymorphic_types_in_maps(self):
24102410
else:
24112411
assert type(v) == gbl.PolymorphicMaps.Derived
24122412

2413+
def test52_virtual_inheritance(self):
2414+
import cppyy
2415+
from cppyy import gbl
2416+
2417+
cppyy.cppdef("""
2418+
class JetTag {
2419+
public:
2420+
JetTag() {}
2421+
virtual ~JetTag() = default;
2422+
int jt = 0;
2423+
std::string name = "NAME";
2424+
};
2425+
class BaseTag: public JetTag {
2426+
public:
2427+
int bt = 1;
2428+
} bt;
2429+
class JetFitTag: public virtual BaseTag {
2430+
public:
2431+
int jft = 2;
2432+
} jft;
2433+
class JetFit: public virtual JetFitTag {
2434+
public:
2435+
int jf = 3;
2436+
} jf;
2437+
std::vector<const JetTag*> make() {
2438+
std::vector<const JetTag*> res;
2439+
res.push_back(&bt);
2440+
res.push_back(&jft);
2441+
res.push_back(&jf);
2442+
return res;
2443+
}
2444+
""")
2445+
2446+
for i in gbl.make():
2447+
assert i.name == "NAME"
24132448

24142449
if __name__ == "__main__":
24152450
exit(pytest.main(args=['-sv', '-ra', __file__]))

0 commit comments

Comments
 (0)