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/Interpreter/Value.h" |
21 | #include "clang/Sema/Lookup.h" |
22 | #include "clang/Sema/Sema.h" |
23 | |
24 | #include "llvm/ExecutionEngine/Orc/LLJIT.h" |
25 | #include "llvm/Support/ManagedStatic.h" |
26 | #include "llvm/Support/TargetSelect.h" |
27 | |
28 | #include "gmock/gmock.h" |
29 | #include "gtest/gtest.h" |
30 | |
31 | using namespace clang; |
32 | |
33 | #if defined(_AIX) |
34 | #define CLANG_INTERPRETER_NO_SUPPORT_EXEC |
35 | #endif |
36 | |
37 | int Global = 42; |
38 | // JIT reports symbol not found on Windows without the visibility attribute. |
39 | REPL_EXTERNAL_VISIBILITY int getGlobal() { return Global; } |
40 | REPL_EXTERNAL_VISIBILITY void setGlobal(int val) { Global = val; } |
41 | |
42 | namespace { |
43 | using Args = std::vector<const char *>; |
44 | static std::unique_ptr<Interpreter> |
45 | createInterpreter(const Args & = {}, |
46 | DiagnosticConsumer *Client = nullptr) { |
47 | Args ClangArgs = {"-Xclang" , "-emit-llvm-only" }; |
48 | ClangArgs.insert(position: ClangArgs.end(), first: ExtraArgs.begin(), last: ExtraArgs.end()); |
49 | auto CB = clang::IncrementalCompilerBuilder(); |
50 | CB.SetCompilerArgs(ClangArgs); |
51 | auto CI = cantFail(ValOrErr: CB.CreateCpp()); |
52 | if (Client) |
53 | CI->getDiagnostics().setClient(client: Client, /*ShouldOwnClient=*/false); |
54 | return cantFail(ValOrErr: clang::Interpreter::create(CI: std::move(CI))); |
55 | } |
56 | |
57 | static size_t DeclsSize(TranslationUnitDecl *PTUDecl) { |
58 | return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end()); |
59 | } |
60 | |
61 | TEST(InterpreterTest, Sanity) { |
62 | std::unique_ptr<Interpreter> Interp = createInterpreter(); |
63 | |
64 | using PTU = PartialTranslationUnit; |
65 | |
66 | PTU &R1(cantFail(ValOrErr: Interp->Parse(Code: "void g(); void g() {}" ))); |
67 | EXPECT_EQ(2U, DeclsSize(R1.TUPart)); |
68 | |
69 | PTU &R2(cantFail(ValOrErr: Interp->Parse(Code: "int i;" ))); |
70 | EXPECT_EQ(1U, DeclsSize(R2.TUPart)); |
71 | } |
72 | |
73 | static std::string DeclToString(Decl *D) { |
74 | return llvm::cast<NamedDecl>(Val: D)->getQualifiedNameAsString(); |
75 | } |
76 | |
77 | TEST(InterpreterTest, IncrementalInputTopLevelDecls) { |
78 | std::unique_ptr<Interpreter> Interp = createInterpreter(); |
79 | auto R1 = Interp->Parse(Code: "int var1 = 42; int f() { return var1; }" ); |
80 | // gtest doesn't expand into explicit bool conversions. |
81 | EXPECT_TRUE(!!R1); |
82 | auto R1DeclRange = R1->TUPart->decls(); |
83 | EXPECT_EQ(2U, DeclsSize(R1->TUPart)); |
84 | EXPECT_EQ("var1" , DeclToString(*R1DeclRange.begin())); |
85 | EXPECT_EQ("f" , DeclToString(*(++R1DeclRange.begin()))); |
86 | |
87 | auto R2 = Interp->Parse(Code: "int var2 = f();" ); |
88 | EXPECT_TRUE(!!R2); |
89 | auto R2DeclRange = R2->TUPart->decls(); |
90 | EXPECT_EQ(1U, DeclsSize(R2->TUPart)); |
91 | EXPECT_EQ("var2" , DeclToString(*R2DeclRange.begin())); |
92 | } |
93 | |
94 | TEST(InterpreterTest, Errors) { |
95 | Args = {"-Xclang" , "-diagnostic-log-file" , "-Xclang" , "-" }; |
96 | |
97 | // Create the diagnostic engine with unowned consumer. |
98 | std::string DiagnosticOutput; |
99 | llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); |
100 | auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( |
101 | args&: DiagnosticsOS, args: new DiagnosticOptions()); |
102 | |
103 | auto Interp = createInterpreter(ExtraArgs, Client: DiagPrinter.get()); |
104 | auto Err = Interp->Parse(Code: "intentional_error v1 = 42; " ).takeError(); |
105 | using ::testing::HasSubstr; |
106 | EXPECT_THAT(DiagnosticsOS.str(), |
107 | HasSubstr("error: unknown type name 'intentional_error'" )); |
108 | EXPECT_EQ("Parsing failed." , llvm::toString(std::move(Err))); |
109 | |
110 | auto RecoverErr = Interp->Parse(Code: "int var1 = 42;" ); |
111 | EXPECT_TRUE(!!RecoverErr); |
112 | } |
113 | |
114 | // Here we test whether the user can mix declarations and statements. The |
115 | // interpreter should be smart enough to recognize the declarations from the |
116 | // statements and wrap the latter into a declaration, producing valid code. |
117 | TEST(InterpreterTest, DeclsAndStatements) { |
118 | Args = {"-Xclang" , "-diagnostic-log-file" , "-Xclang" , "-" }; |
119 | |
120 | // Create the diagnostic engine with unowned consumer. |
121 | std::string DiagnosticOutput; |
122 | llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); |
123 | auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( |
124 | args&: DiagnosticsOS, args: new DiagnosticOptions()); |
125 | |
126 | auto Interp = createInterpreter(ExtraArgs, Client: DiagPrinter.get()); |
127 | auto R1 = Interp->Parse( |
128 | Code: "int var1 = 42; extern \"C\" int printf(const char*, ...);" ); |
129 | // gtest doesn't expand into explicit bool conversions. |
130 | EXPECT_TRUE(!!R1); |
131 | |
132 | auto *PTU1 = R1->TUPart; |
133 | EXPECT_EQ(2U, DeclsSize(PTU1)); |
134 | |
135 | auto R2 = Interp->Parse(Code: "var1++; printf(\"var1 value %d\\n\", var1);" ); |
136 | EXPECT_TRUE(!!R2); |
137 | } |
138 | |
139 | TEST(InterpreterTest, UndoCommand) { |
140 | Args = {"-Xclang" , "-diagnostic-log-file" , "-Xclang" , "-" }; |
141 | |
142 | // Create the diagnostic engine with unowned consumer. |
143 | std::string DiagnosticOutput; |
144 | llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); |
145 | auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( |
146 | args&: DiagnosticsOS, args: new DiagnosticOptions()); |
147 | |
148 | auto Interp = createInterpreter(ExtraArgs, Client: DiagPrinter.get()); |
149 | |
150 | // Fail to undo. |
151 | auto Err1 = Interp->Undo(); |
152 | EXPECT_EQ("Operation failed. Too many undos" , |
153 | llvm::toString(std::move(Err1))); |
154 | auto Err2 = Interp->Parse(Code: "int foo = 42;" ); |
155 | EXPECT_TRUE(!!Err2); |
156 | auto Err3 = Interp->Undo(N: 2); |
157 | EXPECT_EQ("Operation failed. Too many undos" , |
158 | llvm::toString(std::move(Err3))); |
159 | |
160 | // Succeed to undo. |
161 | auto Err4 = Interp->Parse(Code: "int x = 42;" ); |
162 | EXPECT_TRUE(!!Err4); |
163 | auto Err5 = Interp->Undo(); |
164 | EXPECT_FALSE(Err5); |
165 | auto Err6 = Interp->Parse(Code: "int x = 24;" ); |
166 | EXPECT_TRUE(!!Err6); |
167 | auto Err7 = Interp->Parse(Code: "#define X 42" ); |
168 | EXPECT_TRUE(!!Err7); |
169 | auto Err8 = Interp->Undo(); |
170 | EXPECT_FALSE(Err8); |
171 | auto Err9 = Interp->Parse(Code: "#define X 24" ); |
172 | EXPECT_TRUE(!!Err9); |
173 | |
174 | // Undo input contains errors. |
175 | auto Err10 = Interp->Parse(Code: "int y = ;" ); |
176 | EXPECT_FALSE(!!Err10); |
177 | EXPECT_EQ("Parsing failed." , llvm::toString(Err10.takeError())); |
178 | auto Err11 = Interp->Parse(Code: "int y = 42;" ); |
179 | EXPECT_TRUE(!!Err11); |
180 | auto Err12 = Interp->Undo(); |
181 | EXPECT_FALSE(Err12); |
182 | } |
183 | |
184 | static std::string MangleName(NamedDecl *ND) { |
185 | ASTContext &C = ND->getASTContext(); |
186 | std::unique_ptr<MangleContext> MangleC(C.createMangleContext()); |
187 | std::string mangledName; |
188 | llvm::raw_string_ostream RawStr(mangledName); |
189 | MangleC->mangleName(GD: ND, RawStr); |
190 | return RawStr.str(); |
191 | } |
192 | |
193 | static bool HostSupportsJit() { |
194 | auto J = llvm::orc::LLJITBuilder().create(); |
195 | if (J) |
196 | return true; |
197 | LLVMConsumeError(Err: llvm::wrap(Err: J.takeError())); |
198 | return false; |
199 | } |
200 | |
201 | struct LLVMInitRAII { |
202 | LLVMInitRAII() { |
203 | llvm::InitializeNativeTarget(); |
204 | llvm::InitializeNativeTargetAsmPrinter(); |
205 | } |
206 | ~LLVMInitRAII() { llvm::llvm_shutdown(); } |
207 | } LLVMInit; |
208 | |
209 | #ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC |
210 | TEST(IncrementalProcessing, DISABLED_FindMangledNameSymbol) { |
211 | #else |
212 | TEST(IncrementalProcessing, FindMangledNameSymbol) { |
213 | #endif |
214 | |
215 | std::unique_ptr<Interpreter> Interp = createInterpreter(); |
216 | |
217 | auto &PTU(cantFail(ValOrErr: Interp->Parse(Code: "int f(const char*) {return 0;}" ))); |
218 | EXPECT_EQ(1U, DeclsSize(PTU.TUPart)); |
219 | auto R1DeclRange = PTU.TUPart->decls(); |
220 | |
221 | // We cannot execute on the platform. |
222 | if (!HostSupportsJit()) { |
223 | return; |
224 | } |
225 | |
226 | NamedDecl *FD = cast<FunctionDecl>(*R1DeclRange.begin()); |
227 | // Lower the PTU |
228 | if (llvm::Error Err = Interp->Execute(T&: PTU)) { |
229 | // We cannot execute on the platform. |
230 | consumeError(Err: std::move(Err)); |
231 | return; |
232 | } |
233 | |
234 | std::string MangledName = MangleName(ND: FD); |
235 | auto Addr = Interp->getSymbolAddress(IRName: MangledName); |
236 | EXPECT_FALSE(!Addr); |
237 | EXPECT_NE(0U, Addr->getValue()); |
238 | GlobalDecl GD(FD); |
239 | EXPECT_EQ(*Addr, cantFail(Interp->getSymbolAddress(GD))); |
240 | cantFail( |
241 | Err: Interp->ParseAndExecute(Code: "extern \"C\" int printf(const char*,...);" )); |
242 | Addr = Interp->getSymbolAddress(IRName: "printf" ); |
243 | EXPECT_FALSE(!Addr); |
244 | |
245 | // FIXME: Re-enable when we investigate the way we handle dllimports on Win. |
246 | #ifndef _WIN32 |
247 | EXPECT_EQ((uintptr_t)&printf, Addr->getValue()); |
248 | #endif // _WIN32 |
249 | } |
250 | |
251 | static Value AllocateObject(TypeDecl *TD, Interpreter &Interp) { |
252 | std::string Name = TD->getQualifiedNameAsString(); |
253 | Value Addr; |
254 | // FIXME: Consider providing an option in clang::Value to take ownership of |
255 | // the memory created from the interpreter. |
256 | // cantFail(Interp.ParseAndExecute("new " + Name + "()", &Addr)); |
257 | |
258 | // The lifetime of the temporary is extended by the clang::Value. |
259 | cantFail(Err: Interp.ParseAndExecute(Code: Name + "()" , V: &Addr)); |
260 | return Addr; |
261 | } |
262 | |
263 | static NamedDecl *LookupSingleName(Interpreter &Interp, const char *Name) { |
264 | Sema &SemaRef = Interp.getCompilerInstance()->getSema(); |
265 | ASTContext &C = SemaRef.getASTContext(); |
266 | DeclarationName DeclName = &C.Idents.get(Name); |
267 | LookupResult R(SemaRef, DeclName, SourceLocation(), Sema::LookupOrdinaryName); |
268 | SemaRef.LookupName(R, S: SemaRef.TUScope); |
269 | assert(!R.empty()); |
270 | return R.getFoundDecl(); |
271 | } |
272 | |
273 | #ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC |
274 | TEST(IncrementalProcessing, DISABLED_InstantiateTemplate) { |
275 | #else |
276 | TEST(IncrementalProcessing, InstantiateTemplate) { |
277 | #endif |
278 | // FIXME: We cannot yet handle delayed template parsing. If we run with |
279 | // -fdelayed-template-parsing we try adding the newly created decl to the |
280 | // active PTU which causes an assert. |
281 | std::vector<const char *> Args = {"-fno-delayed-template-parsing" }; |
282 | std::unique_ptr<Interpreter> Interp = createInterpreter(ExtraArgs: Args); |
283 | |
284 | llvm::cantFail(ValOrErr: Interp->Parse(Code: "extern \"C\" int printf(const char*,...);" |
285 | "class A {};" |
286 | "struct B {" |
287 | " template<typename T>" |
288 | " static int callme(T) { return 42; }" |
289 | "};" )); |
290 | auto &PTU = llvm::cantFail(ValOrErr: Interp->Parse(Code: "auto _t = &B::callme<A*>;" )); |
291 | auto PTUDeclRange = PTU.TUPart->decls(); |
292 | EXPECT_EQ(1, std::distance(PTUDeclRange.begin(), PTUDeclRange.end())); |
293 | |
294 | // We cannot execute on the platform. |
295 | if (!HostSupportsJit()) { |
296 | return; |
297 | } |
298 | |
299 | // Lower the PTU |
300 | if (llvm::Error Err = Interp->Execute(T&: PTU)) { |
301 | // We cannot execute on the platform. |
302 | consumeError(Err: std::move(Err)); |
303 | return; |
304 | } |
305 | |
306 | TypeDecl *TD = cast<TypeDecl>(Val: LookupSingleName(Interp&: *Interp, Name: "A" )); |
307 | Value NewA = AllocateObject(TD, Interp&: *Interp); |
308 | |
309 | // Find back the template specialization |
310 | VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin()); |
311 | UnaryOperator *UO = llvm::cast<UnaryOperator>(Val: VD->getInit()); |
312 | NamedDecl *TmpltSpec = llvm::cast<DeclRefExpr>(Val: UO->getSubExpr())->getDecl(); |
313 | |
314 | std::string MangledName = MangleName(ND: TmpltSpec); |
315 | typedef int (*TemplateSpecFn)(void *); |
316 | auto fn = |
317 | cantFail(ValOrErr: Interp->getSymbolAddress(IRName: MangledName)).toPtr<TemplateSpecFn>(); |
318 | EXPECT_EQ(42, fn(NewA.getPtr())); |
319 | } |
320 | |
321 | #ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC |
322 | TEST(InterpreterTest, DISABLED_Value) { |
323 | #else |
324 | TEST(InterpreterTest, Value) { |
325 | #endif |
326 | // We cannot execute on the platform. |
327 | if (!HostSupportsJit()) |
328 | return; |
329 | |
330 | std::unique_ptr<Interpreter> Interp = createInterpreter(); |
331 | |
332 | Value V1; |
333 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "int x = 42;" )); |
334 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "x" , V: &V1)); |
335 | EXPECT_TRUE(V1.isValid()); |
336 | EXPECT_TRUE(V1.hasValue()); |
337 | EXPECT_EQ(V1.getInt(), 42); |
338 | EXPECT_EQ(V1.convertTo<int>(), 42); |
339 | EXPECT_TRUE(V1.getType()->isIntegerType()); |
340 | EXPECT_EQ(V1.getKind(), Value::K_Int); |
341 | EXPECT_FALSE(V1.isManuallyAlloc()); |
342 | |
343 | Value V1b; |
344 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "char c = 42;" )); |
345 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "c" , V: &V1b)); |
346 | EXPECT_TRUE(V1b.getKind() == Value::K_Char_S || |
347 | V1b.getKind() == Value::K_Char_U); |
348 | |
349 | Value V2; |
350 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "double y = 3.14;" )); |
351 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "y" , V: &V2)); |
352 | EXPECT_TRUE(V2.isValid()); |
353 | EXPECT_TRUE(V2.hasValue()); |
354 | EXPECT_EQ(V2.getDouble(), 3.14); |
355 | EXPECT_EQ(V2.convertTo<double>(), 3.14); |
356 | EXPECT_TRUE(V2.getType()->isFloatingType()); |
357 | EXPECT_EQ(V2.getKind(), Value::K_Double); |
358 | EXPECT_FALSE(V2.isManuallyAlloc()); |
359 | |
360 | Value V3; |
361 | llvm::cantFail(Err: Interp->ParseAndExecute( |
362 | Code: "struct S { int* p; S() { p = new int(42); } ~S() { delete p; }};" )); |
363 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "S{}" , V: &V3)); |
364 | EXPECT_TRUE(V3.isValid()); |
365 | EXPECT_TRUE(V3.hasValue()); |
366 | EXPECT_TRUE(V3.getType()->isRecordType()); |
367 | EXPECT_EQ(V3.getKind(), Value::K_PtrOrObj); |
368 | EXPECT_TRUE(V3.isManuallyAlloc()); |
369 | |
370 | Value V4; |
371 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "int getGlobal();" )); |
372 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "void setGlobal(int);" )); |
373 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "getGlobal()" , V: &V4)); |
374 | EXPECT_EQ(V4.getInt(), 42); |
375 | EXPECT_TRUE(V4.getType()->isIntegerType()); |
376 | |
377 | Value V5; |
378 | // Change the global from the compiled code. |
379 | setGlobal(43); |
380 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "getGlobal()" , V: &V5)); |
381 | EXPECT_EQ(V5.getInt(), 43); |
382 | EXPECT_TRUE(V5.getType()->isIntegerType()); |
383 | |
384 | // Change the global from the interpreted code. |
385 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "setGlobal(44);" )); |
386 | EXPECT_EQ(getGlobal(), 44); |
387 | |
388 | Value V6; |
389 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "void foo() {}" )); |
390 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "foo()" , V: &V6)); |
391 | EXPECT_TRUE(V6.isValid()); |
392 | EXPECT_FALSE(V6.hasValue()); |
393 | EXPECT_TRUE(V6.getType()->isVoidType()); |
394 | EXPECT_EQ(V6.getKind(), Value::K_Void); |
395 | EXPECT_FALSE(V2.isManuallyAlloc()); |
396 | |
397 | Value V7; |
398 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "foo" , V: &V7)); |
399 | EXPECT_TRUE(V7.isValid()); |
400 | EXPECT_TRUE(V7.hasValue()); |
401 | EXPECT_TRUE(V7.getType()->isFunctionProtoType()); |
402 | EXPECT_EQ(V7.getKind(), Value::K_PtrOrObj); |
403 | EXPECT_FALSE(V7.isManuallyAlloc()); |
404 | |
405 | Value V8; |
406 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "struct SS{ void f() {} };" )); |
407 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "&SS::f" , V: &V8)); |
408 | EXPECT_TRUE(V8.isValid()); |
409 | EXPECT_TRUE(V8.hasValue()); |
410 | EXPECT_TRUE(V8.getType()->isMemberFunctionPointerType()); |
411 | EXPECT_EQ(V8.getKind(), Value::K_PtrOrObj); |
412 | EXPECT_TRUE(V8.isManuallyAlloc()); |
413 | |
414 | Value V9; |
415 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "struct A { virtual int f(); };" )); |
416 | llvm::cantFail( |
417 | Err: Interp->ParseAndExecute(Code: "struct B : A { int f() { return 42; }};" )); |
418 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "int (B::*ptr)() = &B::f;" )); |
419 | llvm::cantFail(Err: Interp->ParseAndExecute(Code: "ptr" , V: &V9)); |
420 | EXPECT_TRUE(V9.isValid()); |
421 | EXPECT_TRUE(V9.hasValue()); |
422 | EXPECT_TRUE(V9.getType()->isMemberFunctionPointerType()); |
423 | EXPECT_EQ(V9.getKind(), Value::K_PtrOrObj); |
424 | EXPECT_TRUE(V9.isManuallyAlloc()); |
425 | } |
426 | } // end anonymous namespace |
427 | |