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"
11 using namespace clang
;
12 using namespace clang::interp
;
13 using namespace clang::ast_matchers
;
15 /// Test the various toAPValue implementations.
16 TEST(ToAPValue
, Pointers
) {
17 constexpr char Code
[] =
18 "struct A { bool a; bool z; };\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";
29 auto AST
= tooling::buildASTFromCodeWithArgs(
30 Code
, {"-fexperimental-new-constant-interpreter"});
32 auto &ASTCtx
= AST
->getASTContext();
33 auto &Ctx
= AST
->getASTContext().getInterpContext();
34 Program
&Prog
= Ctx
.getProgram();
36 auto getDecl
= [&](const char *Name
) -> const ValueDecl
* {
38 match(valueDecl(hasName(Name
)).bind("var"), AST
->getASTContext());
39 assert(Nodes
.size() == 1);
40 const auto *D
= Nodes
[0].getNodeAs
<ValueDecl
>("var");
44 auto getGlobalPtr
= [&](const char *Name
) -> Pointer
{
45 const VarDecl
*D
= cast
<VarDecl
>(getDecl(Name
));
46 return Prog
.getPtrGlobal(*Prog
.getGlobal(D
));
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.
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());
72 bool Success
= A
.toIntegralConstant(I
, D
->getType(), AST
->getASTContext());
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());
88 bool Success
= A
.toIntegralConstant(I
, D
->getType(), AST
->getASTContext());
93 // A multidimensional array.
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);
106 GP
.atIndex(0).getFieldDesc()->getElemQualType()->isIntegerType());
110 TEST(ToAPValue
, FunctionPointers
) {
111 constexpr char Code
[] = " constexpr bool foo() { return true; }\n"
112 " constexpr bool (*func)() = foo;\n"
113 " constexpr bool (*nullp)() = nullptr;\n";
115 auto AST
= tooling::buildASTFromCodeWithArgs(
116 Code
, {"-fexperimental-new-constant-interpreter"});
118 auto &ASTCtx
= AST
->getASTContext();
119 auto &Ctx
= AST
->getASTContext().getInterpContext();
120 Program
&Prog
= Ctx
.getProgram();
122 auto getDecl
= [&](const char *Name
) -> const ValueDecl
* {
124 match(valueDecl(hasName(Name
)).bind("var"), AST
->getASTContext());
125 assert(Nodes
.size() == 1);
126 const auto *D
= Nodes
[0].getNodeAs
<ValueDecl
>("var");
131 auto getGlobalPtr
= [&](const char *Name
) -> Pointer
{
132 const VarDecl
*D
= cast
<VarDecl
>(getDecl(Name
));
133 return Prog
.getPtrGlobal(*Prog
.getGlobal(D
));
137 const Pointer
&GP
= getGlobalPtr("func");
138 const FunctionPointer
&FP
= GP
.deref
<FunctionPointer
>();
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"));
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());
160 bool Success
= A
.toIntegralConstant(I
, D
->getType(), AST
->getASTContext());
161 ASSERT_TRUE(Success
);
166 TEST(ToAPValue
, FunctionPointersC
) {
167 // NB: The declaration of func2 is useless, but it makes us register a global
168 // 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"});
174 auto &ASTCtx
= AST
->getASTContext();
175 auto &Ctx
= AST
->getASTContext().getInterpContext();
176 Program
&Prog
= Ctx
.getProgram();
178 auto getDecl
= [&](const char *Name
) -> const ValueDecl
* {
180 match(valueDecl(hasName(Name
)).bind("var"), AST
->getASTContext());
181 assert(Nodes
.size() == 1);
182 const auto *D
= Nodes
[0].getNodeAs
<ValueDecl
>("var");
187 auto getGlobalPtr
= [&](const char *Name
) -> Pointer
{
188 const VarDecl
*D
= cast
<VarDecl
>(getDecl(Name
));
189 return Prog
.getPtrGlobal(*Prog
.getGlobal(D
));
193 const ValueDecl
*D
= getDecl("func");
194 const Pointer
&GP
= getGlobalPtr("func");
195 ASSERT_TRUE(GP
.isLive());
196 const FunctionPointer
&FP
= GP
.deref
<FunctionPointer
>();
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());
205 bool Success
= A
.toIntegralConstant(I
, D
->getType(), AST
->getASTContext());
206 ASSERT_TRUE(Success
);
211 TEST(ToAPValue
, MemberPointers
) {
212 constexpr char Code
[] = "struct S {\n"
215 "constexpr int S::*pm = &S::m;\n"
216 "constexpr int S::*nn = nullptr;\n";
218 auto AST
= tooling::buildASTFromCodeWithArgs(
219 Code
, {"-fexperimental-new-constant-interpreter"});
221 auto &ASTCtx
= AST
->getASTContext();
222 auto &Ctx
= AST
->getASTContext().getInterpContext();
223 Program
&Prog
= Ctx
.getProgram();
225 auto getDecl
= [&](const char *Name
) -> const ValueDecl
* {
227 match(valueDecl(hasName(Name
)).bind("var"), AST
->getASTContext());
228 assert(Nodes
.size() == 1);
229 const auto *D
= Nodes
[0].getNodeAs
<ValueDecl
>("var");
234 auto getGlobalPtr
= [&](const char *Name
) -> Pointer
{
235 const VarDecl
*D
= cast
<VarDecl
>(getDecl(Name
));
236 return Prog
.getPtrGlobal(*Prog
.getGlobal(D
));
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
);
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
);