xref: /llvm-project/clang/unittests/AST/ByteCode/toAPValue.cpp (revision 2c82079924f1e43b211a6f233ea04ea911a7b581)
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