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