brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.5 KiB · 9ff9092 Raw
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