|
| 1 | +#include "../../../lib/AST/Interp/Context.h" |
| 2 | +#include "../../../lib/AST/Interp/Descriptor.h" |
| 3 | +#include "../../../lib/AST/Interp/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 | + |
| 11 | +using namespace clang; |
| 12 | +using namespace clang::interp; |
| 13 | +using namespace clang::ast_matchers; |
| 14 | + |
| 15 | +/// Test the various toAPValue implementations. |
| 16 | +TEST(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 | + |
| 25 | + auto AST = tooling::buildASTFromCodeWithArgs( |
| 26 | + Code, {"-fexperimental-new-constant-interpreter"}); |
| 27 | + |
| 28 | + auto &Ctx = AST->getASTContext().getInterpContext(); |
| 29 | + Program &Prog = Ctx.getProgram(); |
| 30 | + |
| 31 | + auto getDecl = [&](const char *Name) -> const ValueDecl * { |
| 32 | + auto Nodes = |
| 33 | + match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); |
| 34 | + assert(Nodes.size() == 1); |
| 35 | + const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); |
| 36 | + assert(D); |
| 37 | + return D; |
| 38 | + }; |
| 39 | + auto getGlobalPtr = [&](const char *Name) -> Pointer { |
| 40 | + const VarDecl *D = cast<VarDecl>(getDecl(Name)); |
| 41 | + return Prog.getPtrGlobal(*Prog.getGlobal(D)); |
| 42 | + }; |
| 43 | + |
| 44 | + const Pointer &GP = getGlobalPtr("b"); |
| 45 | + const Pointer &P = GP.deref<Pointer>(); |
| 46 | + ASSERT_TRUE(P.isLive()); |
| 47 | + APValue A = P.toAPValue(); |
| 48 | + ASSERT_TRUE(A.isLValue()); |
| 49 | + ASSERT_TRUE(A.hasLValuePath()); |
| 50 | + const auto &Path = A.getLValuePath(); |
| 51 | + ASSERT_EQ(Path.size(), 3u); |
| 52 | + ASSERT_EQ(A.getLValueBase(), getDecl("d")); |
| 53 | +} |
| 54 | + |
| 55 | +TEST(ToAPValue, FunctionPointers) { |
| 56 | + constexpr char Code[] = " constexpr bool foo() { return true; }\n" |
| 57 | + " constexpr bool (*func)() = foo;\n"; |
| 58 | + |
| 59 | + auto AST = tooling::buildASTFromCodeWithArgs( |
| 60 | + Code, {"-fexperimental-new-constant-interpreter"}); |
| 61 | + |
| 62 | + auto &Ctx = AST->getASTContext().getInterpContext(); |
| 63 | + Program &Prog = Ctx.getProgram(); |
| 64 | + |
| 65 | + auto getDecl = [&](const char *Name) -> const ValueDecl * { |
| 66 | + auto Nodes = |
| 67 | + match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext()); |
| 68 | + assert(Nodes.size() == 1); |
| 69 | + const auto *D = Nodes[0].getNodeAs<ValueDecl>("var"); |
| 70 | + assert(D); |
| 71 | + return D; |
| 72 | + }; |
| 73 | + |
| 74 | + auto getGlobalPtr = [&](const char *Name) -> Pointer { |
| 75 | + const VarDecl *D = cast<VarDecl>(getDecl(Name)); |
| 76 | + return Prog.getPtrGlobal(*Prog.getGlobal(D)); |
| 77 | + }; |
| 78 | + |
| 79 | + const Pointer &GP = getGlobalPtr("func"); |
| 80 | + const FunctionPointer &FP = GP.deref<FunctionPointer>(); |
| 81 | + ASSERT_FALSE(FP.isZero()); |
| 82 | + APValue A = FP.toAPValue(); |
| 83 | + ASSERT_TRUE(A.hasValue()); |
| 84 | + ASSERT_TRUE(A.isLValue()); |
| 85 | + ASSERT_TRUE(A.hasLValuePath()); |
| 86 | + const auto &Path = A.getLValuePath(); |
| 87 | + ASSERT_EQ(Path.size(), 0u); |
| 88 | + ASSERT_FALSE(A.getLValueBase().isNull()); |
| 89 | + ASSERT_EQ(A.getLValueBase().dyn_cast<const ValueDecl *>(), getDecl("foo")); |
| 90 | +} |
0 commit comments