diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 96aab8020..c91b26d79 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1128,9 +1128,31 @@ namespace Cpp { if (auto *CXXRD = llvm::dyn_cast_or_null(D)) { std::vector datamembers; - for (auto it = CXXRD->field_begin(), end = CXXRD->field_end(); it != end; - it++) { - datamembers.push_back((TCppScope_t)*it); + llvm::SmallVector stack_begin; + llvm::SmallVector stack_end; + stack_begin.push_back(CXXRD->field_begin()); + stack_end.push_back(CXXRD->field_end()); + while (!stack_begin.empty()) { + if (stack_begin.back() == stack_end.back()) { + stack_begin.pop_back(); + stack_end.pop_back(); + continue; + } + Decl* D = *(stack_begin.back()); + if (auto* FD = llvm::dyn_cast(D)) { + if (FD->isAnonymousStructOrUnion()) { + if (const auto* RT = FD->getType()->getAs()) { + if (auto* CXXRD = llvm::dyn_cast(RT->getDecl())) { + stack_begin.back()++; + stack_begin.push_back(CXXRD->field_begin()); + stack_end.push_back(CXXRD->field_end()); + continue; + } + } + } + } + datamembers.push_back((TCppScope_t)D); + stack_begin.back()++; } return datamembers; @@ -1175,9 +1197,26 @@ namespace Cpp { auto *D = (Decl *) var; auto &C = getASTContext(); - if (auto *FD = llvm::dyn_cast(D)) - return (intptr_t) C.toCharUnitsFromBits(C.getASTRecordLayout(FD->getParent()) - .getFieldOffset(FD->getFieldIndex())).getQuantity(); + if (auto* FD = llvm::dyn_cast(D)) { + const clang::RecordDecl* RD = FD->getParent(); + intptr_t offset = + C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity(); + while (RD->isAnonymousStructOrUnion()) { + const clang::RecordDecl* anon = RD; + RD = llvm::dyn_cast(anon->getParent()); + for (auto F = RD->field_begin(); F != RD->field_end(); ++F) { + const auto* RT = F->getType()->getAs(); + if (!RT) + continue; + if (anon == RT->getDecl()) { + FD = *F; + break; + } + } + offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity(); + } + return offset; + } if (auto *VD = llvm::dyn_cast(D)) { auto GD = GlobalDecl(VD); diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 00e455605..0e155f709 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -18,6 +18,12 @@ target_link_libraries(CppInterOpTests clangCppInterOp ) +if(NOT WIN32) + set_source_files_properties(VariableReflectionTest.cpp PROPERTIES COMPILE_FLAGS + "-Wno-pedantic" + ) +endif() + set_source_files_properties(InterpreterTest.cpp PROPERTIES COMPILE_DEFINITIONS "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" ) diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 2c42897dd..efb604cde 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -39,6 +39,80 @@ TEST(VariableReflectionTest, GetDatamembers) { EXPECT_EQ(datamembers1.size(), 0); } +#define CODE \ + struct Klass1 { \ + Klass1(int i) : num(1), b(i) {} \ + int num; \ + union { \ + double a; \ + int b; \ + }; \ + } const k1(5); \ + struct Klass2 { \ + Klass2(double d) : num(2), a(d) {} \ + int num; \ + struct { \ + double a; \ + int b; \ + }; \ + } const k2(2.5); \ + struct Klass3 { \ + Klass3(int i) : num(i) {} \ + int num; \ + struct { \ + double a; \ + union { \ + float b; \ + int c; \ + }; \ + }; \ + int num2; \ + } const k3(5); + +CODE + +TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) { + if (llvm::sys::RunningOnValgrind()) + GTEST_SKIP() << "XFAIL due to Valgrind report"; + + std::vector Decls; +#define Stringify(s) Stringifyx(s) +#define Stringifyx(...) #__VA_ARGS__ + GetAllTopLevelDecls(Stringify(CODE), Decls); +#undef Stringifyx +#undef Stringify +#undef CODE + + auto datamembers_klass1 = Cpp::GetDatamembers(Decls[0]); + auto datamembers_klass2 = Cpp::GetDatamembers(Decls[2]); + auto datamembers_klass3 = Cpp::GetDatamembers(Decls[4]); + + EXPECT_EQ(datamembers_klass1.size(), 3); + EXPECT_EQ(datamembers_klass2.size(), 3); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[1]), + ((intptr_t) & (k1.a)) - ((intptr_t) & (k1.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[2]), + ((intptr_t) & (k1.b)) - ((intptr_t) & (k1.num))); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[1]), + ((intptr_t) & (k2.a)) - ((intptr_t) & (k2.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[2]), + ((intptr_t) & (k2.b)) - ((intptr_t) & (k2.num))); + + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[0]), 0); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[1]), + ((intptr_t) & (k3.a)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[2]), + ((intptr_t) & (k3.b)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[3]), + ((intptr_t) & (k3.c)) - ((intptr_t) & (k3.num))); + EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[4]), + ((intptr_t) & (k3.num2)) - ((intptr_t) & (k3.num))); +} + TEST(VariableReflectionTest, LookupDatamember) { std::vector Decls; std::string code = R"(