diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 78e506ce..1c72bbba 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1248,6 +1248,18 @@ namespace Cpp { if (!address) address = I.getAddressOfGlobal(GD); + if (!address) { + if (!VD->hasInit()) + getSema().InstantiateVariableDefinition(SourceLocation(), VD); + 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. @@ -1289,7 +1301,7 @@ namespace Cpp { "Failed to GetVariableOffset:"); return 0; } - return (intptr_t) jitTargetAddressToPointer(VDAorErr.get()); + return (intptr_t)jitTargetAddressToPointer(VDAorErr.get()); } return 0; diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 5826840a..78a628f1 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -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 @@ -215,11 +217,15 @@ TEST(VariableReflectionTest, GetVariableOffset) { #undef Stringify #undef CODE + EXPECT_EQ(7, Decls.size()); + std::vector 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); @@ -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)); } @@ -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 + class MyTemplatedClass { + public: + static constexpr int x = i; + }; + + template + struct integral_constant + { + static constexpr _Tp value = __v; + }; + + template + struct Elements + : public integral_constant {}; + )"); + + Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass"); + EXPECT_TRUE(MyClass); + + std::vector 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 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 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); +}