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