1 //===- unittests/Interpreter/InterpreterTest.cpp --- Interpreter tests ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Unit tests for Clang's Interpreter library.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "clang/Interpreter/Interpreter.h"
14
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclGroup.h"
17 #include "clang/AST/Mangle.h"
18 #include "clang/Frontend/CompilerInstance.h"
19 #include "clang/Frontend/TextDiagnosticPrinter.h"
20 #include "clang/Sema/Lookup.h"
21 #include "clang/Sema/Sema.h"
22
23 #include "llvm/Support/TargetSelect.h"
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27
28 using namespace clang;
29
30 namespace {
31 using Args = std::vector<const char *>;
32 static std::unique_ptr<Interpreter>
createInterpreter(const Args & ExtraArgs={},DiagnosticConsumer * Client=nullptr)33 createInterpreter(const Args &ExtraArgs = {},
34 DiagnosticConsumer *Client = nullptr) {
35 Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
36 ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
37 auto CI = cantFail(clang::IncrementalCompilerBuilder::create(ClangArgs));
38 if (Client)
39 CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false);
40 return cantFail(clang::Interpreter::create(std::move(CI)));
41 }
42
DeclsSize(TranslationUnitDecl * PTUDecl)43 static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
44 return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
45 }
46
TEST(InterpreterTest,Sanity)47 TEST(InterpreterTest, Sanity) {
48 std::unique_ptr<Interpreter> Interp = createInterpreter();
49
50 using PTU = PartialTranslationUnit;
51
52 PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
53 EXPECT_EQ(2U, DeclsSize(R1.TUPart));
54
55 PTU &R2(cantFail(Interp->Parse("int i;")));
56 EXPECT_EQ(1U, DeclsSize(R2.TUPart));
57 }
58
DeclToString(Decl * D)59 static std::string DeclToString(Decl *D) {
60 return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString();
61 }
62
TEST(InterpreterTest,IncrementalInputTopLevelDecls)63 TEST(InterpreterTest, IncrementalInputTopLevelDecls) {
64 std::unique_ptr<Interpreter> Interp = createInterpreter();
65 auto R1 = Interp->Parse("int var1 = 42; int f() { return var1; }");
66 // gtest doesn't expand into explicit bool conversions.
67 EXPECT_TRUE(!!R1);
68 auto R1DeclRange = R1->TUPart->decls();
69 EXPECT_EQ(2U, DeclsSize(R1->TUPart));
70 EXPECT_EQ("var1", DeclToString(*R1DeclRange.begin()));
71 EXPECT_EQ("f", DeclToString(*(++R1DeclRange.begin())));
72
73 auto R2 = Interp->Parse("int var2 = f();");
74 EXPECT_TRUE(!!R2);
75 auto R2DeclRange = R2->TUPart->decls();
76 EXPECT_EQ(1U, DeclsSize(R2->TUPart));
77 EXPECT_EQ("var2", DeclToString(*R2DeclRange.begin()));
78 }
79
TEST(InterpreterTest,Errors)80 TEST(InterpreterTest, Errors) {
81 Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"};
82
83 // Create the diagnostic engine with unowned consumer.
84 std::string DiagnosticOutput;
85 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
86 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
87 DiagnosticsOS, new DiagnosticOptions());
88
89 auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
90 auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError();
91 using ::testing::HasSubstr;
92 EXPECT_THAT(DiagnosticsOS.str(),
93 HasSubstr("error: unknown type name 'intentional_error'"));
94 EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
95
96 auto RecoverErr = Interp->Parse("int var1 = 42;");
97 EXPECT_TRUE(!!RecoverErr);
98 }
99
100 // Here we test whether the user can mix declarations and statements. The
101 // interpreter should be smart enough to recognize the declarations from the
102 // statements and wrap the latter into a declaration, producing valid code.
TEST(InterpreterTest,DeclsAndStatements)103 TEST(InterpreterTest, DeclsAndStatements) {
104 Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"};
105
106 // Create the diagnostic engine with unowned consumer.
107 std::string DiagnosticOutput;
108 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
109 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
110 DiagnosticsOS, new DiagnosticOptions());
111
112 auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
113 auto R1 = Interp->Parse(
114 "int var1 = 42; extern \"C\" int printf(const char*, ...);");
115 // gtest doesn't expand into explicit bool conversions.
116 EXPECT_TRUE(!!R1);
117
118 auto *PTU1 = R1->TUPart;
119 EXPECT_EQ(2U, DeclsSize(PTU1));
120
121 // FIXME: Add support for wrapping and running statements.
122 auto R2 = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);");
123 EXPECT_FALSE(!!R2);
124 using ::testing::HasSubstr;
125 EXPECT_THAT(DiagnosticsOS.str(),
126 HasSubstr("error: unknown type name 'var1'"));
127 auto Err = R2.takeError();
128 EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
129 }
130
TEST(InterpreterTest,UndoCommand)131 TEST(InterpreterTest, UndoCommand) {
132 Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"};
133
134 // Create the diagnostic engine with unowned consumer.
135 std::string DiagnosticOutput;
136 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
137 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
138 DiagnosticsOS, new DiagnosticOptions());
139
140 auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
141
142 // Fail to undo.
143 auto Err1 = Interp->Undo();
144 EXPECT_EQ("Operation failed. Too many undos",
145 llvm::toString(std::move(Err1)));
146 auto Err2 = Interp->Parse("int foo = 42;");
147 EXPECT_TRUE(!!Err2);
148 auto Err3 = Interp->Undo(2);
149 EXPECT_EQ("Operation failed. Too many undos",
150 llvm::toString(std::move(Err3)));
151
152 // Succeed to undo.
153 auto Err4 = Interp->Parse("int x = 42;");
154 EXPECT_TRUE(!!Err4);
155 auto Err5 = Interp->Undo();
156 EXPECT_FALSE(Err5);
157 auto Err6 = Interp->Parse("int x = 24;");
158 EXPECT_TRUE(!!Err6);
159 auto Err7 = Interp->Parse("#define X 42");
160 EXPECT_TRUE(!!Err7);
161 auto Err8 = Interp->Undo();
162 EXPECT_FALSE(Err8);
163 auto Err9 = Interp->Parse("#define X 24");
164 EXPECT_TRUE(!!Err9);
165
166 // Undo input contains errors.
167 auto Err10 = Interp->Parse("int y = ;");
168 EXPECT_FALSE(!!Err10);
169 EXPECT_EQ("Parsing failed.", llvm::toString(Err10.takeError()));
170 auto Err11 = Interp->Parse("int y = 42;");
171 EXPECT_TRUE(!!Err11);
172 auto Err12 = Interp->Undo();
173 EXPECT_FALSE(Err12);
174 }
175
MangleName(NamedDecl * ND)176 static std::string MangleName(NamedDecl *ND) {
177 ASTContext &C = ND->getASTContext();
178 std::unique_ptr<MangleContext> MangleC(C.createMangleContext());
179 std::string mangledName;
180 llvm::raw_string_ostream RawStr(mangledName);
181 MangleC->mangleName(ND, RawStr);
182 return RawStr.str();
183 }
184
185 struct LLVMInitRAII {
LLVMInitRAII__anonc9140f9d0111::LLVMInitRAII186 LLVMInitRAII() {
187 llvm::InitializeNativeTarget();
188 llvm::InitializeNativeTargetAsmPrinter();
189 }
~LLVMInitRAII__anonc9140f9d0111::LLVMInitRAII190 ~LLVMInitRAII() { llvm::llvm_shutdown(); }
191 } LLVMInit;
192
193 #ifdef _AIX
TEST(IncrementalProcessing,DISABLED_FindMangledNameSymbol)194 TEST(IncrementalProcessing, DISABLED_FindMangledNameSymbol) {
195 #else
196 TEST(IncrementalProcessing, FindMangledNameSymbol) {
197 #endif
198
199 std::unique_ptr<Interpreter> Interp = createInterpreter();
200
201 auto &PTU(cantFail(Interp->Parse("int f(const char*) {return 0;}")));
202 EXPECT_EQ(1U, DeclsSize(PTU.TUPart));
203 auto R1DeclRange = PTU.TUPart->decls();
204
205 NamedDecl *FD = cast<FunctionDecl>(*R1DeclRange.begin());
206 // Lower the PTU
207 if (llvm::Error Err = Interp->Execute(PTU)) {
208 // We cannot execute on the platform.
209 consumeError(std::move(Err));
210 return;
211 }
212
213 std::string MangledName = MangleName(FD);
214 auto Addr = cantFail(Interp->getSymbolAddress(MangledName));
215 EXPECT_NE(0U, Addr);
216 GlobalDecl GD(FD);
217 EXPECT_EQ(Addr, cantFail(Interp->getSymbolAddress(GD)));
218 }
219
220 static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
221 std::string Name = TD->getQualifiedNameAsString();
222 const clang::Type *RDTy = TD->getTypeForDecl();
223 clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
224 size_t Size = C.getTypeSize(RDTy);
225 void *Addr = malloc(Size);
226
227 // Tell the interpreter to call the default ctor with this memory. Synthesize:
228 // new (loc) ClassName;
229 static unsigned Counter = 0;
230 std::stringstream SS;
231 SS << "auto _v" << Counter++ << " = "
232 << "new ((void*)"
233 // Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
234 << std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";
235
236 auto R = Interp.ParseAndExecute(SS.str());
237 if (!R) {
238 free(Addr);
239 return nullptr;
240 }
241
242 return Addr;
243 }
244
245 static NamedDecl *LookupSingleName(Interpreter &Interp, const char *Name) {
246 Sema &SemaRef = Interp.getCompilerInstance()->getSema();
247 ASTContext &C = SemaRef.getASTContext();
248 DeclarationName DeclName = &C.Idents.get(Name);
249 LookupResult R(SemaRef, DeclName, SourceLocation(), Sema::LookupOrdinaryName);
250 SemaRef.LookupName(R, SemaRef.TUScope);
251 assert(!R.empty());
252 return R.getFoundDecl();
253 }
254
255 #ifdef _AIX
256 TEST(IncrementalProcessing, DISABLED_InstantiateTemplate) {
257 #else
258 TEST(IncrementalProcessing, InstantiateTemplate) {
259 #endif
260 // FIXME: We cannot yet handle delayed template parsing. If we run with
261 // -fdelayed-template-parsing we try adding the newly created decl to the
262 // active PTU which causes an assert.
263 std::vector<const char *> Args = {"-fno-delayed-template-parsing"};
264 std::unique_ptr<Interpreter> Interp = createInterpreter(Args);
265
266 llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);"
267 "extern \"C\" int printf(const char*,...);"
268 "class A {};"
269 "struct B {"
270 " template<typename T>"
271 " static int callme(T) { return 42; }"
272 "};"));
273 auto &PTU = llvm::cantFail(Interp->Parse("auto _t = &B::callme<A*>;"));
274 auto PTUDeclRange = PTU.TUPart->decls();
275 EXPECT_EQ(1, std::distance(PTUDeclRange.begin(), PTUDeclRange.end()));
276
277 // Lower the PTU
278 if (llvm::Error Err = Interp->Execute(PTU)) {
279 // We cannot execute on the platform.
280 consumeError(std::move(Err));
281 return;
282 }
283
284 TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
285 void *NewA = AllocateObject(TD, *Interp);
286
287 // Find back the template specialization
288 VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin());
289 UnaryOperator *UO = llvm::cast<UnaryOperator>(VD->getInit());
290 NamedDecl *TmpltSpec = llvm::cast<DeclRefExpr>(UO->getSubExpr())->getDecl();
291
292 std::string MangledName = MangleName(TmpltSpec);
293 typedef int (*TemplateSpecFn)(void *);
294 auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName));
295 EXPECT_EQ(42, fn(NewA));
296 free(NewA);
297 }
298
299 } // end anonymous namespace
300