1a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Context.h" 2a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Descriptor.h" 3a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Program.h" 4a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h" 5a07aba5dSTimm Baeder #include "clang/AST/Decl.h" 6a07aba5dSTimm Baeder #include "clang/ASTMatchers/ASTMatchFinder.h" 7a07aba5dSTimm Baeder #include "clang/ASTMatchers/ASTMatchers.h" 8a07aba5dSTimm Baeder #include "clang/Tooling/Tooling.h" 9a07aba5dSTimm Baeder #include "gtest/gtest.h" 10a07aba5dSTimm Baeder 11a07aba5dSTimm Baeder using namespace clang; 12a07aba5dSTimm Baeder using namespace clang::interp; 13a07aba5dSTimm Baeder using namespace clang::ast_matchers; 14a07aba5dSTimm Baeder 15a07aba5dSTimm Baeder /// Test the various toAPValue implementations. 16a07aba5dSTimm Baeder TEST(ToAPValue, Pointers) { 17a07aba5dSTimm Baeder constexpr char Code[] = 18a07aba5dSTimm Baeder "struct A { bool a; bool z; };\n" 19a07aba5dSTimm Baeder "struct S {\n" 20a07aba5dSTimm Baeder " A a[3];\n" 21a07aba5dSTimm Baeder "};\n" 22a07aba5dSTimm Baeder "constexpr S d = {{{true, false}, {false, true}, {false, false}}};\n" 23a07aba5dSTimm Baeder "constexpr const bool *b = &d.a[1].z;\n" 24a07aba5dSTimm Baeder "const void *p = (void*)12;\n" 25*2c820799STimm Baeder "const void *nullp = (void*)0;\n" 26*2c820799STimm Baeder "extern int earr[5][5];\n" 27*2c820799STimm Baeder "constexpr const int *arrp = &earr[2][4];\n"; 28a07aba5dSTimm Baeder 29a07aba5dSTimm Baeder auto AST = tooling::buildASTFromCodeWithArgs( 30a07aba5dSTimm Baeder Code, {"-fexperimental-new-constant-interpreter"}); 31a07aba5dSTimm Baeder 32a07aba5dSTimm Baeder auto &ASTCtx = AST->getASTContext(); 33a07aba5dSTimm Baeder auto &Ctx = AST->getASTContext().getInterpContext(); 34a07aba5dSTimm Baeder Program &Prog = Ctx.getProgram(); 35a07aba5dSTimm Baeder 36a07aba5dSTimm Baeder auto getDecl = [&](const char *Name) -> const ValueDecl * { 37a07aba5dSTimm Baeder auto Nodes = 38a07aba5dSTimm Baeder match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); 39a07aba5dSTimm Baeder assert(Nodes.size() == 1); 40a07aba5dSTimm Baeder const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); 41a07aba5dSTimm Baeder assert(D); 42a07aba5dSTimm Baeder return D; 43a07aba5dSTimm Baeder }; 44a07aba5dSTimm Baeder auto getGlobalPtr = [&](const char *Name) -> Pointer { 45a07aba5dSTimm Baeder const VarDecl *D = cast<VarDecl>(getDecl(Name)); 46a07aba5dSTimm Baeder return Prog.getPtrGlobal(*Prog.getGlobal(D)); 47a07aba5dSTimm Baeder }; 48a07aba5dSTimm Baeder 49a07aba5dSTimm Baeder { 50a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("b"); 51a07aba5dSTimm Baeder const Pointer &P = GP.deref<Pointer>(); 52a07aba5dSTimm Baeder ASSERT_TRUE(P.isLive()); 53a07aba5dSTimm Baeder APValue A = P.toAPValue(ASTCtx); 54a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 55a07aba5dSTimm Baeder ASSERT_TRUE(A.hasLValuePath()); 56a07aba5dSTimm Baeder const auto &Path = A.getLValuePath(); 57a07aba5dSTimm Baeder ASSERT_EQ(Path.size(), 3u); 58a07aba5dSTimm Baeder ASSERT_EQ(A.getLValueBase(), getDecl("d")); 59a07aba5dSTimm Baeder // FIXME: Also test all path elements. 60a07aba5dSTimm Baeder } 61a07aba5dSTimm Baeder 62a07aba5dSTimm Baeder { 63a07aba5dSTimm Baeder const ValueDecl *D = getDecl("p"); 64a07aba5dSTimm Baeder ASSERT_NE(D, nullptr); 65a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("p"); 66a07aba5dSTimm Baeder const Pointer &P = GP.deref<Pointer>(); 67a07aba5dSTimm Baeder ASSERT_TRUE(P.isIntegralPointer()); 68a07aba5dSTimm Baeder APValue A = P.toAPValue(ASTCtx); 69a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 70a07aba5dSTimm Baeder ASSERT_TRUE(A.getLValueBase().isNull()); 71a07aba5dSTimm Baeder APSInt I; 72a07aba5dSTimm Baeder bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext()); 73a07aba5dSTimm Baeder ASSERT_TRUE(Success); 74a07aba5dSTimm Baeder ASSERT_EQ(I, 12); 75a07aba5dSTimm Baeder } 76a07aba5dSTimm Baeder 77a07aba5dSTimm Baeder { 78a07aba5dSTimm Baeder const ValueDecl *D = getDecl("nullp"); 79a07aba5dSTimm Baeder ASSERT_NE(D, nullptr); 80a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("nullp"); 81a07aba5dSTimm Baeder const Pointer &P = GP.deref<Pointer>(); 82a07aba5dSTimm Baeder ASSERT_TRUE(P.isIntegralPointer()); 83a07aba5dSTimm Baeder APValue A = P.toAPValue(ASTCtx); 84a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 85a07aba5dSTimm Baeder ASSERT_TRUE(A.getLValueBase().isNull()); 86a07aba5dSTimm Baeder ASSERT_TRUE(A.isNullPointer()); 87a07aba5dSTimm Baeder APSInt I; 88a07aba5dSTimm Baeder bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext()); 89a07aba5dSTimm Baeder ASSERT_TRUE(Success); 90a07aba5dSTimm Baeder ASSERT_EQ(I, 0); 91a07aba5dSTimm Baeder } 92*2c820799STimm Baeder 93*2c820799STimm Baeder // A multidimensional array. 94*2c820799STimm Baeder { 95*2c820799STimm Baeder const ValueDecl *D = getDecl("arrp"); 96*2c820799STimm Baeder ASSERT_NE(D, nullptr); 97*2c820799STimm Baeder const Pointer &GP = getGlobalPtr("arrp").deref<Pointer>(); 98*2c820799STimm Baeder APValue A = GP.toAPValue(ASTCtx); 99*2c820799STimm Baeder ASSERT_TRUE(A.isLValue()); 100*2c820799STimm Baeder ASSERT_TRUE(A.hasLValuePath()); 101*2c820799STimm Baeder ASSERT_EQ(A.getLValuePath().size(), 2u); 102*2c820799STimm Baeder ASSERT_EQ(A.getLValuePath()[0].getAsArrayIndex(), 2u); 103*2c820799STimm Baeder ASSERT_EQ(A.getLValuePath()[1].getAsArrayIndex(), 4u); 104*2c820799STimm Baeder ASSERT_EQ(A.getLValueOffset().getQuantity(), 56u); 105*2c820799STimm Baeder ASSERT_TRUE( 106*2c820799STimm Baeder GP.atIndex(0).getFieldDesc()->getElemQualType()->isIntegerType()); 107*2c820799STimm Baeder } 108a07aba5dSTimm Baeder } 109a07aba5dSTimm Baeder 110a07aba5dSTimm Baeder TEST(ToAPValue, FunctionPointers) { 111a07aba5dSTimm Baeder constexpr char Code[] = " constexpr bool foo() { return true; }\n" 112a07aba5dSTimm Baeder " constexpr bool (*func)() = foo;\n" 113a07aba5dSTimm Baeder " constexpr bool (*nullp)() = nullptr;\n"; 114a07aba5dSTimm Baeder 115a07aba5dSTimm Baeder auto AST = tooling::buildASTFromCodeWithArgs( 116a07aba5dSTimm Baeder Code, {"-fexperimental-new-constant-interpreter"}); 117a07aba5dSTimm Baeder 118a07aba5dSTimm Baeder auto &ASTCtx = AST->getASTContext(); 119a07aba5dSTimm Baeder auto &Ctx = AST->getASTContext().getInterpContext(); 120a07aba5dSTimm Baeder Program &Prog = Ctx.getProgram(); 121a07aba5dSTimm Baeder 122a07aba5dSTimm Baeder auto getDecl = [&](const char *Name) -> const ValueDecl * { 123a07aba5dSTimm Baeder auto Nodes = 124a07aba5dSTimm Baeder match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); 125a07aba5dSTimm Baeder assert(Nodes.size() == 1); 126a07aba5dSTimm Baeder const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); 127a07aba5dSTimm Baeder assert(D); 128a07aba5dSTimm Baeder return D; 129a07aba5dSTimm Baeder }; 130a07aba5dSTimm Baeder 131a07aba5dSTimm Baeder auto getGlobalPtr = [&](const char *Name) -> Pointer { 132a07aba5dSTimm Baeder const VarDecl *D = cast<VarDecl>(getDecl(Name)); 133a07aba5dSTimm Baeder return Prog.getPtrGlobal(*Prog.getGlobal(D)); 134a07aba5dSTimm Baeder }; 135a07aba5dSTimm Baeder 136a07aba5dSTimm Baeder { 137a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("func"); 138a07aba5dSTimm Baeder const FunctionPointer &FP = GP.deref<FunctionPointer>(); 139a07aba5dSTimm Baeder ASSERT_FALSE(FP.isZero()); 140a07aba5dSTimm Baeder APValue A = FP.toAPValue(ASTCtx); 141a07aba5dSTimm Baeder ASSERT_TRUE(A.hasValue()); 142a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 143a07aba5dSTimm Baeder ASSERT_TRUE(A.hasLValuePath()); 144a07aba5dSTimm Baeder const auto &Path = A.getLValuePath(); 145a07aba5dSTimm Baeder ASSERT_EQ(Path.size(), 0u); 146a07aba5dSTimm Baeder ASSERT_FALSE(A.getLValueBase().isNull()); 147a07aba5dSTimm Baeder ASSERT_EQ(A.getLValueBase().dyn_cast<const ValueDecl *>(), getDecl("foo")); 148a07aba5dSTimm Baeder } 149a07aba5dSTimm Baeder 150a07aba5dSTimm Baeder { 151a07aba5dSTimm Baeder const ValueDecl *D = getDecl("nullp"); 152a07aba5dSTimm Baeder ASSERT_NE(D, nullptr); 153a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("nullp"); 154a07aba5dSTimm Baeder const auto &P = GP.deref<FunctionPointer>(); 155a07aba5dSTimm Baeder APValue A = P.toAPValue(ASTCtx); 156a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 157a07aba5dSTimm Baeder ASSERT_TRUE(A.getLValueBase().isNull()); 158a07aba5dSTimm Baeder ASSERT_TRUE(A.isNullPointer()); 159a07aba5dSTimm Baeder APSInt I; 160a07aba5dSTimm Baeder bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext()); 161a07aba5dSTimm Baeder ASSERT_TRUE(Success); 162a07aba5dSTimm Baeder ASSERT_EQ(I, 0); 163a07aba5dSTimm Baeder } 164a07aba5dSTimm Baeder } 165a07aba5dSTimm Baeder 166a07aba5dSTimm Baeder TEST(ToAPValue, FunctionPointersC) { 167a07aba5dSTimm Baeder // NB: The declaration of func2 is useless, but it makes us register a global 168a07aba5dSTimm Baeder // variable for func. 169a07aba5dSTimm Baeder constexpr char Code[] = "const int (* const func)(int *) = (void*)17;\n" 170a07aba5dSTimm Baeder "const int (*func2)(int *) = func;\n"; 171a07aba5dSTimm Baeder auto AST = tooling::buildASTFromCodeWithArgs( 172a07aba5dSTimm Baeder Code, {"-x", "c", "-fexperimental-new-constant-interpreter"}); 173a07aba5dSTimm Baeder 174a07aba5dSTimm Baeder auto &ASTCtx = AST->getASTContext(); 175a07aba5dSTimm Baeder auto &Ctx = AST->getASTContext().getInterpContext(); 176a07aba5dSTimm Baeder Program &Prog = Ctx.getProgram(); 177a07aba5dSTimm Baeder 178a07aba5dSTimm Baeder auto getDecl = [&](const char *Name) -> const ValueDecl * { 179a07aba5dSTimm Baeder auto Nodes = 180a07aba5dSTimm Baeder match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); 181a07aba5dSTimm Baeder assert(Nodes.size() == 1); 182a07aba5dSTimm Baeder const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); 183a07aba5dSTimm Baeder assert(D); 184a07aba5dSTimm Baeder return D; 185a07aba5dSTimm Baeder }; 186a07aba5dSTimm Baeder 187a07aba5dSTimm Baeder auto getGlobalPtr = [&](const char *Name) -> Pointer { 188a07aba5dSTimm Baeder const VarDecl *D = cast<VarDecl>(getDecl(Name)); 189a07aba5dSTimm Baeder return Prog.getPtrGlobal(*Prog.getGlobal(D)); 190a07aba5dSTimm Baeder }; 191a07aba5dSTimm Baeder 192a07aba5dSTimm Baeder { 193a07aba5dSTimm Baeder const ValueDecl *D = getDecl("func"); 194a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("func"); 195a07aba5dSTimm Baeder ASSERT_TRUE(GP.isLive()); 196a07aba5dSTimm Baeder const FunctionPointer &FP = GP.deref<FunctionPointer>(); 197a07aba5dSTimm Baeder ASSERT_FALSE(FP.isZero()); 198a07aba5dSTimm Baeder APValue A = FP.toAPValue(ASTCtx); 199a07aba5dSTimm Baeder ASSERT_TRUE(A.hasValue()); 200a07aba5dSTimm Baeder ASSERT_TRUE(A.isLValue()); 201a07aba5dSTimm Baeder const auto &Path = A.getLValuePath(); 202a07aba5dSTimm Baeder ASSERT_EQ(Path.size(), 0u); 203a07aba5dSTimm Baeder ASSERT_TRUE(A.getLValueBase().isNull()); 204a07aba5dSTimm Baeder APSInt I; 205a07aba5dSTimm Baeder bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext()); 206a07aba5dSTimm Baeder ASSERT_TRUE(Success); 207a07aba5dSTimm Baeder ASSERT_EQ(I, 17); 208a07aba5dSTimm Baeder } 209a07aba5dSTimm Baeder } 210a07aba5dSTimm Baeder 211a07aba5dSTimm Baeder TEST(ToAPValue, MemberPointers) { 212a07aba5dSTimm Baeder constexpr char Code[] = "struct S {\n" 213a07aba5dSTimm Baeder " int m, n;\n" 214a07aba5dSTimm Baeder "};\n" 215a07aba5dSTimm Baeder "constexpr int S::*pm = &S::m;\n" 216a07aba5dSTimm Baeder "constexpr int S::*nn = nullptr;\n"; 217a07aba5dSTimm Baeder 218a07aba5dSTimm Baeder auto AST = tooling::buildASTFromCodeWithArgs( 219a07aba5dSTimm Baeder Code, {"-fexperimental-new-constant-interpreter"}); 220a07aba5dSTimm Baeder 221a07aba5dSTimm Baeder auto &ASTCtx = AST->getASTContext(); 222a07aba5dSTimm Baeder auto &Ctx = AST->getASTContext().getInterpContext(); 223a07aba5dSTimm Baeder Program &Prog = Ctx.getProgram(); 224a07aba5dSTimm Baeder 225a07aba5dSTimm Baeder auto getDecl = [&](const char *Name) -> const ValueDecl * { 226a07aba5dSTimm Baeder auto Nodes = 227a07aba5dSTimm Baeder match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); 228a07aba5dSTimm Baeder assert(Nodes.size() == 1); 229a07aba5dSTimm Baeder const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); 230a07aba5dSTimm Baeder assert(D); 231a07aba5dSTimm Baeder return D; 232a07aba5dSTimm Baeder }; 233a07aba5dSTimm Baeder 234a07aba5dSTimm Baeder auto getGlobalPtr = [&](const char *Name) -> Pointer { 235a07aba5dSTimm Baeder const VarDecl *D = cast<VarDecl>(getDecl(Name)); 236a07aba5dSTimm Baeder return Prog.getPtrGlobal(*Prog.getGlobal(D)); 237a07aba5dSTimm Baeder }; 238a07aba5dSTimm Baeder 239a07aba5dSTimm Baeder { 240a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("pm"); 241a07aba5dSTimm Baeder ASSERT_TRUE(GP.isLive()); 242a07aba5dSTimm Baeder const MemberPointer &FP = GP.deref<MemberPointer>(); 243a07aba5dSTimm Baeder APValue A = FP.toAPValue(ASTCtx); 244a07aba5dSTimm Baeder ASSERT_EQ(A.getMemberPointerDecl(), getDecl("m")); 245a07aba5dSTimm Baeder ASSERT_EQ(A.getKind(), APValue::MemberPointer); 246a07aba5dSTimm Baeder } 247a07aba5dSTimm Baeder 248a07aba5dSTimm Baeder { 249a07aba5dSTimm Baeder const Pointer &GP = getGlobalPtr("nn"); 250a07aba5dSTimm Baeder ASSERT_TRUE(GP.isLive()); 251a07aba5dSTimm Baeder const MemberPointer &NP = GP.deref<MemberPointer>(); 252a07aba5dSTimm Baeder ASSERT_TRUE(NP.isZero()); 253a07aba5dSTimm Baeder APValue A = NP.toAPValue(ASTCtx); 254a07aba5dSTimm Baeder ASSERT_EQ(A.getKind(), APValue::MemberPointer); 255a07aba5dSTimm Baeder } 256a07aba5dSTimm Baeder } 257