brintos

brintos / llvm-project-archived public Read only

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