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
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
27 auto AST = tooling::buildASTFromCodeWithArgs(
28 Code, Args: {"-fexperimental-new-constant-interpreter"});
29
30 auto &Ctx = AST->getASTContext().getInterpContext();
31 Program &Prog = Ctx.getProgram();
32
33 auto getDecl = [&](const char *Name) -> const ValueDecl * {
34 auto Nodes =
35 match(Matcher: valueDecl(hasName(Name)).bind(ID: "var"), Context&: AST->getASTContext());
36 assert(Nodes.size() == 1);
37 const auto *D = Nodes[0].getNodeAs<ValueDecl>(ID: "var");
38 assert(D);
39 return D;
40 };
41 auto getGlobalPtr = [&](const char *Name) -> Pointer {
42 const VarDecl *D = cast<VarDecl>(Val: getDecl(Name));
43 return Prog.getPtrGlobal(Idx: *Prog.getGlobal(D));
44 };
45
46 {
47 const Pointer &GP = getGlobalPtr("b");
48 const Pointer &P = GP.deref<Pointer>();
49 ASSERT_TRUE(P.isLive());
50 APValue A = P.toAPValue();
51 ASSERT_TRUE(A.isLValue());
52 ASSERT_TRUE(A.hasLValuePath());
53 const auto &Path = A.getLValuePath();
54 ASSERT_EQ(Path.size(), 3u);
55 ASSERT_EQ(A.getLValueBase(), getDecl("d"));
56 // FIXME: Also test all path elements.
57 }
58
59 {
60 const ValueDecl *D = getDecl("p");
61 ASSERT_NE(D, nullptr);
62 const Pointer &GP = getGlobalPtr("p");
63 const Pointer &P = GP.deref<Pointer>();
64 ASSERT_TRUE(P.isIntegralPointer());
65 APValue A = P.toAPValue();
66 ASSERT_TRUE(A.isLValue());
67 ASSERT_TRUE(A.getLValueBase().isNull());
68 APSInt I;
69 bool Success = A.toIntegralConstant(Result&: I, SrcTy: D->getType(), Ctx: AST->getASTContext());
70 ASSERT_TRUE(Success);
71 ASSERT_EQ(I, 12);
72 }
73
74 {
75 const ValueDecl *D = getDecl("nullp");
76 ASSERT_NE(D, nullptr);
77 const Pointer &GP = getGlobalPtr("nullp");
78 const Pointer &P = GP.deref<Pointer>();
79 ASSERT_TRUE(P.isIntegralPointer());
80 APValue A = P.toAPValue();
81 ASSERT_TRUE(A.isLValue());
82 ASSERT_TRUE(A.getLValueBase().isNull());
83 ASSERT_TRUE(A.isNullPointer());
84 APSInt I;
85 bool Success = A.toIntegralConstant(Result&: I, SrcTy: D->getType(), Ctx: AST->getASTContext());
86 ASSERT_TRUE(Success);
87 ASSERT_EQ(I, 0);
88 }
89}
90
91TEST(ToAPValue, FunctionPointers) {
92 constexpr char Code[] = " constexpr bool foo() { return true; }\n"
93 " constexpr bool (*func)() = foo;\n"
94 " constexpr bool (*nullp)() = nullptr;\n";
95
96 auto AST = tooling::buildASTFromCodeWithArgs(
97 Code, Args: {"-fexperimental-new-constant-interpreter"});
98
99 auto &Ctx = AST->getASTContext().getInterpContext();
100 Program &Prog = Ctx.getProgram();
101
102 auto getDecl = [&](const char *Name) -> const ValueDecl * {
103 auto Nodes =
104 match(Matcher: valueDecl(hasName(Name)).bind(ID: "var"), Context&: AST->getASTContext());
105 assert(Nodes.size() == 1);
106 const auto *D = Nodes[0].getNodeAs<ValueDecl>(ID: "var");
107 assert(D);
108 return D;
109 };
110
111 auto getGlobalPtr = [&](const char *Name) -> Pointer {
112 const VarDecl *D = cast<VarDecl>(Val: getDecl(Name));
113 return Prog.getPtrGlobal(Idx: *Prog.getGlobal(D));
114 };
115
116 {
117 const Pointer &GP = getGlobalPtr("func");
118 const FunctionPointer &FP = GP.deref<FunctionPointer>();
119 ASSERT_FALSE(FP.isZero());
120 APValue A = FP.toAPValue();
121 ASSERT_TRUE(A.hasValue());
122 ASSERT_TRUE(A.isLValue());
123 ASSERT_TRUE(A.hasLValuePath());
124 const auto &Path = A.getLValuePath();
125 ASSERT_EQ(Path.size(), 0u);
126 ASSERT_FALSE(A.getLValueBase().isNull());
127 ASSERT_EQ(A.getLValueBase().dyn_cast<const ValueDecl *>(), getDecl("foo"));
128 }
129
130 {
131 const ValueDecl *D = getDecl("nullp");
132 ASSERT_NE(D, nullptr);
133 const Pointer &GP = getGlobalPtr("nullp");
134 const auto &P = GP.deref<FunctionPointer>();
135 APValue A = P.toAPValue();
136 ASSERT_TRUE(A.isLValue());
137 ASSERT_TRUE(A.getLValueBase().isNull());
138 ASSERT_TRUE(A.isNullPointer());
139 APSInt I;
140 bool Success = A.toIntegralConstant(Result&: I, SrcTy: D->getType(), Ctx: AST->getASTContext());
141 ASSERT_TRUE(Success);
142 ASSERT_EQ(I, 0);
143 }
144}
145
146TEST(ToAPValue, FunctionPointersC) {
147 // NB: The declaration of func2 is useless, but it makes us register a global
148 // variable for func.
149 constexpr char Code[] = "const int (* const func)(int *) = (void*)17;\n"
150 "const int (*func2)(int *) = func;\n";
151 auto AST = tooling::buildASTFromCodeWithArgs(
152 Code, Args: {"-x", "c", "-fexperimental-new-constant-interpreter"});
153
154 auto &Ctx = AST->getASTContext().getInterpContext();
155 Program &Prog = Ctx.getProgram();
156
157 auto getDecl = [&](const char *Name) -> const ValueDecl * {
158 auto Nodes =
159 match(Matcher: valueDecl(hasName(Name)).bind(ID: "var"), Context&: AST->getASTContext());
160 assert(Nodes.size() == 1);
161 const auto *D = Nodes[0].getNodeAs<ValueDecl>(ID: "var");
162 assert(D);
163 return D;
164 };
165
166 auto getGlobalPtr = [&](const char *Name) -> Pointer {
167 const VarDecl *D = cast<VarDecl>(Val: getDecl(Name));
168 return Prog.getPtrGlobal(Idx: *Prog.getGlobal(D));
169 };
170
171 {
172 const ValueDecl *D = getDecl("func");
173 const Pointer &GP = getGlobalPtr("func");
174 ASSERT_TRUE(GP.isLive());
175 const FunctionPointer &FP = GP.deref<FunctionPointer>();
176 ASSERT_FALSE(FP.isZero());
177 APValue A = FP.toAPValue();
178 ASSERT_TRUE(A.hasValue());
179 ASSERT_TRUE(A.isLValue());
180 const auto &Path = A.getLValuePath();
181 ASSERT_EQ(Path.size(), 0u);
182 ASSERT_TRUE(A.getLValueBase().isNull());
183 APSInt I;
184 bool Success = A.toIntegralConstant(Result&: I, SrcTy: D->getType(), Ctx: AST->getASTContext());
185 ASSERT_TRUE(Success);
186 ASSERT_EQ(I, 17);
187 }
188}
189

source code of clang/unittests/AST/Interp/toAPValue.cpp