Skip to content

Commit 33546ba

Browse files
Fix: resolve nested attributes of anonymous records in GetDatamembers (#321)
1 parent ea73105 commit 33546ba

File tree

3 files changed

+125
-6
lines changed

3 files changed

+125
-6
lines changed

lib/Interpreter/CppInterOp.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,9 +1128,31 @@ namespace Cpp {
11281128

11291129
if (auto *CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
11301130
std::vector<TCppScope_t> datamembers;
1131-
for (auto it = CXXRD->field_begin(), end = CXXRD->field_end(); it != end;
1132-
it++) {
1133-
datamembers.push_back((TCppScope_t)*it);
1131+
llvm::SmallVector<RecordDecl::field_iterator, 2> stack_begin;
1132+
llvm::SmallVector<RecordDecl::field_iterator, 2> stack_end;
1133+
stack_begin.push_back(CXXRD->field_begin());
1134+
stack_end.push_back(CXXRD->field_end());
1135+
while (!stack_begin.empty()) {
1136+
if (stack_begin.back() == stack_end.back()) {
1137+
stack_begin.pop_back();
1138+
stack_end.pop_back();
1139+
continue;
1140+
}
1141+
Decl* D = *(stack_begin.back());
1142+
if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
1143+
if (FD->isAnonymousStructOrUnion()) {
1144+
if (const auto* RT = FD->getType()->getAs<RecordType>()) {
1145+
if (auto* CXXRD = llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
1146+
stack_begin.back()++;
1147+
stack_begin.push_back(CXXRD->field_begin());
1148+
stack_end.push_back(CXXRD->field_end());
1149+
continue;
1150+
}
1151+
}
1152+
}
1153+
}
1154+
datamembers.push_back((TCppScope_t)D);
1155+
stack_begin.back()++;
11341156
}
11351157

11361158
return datamembers;
@@ -1175,9 +1197,26 @@ namespace Cpp {
11751197
auto *D = (Decl *) var;
11761198
auto &C = getASTContext();
11771199

1178-
if (auto *FD = llvm::dyn_cast<FieldDecl>(D))
1179-
return (intptr_t) C.toCharUnitsFromBits(C.getASTRecordLayout(FD->getParent())
1180-
.getFieldOffset(FD->getFieldIndex())).getQuantity();
1200+
if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
1201+
const clang::RecordDecl* RD = FD->getParent();
1202+
intptr_t offset =
1203+
C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
1204+
while (RD->isAnonymousStructOrUnion()) {
1205+
const clang::RecordDecl* anon = RD;
1206+
RD = llvm::dyn_cast<RecordDecl>(anon->getParent());
1207+
for (auto F = RD->field_begin(); F != RD->field_end(); ++F) {
1208+
const auto* RT = F->getType()->getAs<RecordType>();
1209+
if (!RT)
1210+
continue;
1211+
if (anon == RT->getDecl()) {
1212+
FD = *F;
1213+
break;
1214+
}
1215+
}
1216+
offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
1217+
}
1218+
return offset;
1219+
}
11811220

11821221
if (auto *VD = llvm::dyn_cast<VarDecl>(D)) {
11831222
auto GD = GlobalDecl(VD);

unittests/CppInterOp/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ target_link_libraries(CppInterOpTests
1818
clangCppInterOp
1919
)
2020

21+
if(NOT WIN32)
22+
set_source_files_properties(VariableReflectionTest.cpp PROPERTIES COMPILE_FLAGS
23+
"-Wno-pedantic"
24+
)
25+
endif()
26+
2127
set_source_files_properties(InterpreterTest.cpp PROPERTIES COMPILE_DEFINITIONS
2228
"LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\""
2329
)

unittests/CppInterOp/VariableReflectionTest.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,80 @@ TEST(VariableReflectionTest, GetDatamembers) {
3939
EXPECT_EQ(datamembers1.size(), 0);
4040
}
4141

42+
#define CODE \
43+
struct Klass1 { \
44+
Klass1(int i) : num(1), b(i) {} \
45+
int num; \
46+
union { \
47+
double a; \
48+
int b; \
49+
}; \
50+
} const k1(5); \
51+
struct Klass2 { \
52+
Klass2(double d) : num(2), a(d) {} \
53+
int num; \
54+
struct { \
55+
double a; \
56+
int b; \
57+
}; \
58+
} const k2(2.5); \
59+
struct Klass3 { \
60+
Klass3(int i) : num(i) {} \
61+
int num; \
62+
struct { \
63+
double a; \
64+
union { \
65+
float b; \
66+
int c; \
67+
}; \
68+
}; \
69+
int num2; \
70+
} const k3(5);
71+
72+
CODE
73+
74+
TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) {
75+
if (llvm::sys::RunningOnValgrind())
76+
GTEST_SKIP() << "XFAIL due to Valgrind report";
77+
78+
std::vector<Decl*> Decls;
79+
#define Stringify(s) Stringifyx(s)
80+
#define Stringifyx(...) #__VA_ARGS__
81+
GetAllTopLevelDecls(Stringify(CODE), Decls);
82+
#undef Stringifyx
83+
#undef Stringify
84+
#undef CODE
85+
86+
auto datamembers_klass1 = Cpp::GetDatamembers(Decls[0]);
87+
auto datamembers_klass2 = Cpp::GetDatamembers(Decls[2]);
88+
auto datamembers_klass3 = Cpp::GetDatamembers(Decls[4]);
89+
90+
EXPECT_EQ(datamembers_klass1.size(), 3);
91+
EXPECT_EQ(datamembers_klass2.size(), 3);
92+
93+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[0]), 0);
94+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[1]),
95+
((intptr_t) & (k1.a)) - ((intptr_t) & (k1.num)));
96+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass1[2]),
97+
((intptr_t) & (k1.b)) - ((intptr_t) & (k1.num)));
98+
99+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[0]), 0);
100+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[1]),
101+
((intptr_t) & (k2.a)) - ((intptr_t) & (k2.num)));
102+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass2[2]),
103+
((intptr_t) & (k2.b)) - ((intptr_t) & (k2.num)));
104+
105+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[0]), 0);
106+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[1]),
107+
((intptr_t) & (k3.a)) - ((intptr_t) & (k3.num)));
108+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[2]),
109+
((intptr_t) & (k3.b)) - ((intptr_t) & (k3.num)));
110+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[3]),
111+
((intptr_t) & (k3.c)) - ((intptr_t) & (k3.num)));
112+
EXPECT_EQ(Cpp::GetVariableOffset(datamembers_klass3[4]),
113+
((intptr_t) & (k3.num2)) - ((intptr_t) & (k3.num)));
114+
}
115+
42116
TEST(VariableReflectionTest, LookupDatamember) {
43117
std::vector<Decl*> Decls;
44118
std::string code = R"(

0 commit comments

Comments
 (0)