Skip to content

Commit

Permalink
fix GetVariableOffset for static constexpr class attribute
Browse files Browse the repository at this point in the history
by explicitly initializing constexpr with `Sema::InstantiateVariableDefinition`
  • Loading branch information
Vipul-Cariappa committed Nov 15, 2024
1 parent 826be78 commit 97a9b6c
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 14 deletions.
14 changes: 13 additions & 1 deletion lib/Interpreter/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,18 @@ namespace Cpp {

if (!address)
address = I.getAddressOfGlobal(GD);
if (!address) {
if (!VD->hasInit())
getSema().InstantiateVariableDefinition(SourceLocation(), VD);

Check warning on line 1253 in lib/Interpreter/CppInterOp.cpp

View check run for this annotation

Codecov / codecov/patch

lib/Interpreter/CppInterOp.cpp#L1253

Added line #L1253 was not covered by tests
if (VD->hasInit() &&
(VD->isConstexpr() || VD->getType().isConstQualified())) {
if (const APValue* val = VD->evaluateValue()) {
if (VD->getType()->isIntegralType(C)) {
return (intptr_t)val->getInt().getRawData();
}
}
}
}
if (!address) {
auto Linkage = C.GetGVALinkageForVariable(VD);
// The decl was deferred by CodeGen. Force its emission.
Expand Down Expand Up @@ -1289,7 +1301,7 @@ namespace Cpp {
"Failed to GetVariableOffset:");
return 0;
}
return (intptr_t) jitTargetAddressToPointer<void*>(VDAorErr.get());
return (intptr_t)jitTargetAddressToPointer<void*>(VDAorErr.get());
}

return 0;
Expand Down
111 changes: 98 additions & 13 deletions unittests/CppInterOp/VariableReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,19 @@ TEST(VariableReflectionTest, GetVariableType) {
EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetVariableType(Decls[8])), "int[4]");
}

#define CODE \
int a; \
const int N = 5; \
class C { \
public: \
int a; \
double b; \
int *c; \
int d; \
static int s_a; \
} c; \
#define CODE \
int a; \
const int N = 5; \
static int S = N + 1; \
static const int SN = S + 1; \
class C { \
public: \
int a; \
double b; \
int* c; \
int d; \
static int s_a; \
} c; \
int C::s_a = 7 + N;

CODE
Expand All @@ -215,11 +217,15 @@ TEST(VariableReflectionTest, GetVariableOffset) {
#undef Stringify
#undef CODE

EXPECT_EQ(7, Decls.size());

std::vector<Cpp::TCppScope_t> datamembers;
Cpp::GetDatamembers(Decls[2], datamembers);
Cpp::GetDatamembers(Decls[4], datamembers);

EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[0])); // a
EXPECT_TRUE((bool) Cpp::GetVariableOffset(Decls[1])); // N
EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[2])); // S
EXPECT_TRUE((bool)Cpp::GetVariableOffset(Decls[3])); // SN

EXPECT_EQ(Cpp::GetVariableOffset(datamembers[0]), 0);

Expand All @@ -230,7 +236,7 @@ TEST(VariableReflectionTest, GetVariableOffset) {
EXPECT_EQ(Cpp::GetVariableOffset(datamembers[3]),
((intptr_t) &(c.d)) - ((intptr_t) &(c.a)));

auto *VD_C_s_a = Cpp::GetNamed("s_a", Decls[2]); // C::s_a
auto* VD_C_s_a = Cpp::GetNamed("s_a", Decls[4]); // C::s_a
EXPECT_TRUE((bool) Cpp::GetVariableOffset(VD_C_s_a));
}

Expand Down Expand Up @@ -355,3 +361,82 @@ TEST(VariableReflectionTest, DISABLED_GetArrayDimensions) {
// EXPECT_TRUE(is_vec_eq(Cpp::GetArrayDimensions(Decls[1]), {1}));
// EXPECT_TRUE(is_vec_eq(Cpp::GetArrayDimensions(Decls[2]), {1,2}));
}

TEST(VariableReflectionTest, StaticConstExprDatamember) {
if (llvm::sys::RunningOnValgrind())
GTEST_SKIP() << "XFAIL due to Valgrind report";

#ifdef _WIN32
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";
#endif

Cpp::CreateInterpreter();

Cpp::Declare(R"(
class MyClass {
public:
static constexpr int x = 3;
};
template<int i>
class MyTemplatedClass {
public:
static constexpr int x = i;
};
template<typename _Tp, _Tp __v>
struct integral_constant
{
static constexpr _Tp value = __v;
};
template<typename... Eles>
struct Elements
: public integral_constant<int, sizeof...(Eles)> {};
)");

Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass");
EXPECT_TRUE(MyClass);

std::vector<Cpp::TCppScope_t> datamembers;
Cpp::GetStaticDatamembers(MyClass, datamembers);
EXPECT_EQ(datamembers.size(), 1);

intptr_t offset = Cpp::GetVariableOffset(datamembers[0]);
EXPECT_EQ(3, *(int*)offset);

ASTContext& C = Interp->getCI()->getASTContext();
std::vector<Cpp::TemplateArgInfo> template_args = {
{C.IntTy.getAsOpaquePtr(), "5"}};

Cpp::TCppFunction_t MyTemplatedClass =
Cpp::InstantiateTemplate(Cpp::GetNamed("MyTemplatedClass"),
template_args.data(), template_args.size());
EXPECT_TRUE(MyTemplatedClass);

datamembers.clear();
Cpp::GetStaticDatamembers(MyTemplatedClass, datamembers);
EXPECT_EQ(datamembers.size(), 1);

offset = Cpp::GetVariableOffset(datamembers[0]);
EXPECT_EQ(5, *(int*)offset);

std::vector<Cpp::TemplateArgInfo> ele_template_args = {
{C.IntTy.getAsOpaquePtr()}, {C.FloatTy.getAsOpaquePtr()}};

Cpp::TCppFunction_t Elements = Cpp::InstantiateTemplate(
Cpp::GetNamed("Elements"), ele_template_args.data(),
ele_template_args.size());
EXPECT_TRUE(Elements);

EXPECT_EQ(1, Cpp::GetNumBases(Elements));

Cpp::TCppScope_t IC = Cpp::GetBaseClass(Elements, 0);

datamembers.clear();
Cpp::GetStaticDatamembers(IC, datamembers);
EXPECT_EQ(datamembers.size(), 1);

offset = Cpp::GetVariableOffset(datamembers[0]);
EXPECT_EQ(2, *(int*)offset);
}

0 comments on commit 97a9b6c

Please sign in to comment.