From af0f82c7a318bf0af3378ec8d87af09770469337 Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Thu, 26 Jun 2025 14:09:22 +0200 Subject: [PATCH] fix: handle cases where a class is declared before defining --- lib/CppInterOp/CppInterOp.cpp | 6 ++++-- .../CppInterOp/VariableReflectionTest.cpp | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index b7fe67392..f0d7b2b38 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -1325,6 +1325,8 @@ void GetDatamembers(TCppScope_t scope, std::vector& datamembers) { if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { getSema().ForceDeclarationOfImplicitMembers(CXXRD); + if (CXXRD->hasDefinition()) + CXXRD = CXXRD->getDefinition(); llvm::SmallVector stack_begin; llvm::SmallVector stack_end; @@ -1445,7 +1447,7 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, } offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity(); } - if (BaseCXXRD && BaseCXXRD != FieldParentRecordDecl) { + if (BaseCXXRD && BaseCXXRD != FieldParentRecordDecl->getCanonicalDecl()) { // FieldDecl FD belongs to some class C, but the base class BaseCXXRD is // not C. That means BaseCXXRD derives from C. Offset needs to be // calculated for Derived class @@ -1474,7 +1476,7 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, } if (auto* RD = llvm::dyn_cast(FieldParentRecordDecl)) { // add in the offsets for the (multi level) base classes - while (BaseCXXRD != RD) { + while (BaseCXXRD != RD->getCanonicalDecl()) { CXXRecordDecl* Parent = direction.at(RD); offset += C.getASTRecordLayout(Parent).getBaseClassOffset(RD).getQuantity(); diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index b9baf6c55..f75d1839a 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -299,6 +299,25 @@ TEST(VariableReflectionTest, GetVariableOffset) { auto* VD_C_s_a = Cpp::GetNamed("s_a", Decls[4]); // C::s_a EXPECT_TRUE((bool) Cpp::GetVariableOffset(VD_C_s_a)); + + struct K { + int x; + int y; + int z; + }; + Cpp::Declare("struct K;"); + Cpp::TCppScope_t k = Cpp::GetNamed("K"); + EXPECT_TRUE(k); + + Cpp::Declare("struct K { int x; int y; int z; };"); + + datamembers.clear(); + Cpp::GetDatamembers(k, datamembers); + EXPECT_EQ(datamembers.size(), 3); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0]), offsetof(K, x)); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1]), offsetof(K, y)); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2]), offsetof(K, z)); } #define CODE \