junaire updated this revision to Diff 513024.
junaire added a comment.

Update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146809/new/

https://reviews.llvm.org/D146809

Files:
  clang/include/clang/Interpreter/Interpreter.h
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
  clang/lib/Interpreter/CMakeLists.txt
  clang/lib/Interpreter/IncrementalExecutor.cpp
  clang/lib/Interpreter/IncrementalExecutor.h
  clang/lib/Interpreter/IncrementalParser.h
  clang/lib/Interpreter/Interpreter.cpp
  clang/lib/Interpreter/InterpreterUtils.cpp
  clang/lib/Interpreter/InterpreterUtils.h
  clang/lib/Interpreter/Value.cpp
  clang/lib/Interpreter/ValuePrinter.cpp
  clang/test/Interpreter/pretty-print.cpp

Index: clang/test/Interpreter/pretty-print.cpp
===================================================================
--- /dev/null
+++ clang/test/Interpreter/pretty-print.cpp
@@ -0,0 +1,51 @@
+// RUN: clang-repl "int i = 10;" 'extern "C" int printf(const char*,...);' \
+// RUN:            'auto r1 = printf("i = %d\n", i);' | FileCheck --check-prefix=CHECK-DRIVER %s
+// UNSUPPORTED: system-aix
+// CHECK-DRIVER: i = 10
+// RUN: cat %s | clang-repl | FileCheck %s
+char c = 'a';
+c
+// CHECK: (char) 'a'
+
+int x = 42;
+x
+// CHECK-NEXT: (int) 42
+
+x - 2
+// CHECK-NEXT: (int) 40
+
+float f = 4.2f;
+f
+// CHECK-NEXT: (float) 4.20000f
+
+double d = 4.21;
+d
+// CHECK-NEXT: (double) 4.21000000000
+
+struct S{};
+S s;
+s
+// CHECK-NEXT: (S &) [[Addr:@0x.*]]
+
+S{}
+// CHECK-NEXT: (S) [[Addr:@0x.*]]
+
+struct SS { int* p; SS() { p = new int(42); } ~SS() { delete p; } };
+SS{}
+// CHECK-NEXT: (SS) [[Addr:@0x.*]]
+SS ss;
+ss
+// CHECK-NEXT: (SS &) [[Addr:@0x.*]]
+
+int arr[3] = {1,2,3};
+arr
+// CHECK-NEXT: (int[3]) { 1, 2, 3 }
+
+#include <memory>
+
+auto p1 = std::make_shared<int>(42);
+p1
+// CHECK-NEXT: (shared_ptr<int> &) std::shared_ptr -> [[Addr:@0x.*]]
+
+%quit
+
Index: clang/lib/Interpreter/ValuePrinter.cpp
===================================================================
--- /dev/null
+++ clang/lib/Interpreter/ValuePrinter.cpp
@@ -0,0 +1,507 @@
+#include "InterpreterUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Interpreter/Interpreter.h"
+#include "clang/Interpreter/Value.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <string>
+
+using namespace clang;
+
+namespace rep_runtime_internal {
+REPL_EXTERNAL_VISIBILITY
+extern const char *const kEmptyCollection = "{}";
+} // namespace rep_runtime_internal
+
+static std::string PrintDeclType(const QualType &QT, NamedDecl *D) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  if (QT.hasQualifiers())
+    SS << QT.getQualifiers().getAsString() << " ";
+  SS << D->getQualifiedNameAsString();
+  return Str;
+}
+
+static std::string PrintQualType(ASTContext &Ctx, QualType QT) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  PrintingPolicy Policy(Ctx.getPrintingPolicy());
+  // Print the Allocator in STL containers, for instance.
+  Policy.SuppressDefaultTemplateArgs = false;
+  Policy.SuppressUnwrittenScope = true;
+  // Print 'a<b<c> >' rather than 'a<b<c>>'.
+  Policy.SplitTemplateClosers = true;
+
+  struct LocalPrintingPolicyRAII {
+    ASTContext &Context;
+    PrintingPolicy Policy;
+
+    LocalPrintingPolicyRAII(ASTContext &Ctx, PrintingPolicy &PP)
+        : Context(Ctx), Policy(Ctx.getPrintingPolicy()) {
+      Context.setPrintingPolicy(PP);
+    }
+    ~LocalPrintingPolicyRAII() { Context.setPrintingPolicy(Policy); }
+  } X(Ctx, Policy);
+
+  const QualType NonRefTy = QT.getNonReferenceType();
+
+  if (const auto *TTy = llvm::dyn_cast<TagType>(NonRefTy))
+    SS << PrintDeclType(NonRefTy, TTy->getDecl());
+  else if (const auto *TRy = dyn_cast<RecordType>(NonRefTy))
+    SS << PrintDeclType(NonRefTy, TRy->getDecl());
+  else {
+    const QualType Canon = NonRefTy.getCanonicalType();
+    if (Canon->isBuiltinType() && !NonRefTy->isFunctionPointerType() &&
+        !NonRefTy->isMemberPointerType()) {
+      SS << Canon.getAsString(Ctx.getPrintingPolicy());
+    } else if (const auto *TDTy = dyn_cast<TypedefType>(NonRefTy)) {
+      // FIXME: TemplateSpecializationType & SubstTemplateTypeParmType checks
+      // are predominately to get STL containers to print nicer and might be
+      // better handled in GetFullyQualifiedName.
+      //
+      // std::vector<Type>::iterator is a TemplateSpecializationType
+      // std::vector<Type>::value_type is a SubstTemplateTypeParmType
+      //
+      QualType SSDesugar = TDTy->getLocallyUnqualifiedSingleStepDesugaredType();
+      if (llvm::isa<SubstTemplateTypeParmType>(SSDesugar))
+        SS << GetFullTypeName(Ctx, Canon);
+      else if (llvm::isa<TemplateSpecializationType>(SSDesugar))
+        SS << GetFullTypeName(Ctx, NonRefTy);
+      else
+        SS << PrintDeclType(NonRefTy, TDTy->getDecl());
+    } else
+      SS << GetFullTypeName(Ctx, NonRefTy);
+  }
+
+  if (QT->isReferenceType())
+    SS << " &";
+
+  return Str;
+}
+
+std::string PrintType(const Value &V) {
+  ASTContext &Ctx = V.getASTContext();
+  QualType QT = V.getType();
+
+  return PrintQualType(Ctx, QT);
+}
+
+static std::string PrintEnum(const Value &V) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  ASTContext &Ctx = V.getASTContext();
+
+  QualType DesugaredTy = V.getType().getDesugaredType(Ctx);
+  const EnumType *EnumTy = DesugaredTy.getNonReferenceType()->getAs<EnumType>();
+  assert(EnumTy && "Fail to cast to enum type");
+
+  EnumDecl *ED = EnumTy->getDecl();
+  uint64_t Data = V.getULongLong();
+  bool IsFirst = true;
+  llvm::APSInt AP = Ctx.MakeIntValue(Data, DesugaredTy);
+
+  for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) {
+    if (I->getInitVal() == AP) {
+      if (!IsFirst)
+        SS << " ? ";
+      SS << "(" + I->getQualifiedNameAsString() << ")";
+      IsFirst = false;
+    }
+  }
+
+  SS << " : " << PrintQualType(Ctx, ED->getIntegerType()) << " "
+     << llvm::toString(AP, /*Radix=*/10);
+  return Str;
+}
+
+static std::string PrintAddress(const void *Ptr, char Prefix) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  if (!Ptr)
+    return Str;
+  SS << Prefix << Ptr;
+  return Str;
+}
+
+// TODO: Encodings.
+static std::string PrintOneChar(char Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+
+  SS << "'" << Val << "'";
+  return Str;
+}
+// Char pointers
+// Assumption is this is a string.
+// N is limit to prevent endless loop if Ptr is not really a string.
+static std::string PrintString(const char *const *Ptr, size_t N = 10000) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+
+  const char *Start = *Ptr;
+  if (!Start)
+    return "nullptr";
+
+  const char *End = Start + N;
+  // If we're gonnd do this, better make sure the end is valid too
+  // FIXME: getpagesize() & GetSystemInfo().dwPageSize might be better
+  static constexpr auto PAGE_SIZE = 1024;
+  while (N > 1024) {
+    N -= PAGE_SIZE;
+    End = Start + N;
+  }
+
+  // if (*Start == 0)
+  //   return "\"\"";
+
+  // // Copy the bytes until we get a null-terminator
+  // SS << "\"";
+  // while (Start < End && *Start)
+  //   SS << *Start++;
+  // SS << "\"";
+
+  return Str;
+}
+// Build the CallExpr to `PrintValueRuntime`.
+static void BuildWrapperBody(Interpreter &Interp, Sema &S, ASTContext &Ctx,
+                             FunctionDecl *WrapperFD, QualType QT,
+                             const void *ValPtr) {
+  Sema::SynthesizedFunctionScope SemaFScope(S, WrapperFD);
+  clang::Parser::ParseScope PS(
+      &Interp.getParser(), clang::Scope::FnScope | clang::Scope::BlockScope);
+
+  clang::DeclarationName RuntimeCallName =
+      S.PP.getIdentifierInfo("PrintValueRuntime");
+  clang::LookupResult R(S, RuntimeCallName, SourceLocation(),
+                        clang::Sema::LookupOrdinaryName);
+  S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
+
+  Expr *OverldExpr = UnresolvedLookupExpr::Create(
+      Ctx, /*NamingClass=*/nullptr, NestedNameSpecifierLoc(),
+      clang::DeclarationNameInfo(RuntimeCallName, SourceLocation()),
+      /*RequiresADL*/ false, R.isOverloadedResult(), R.begin(), R.end());
+
+  // For `auto foo = bar;` decls, we are interested in the deduced type, i.e.
+  // AutoType 0x55e5ac848030 'int *' sugar
+  // `-PointerType 0x55e5ac847f70 'int *' << this type
+  //   `-BuiltinType 0x55e5ab517420 'int'
+  if (const auto *AT = llvm::dyn_cast<AutoType>(QT.getTypePtr())) {
+    if (AT->isDeduced())
+      QT = AT->getDeducedType();
+  }
+
+  if (const auto *PT = llvm::dyn_cast<PointerType>(QT.getTypePtr())) {
+    // Normalize `X*` to `const void*`, invoke `printValue(const void**)`,
+    // unless it's a character string.
+    QualType QTPointeeUnqual = PT->getPointeeType().getUnqualifiedType();
+    if (!Ctx.hasSameType(QTPointeeUnqual, Ctx.CharTy) &&
+        !Ctx.hasSameType(QTPointeeUnqual, Ctx.WCharTy) &&
+        !Ctx.hasSameType(QTPointeeUnqual, Ctx.Char16Ty) &&
+        !Ctx.hasSameType(QTPointeeUnqual, Ctx.Char32Ty)) {
+      QT = Ctx.getPointerType(Ctx.VoidTy.withConst());
+    }
+  } else if (const auto *RTy = llvm::dyn_cast<ReferenceType>(QT.getTypePtr())) {
+    // X& will be printed as X* (the pointer will be added below).
+    QT = RTy->getPointeeType();
+    // Val will be a X**, but we cast this to X*, so dereference here:
+    ValPtr = *(const void *const *)ValPtr;
+  }
+
+  // `PrintValueRuntime()` takes the *address* of the value to be printed:
+  QualType QTPtr = Ctx.getPointerType(QT);
+  Expr *TypeArg = CStyleCastPtrExpr(S, QTPtr, (uintptr_t)ValPtr);
+  llvm::SmallVector<Expr *, 1> CallArgs = {TypeArg};
+
+  // Create the CallExpr.
+  ExprResult RuntimeCall =
+      S.ActOnCallExpr(S.getCurScope(), OverldExpr, SourceLocation(), CallArgs,
+                      SourceLocation());
+  assert(!RuntimeCall.isInvalid() && "Cannot create call to PrintValueRuntime");
+
+  // Create the ReturnStmt.
+  StmtResult RetStmt =
+      S.ActOnReturnStmt(SourceLocation(), RuntimeCall.get(), S.getCurScope());
+  assert(!RetStmt.isInvalid() && "Cannot create ReturnStmt");
+
+  // Create the CompoundStmt.
+  StmtResult Body =
+      CompoundStmt::Create(Ctx, {RetStmt.get()}, FPOptionsOverride(),
+                           SourceLocation(), SourceLocation());
+  assert(!Body.isInvalid() && "Cannot create function body");
+
+  WrapperFD->setBody(Body.get());
+  // Add attribute `__attribute__((used))`.
+  WrapperFD->addAttr(UsedAttr::CreateImplicit(Ctx));
+}
+
+static constexpr const char *const WrapperName = "__InterpreterCallPrint";
+
+static std::string SynthesizeRuntimePrint(const Value &V) {
+  Interpreter &Interp = V.getInterpreter();
+  Sema &S = Interp.getCompilerInstance()->getSema();
+  ASTContext &Ctx = S.getASTContext();
+
+  // Only include once when the first time we need it. Technically speaking it's
+  // fine to include it several times since we have the header guard, but we
+  // still need to parse it, which is relatively expensive.
+  static bool Included = false;
+  if (!Included) {
+    Included = true;
+    llvm::cantFail(Interp.Parse(
+        "#include <__clang_interpreter_runtime_printvalue.h>"));
+  }
+  // Lookup std::string.
+  NamespaceDecl *Std = LookupNamespace(S, "std");
+  assert(Std && "Cannot find namespace std");
+  Decl *StdStringDecl = LookupNamed(S, "string", Std);
+  assert(StdStringDecl && "Cannot find std::string");
+  const auto *StdStringTyDecl = llvm::dyn_cast<TypeDecl>(StdStringDecl);
+  assert(StdStringTyDecl && "Cannot find type of std::string");
+
+  // Create the wrapper function.
+  DeclarationName DeclName =
+      &Ctx.Idents.get(Interp.CreateUniqName(WrapperName));
+  QualType RetTy(StdStringTyDecl->getTypeForDecl(), 0);
+  QualType FnTy =
+      Ctx.getFunctionType(RetTy, {}, FunctionProtoType::ExtProtoInfo());
+  auto *WrapperFD = FunctionDecl::Create(
+      Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+      DeclName, FnTy, Ctx.getTrivialTypeSourceInfo(FnTy), SC_None);
+
+  const void *ValPtr = V.getPtr();
+  if (!V.isManuallyAlloc())
+    ValPtr = &ValPtr;
+
+  BuildWrapperBody(Interp, S, Ctx, WrapperFD, V.getType(), ValPtr);
+
+  auto AddrOrErr = Interp.CompileDecl(WrapperFD);
+  if (!AddrOrErr)
+    llvm::logAllUnhandledErrors(AddrOrErr.takeError(), llvm::errs(),
+                                "Fail to get symbol address");
+  if (auto *Main =
+          llvm::jitTargetAddressToPointer<std::string (*)()>(AddrOrErr.get()))
+    return (*Main)();
+  return "Error to print the value!";
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const void *Ptr) {
+  return PrintAddress(Ptr, '@');
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const void **Ptr) {
+  return PrintAddress(*Ptr, '@');
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const bool *Val) {
+  if (*Val)
+    return "true";
+  return "false";
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char *Val) {
+  return PrintOneChar(*Val);
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const signed char *Val) {
+  return PrintOneChar(*Val);
+}
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned char *Val) {
+  return PrintOneChar(*Val);
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const short *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned short *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const int *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned int *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long long *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned long *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned long long *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << *Val;
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const float *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << llvm::format("%#.6g", *Val) << 'f';
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const double *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << llvm::format("%#.12g", *Val);
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long double *Val) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << llvm::format("%#.8Lg", *Val) << 'L';
+  return Str;
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char *const *Val) {
+  return PrintString(Val);
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char **Val) {
+  return PrintString(Val);
+}
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const std::string *Val) {
+  return "\"" + *Val + "\"";
+}
+
+template <typename T> static std::string PrintValueWrapper(const T &Val) {
+  return PrintValueRuntime(&Val);
+}
+
+std::string PrintData(const Value &V) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+
+  QualType QT = V.getType();
+  QualType DesugaredTy = QT.getDesugaredType(V.getASTContext());
+  QualType NonRefTy = DesugaredTy.getNonReferenceType();
+
+  if (NonRefTy->isNullPtrType()) {
+    SS << "nullptr\n";
+  } else if (NonRefTy->isEnumeralType()) {
+    return PrintEnum(V);
+  } else if (NonRefTy->isFunctionType()) {
+    llvm_unreachable("Not implemented yet");
+  } else if ((NonRefTy->isPointerType() || NonRefTy->isMemberPointerType()) &&
+             NonRefTy->getPointeeType()->isFunctionProtoType()) {
+    // Function pointer.
+    llvm_unreachable("Not implemented yet");
+  } else if (auto *BT = DesugaredTy.getCanonicalType()->getAs<BuiltinType>()) {
+    switch (BT->getKind()) {
+    case BuiltinType::Bool: {
+      SS << PrintValueWrapper(V.getBool());
+      break;
+    }
+    case BuiltinType::Char_S:
+    case BuiltinType::SChar: {
+      SS << PrintValueWrapper(V.getSChar());
+      break;
+    }
+    case BuiltinType::Short: {
+      SS << PrintValueWrapper(V.getShort());
+      break;
+    }
+    case BuiltinType::Int: {
+      SS << PrintValueWrapper(V.getInt());
+      break;
+    }
+    case BuiltinType::Long: {
+      SS << PrintValueWrapper(V.getLong());
+      break;
+    }
+    case BuiltinType::LongLong: {
+      SS << PrintValueWrapper(V.getLongLong());
+      break;
+    }
+    case BuiltinType::Char_U:
+    case BuiltinType::UChar: {
+      SS << PrintValueWrapper(V.getUChar());
+      break;
+    }
+    case BuiltinType::UShort: {
+      SS << PrintValueWrapper(V.getUShort());
+      break;
+    }
+    case BuiltinType::UInt: {
+      SS << PrintValueWrapper(V.getUInt());
+      break;
+    }
+    case BuiltinType::ULong: {
+      SS << PrintValueWrapper(V.getULong());
+      break;
+    }
+    case BuiltinType::ULongLong: {
+      SS << PrintValueWrapper(V.getULongLong());
+      break;
+    }
+    case BuiltinType::Float: {
+      SS << PrintValueWrapper(V.getFloat());
+      break;
+    }
+    case BuiltinType::Double: {
+      SS << PrintValueWrapper(V.getDouble());
+      break;
+    }
+    case BuiltinType::LongDouble: {
+      SS << PrintValueWrapper(V.getLongDouble());
+      break;
+    }
+    default:
+      llvm_unreachable("Unknown Builtintype kind");
+    }
+  } else if (auto *CXXRD = NonRefTy->getAsCXXRecordDecl();
+             CXXRD && CXXRD->isLambda()) {
+    SS << PrintAddress(V.getPtr(), '@');
+  } else {
+    // All fails then generate a runtime call, this is slow.
+    SS << SynthesizeRuntimePrint(V);
+  }
+  return Str;
+}
Index: clang/lib/Interpreter/Value.cpp
===================================================================
--- clang/lib/Interpreter/Value.cpp
+++ clang/lib/Interpreter/Value.cpp
@@ -240,13 +240,25 @@
 
 void Value::dump() const { print(llvm::outs()); }
 
-void Value::printType(llvm::raw_ostream &Out) const {
-  Out << "Not implement yet.\n";
-}
-void Value::printData(llvm::raw_ostream &Out) const {
-  Out << "Not implement yet.\n";
-}
+// Put them in the header!
+std::string PrintType(const Value &V);
+std::string PrintData(const Value &V);
+
+void Value::printType(llvm::raw_ostream &Out) const { Out << PrintType(*this); }
+
+void Value::printData(llvm::raw_ostream &Out) const { Out << PrintData(*this); }
+
 void Value::print(llvm::raw_ostream &Out) const {
   assert(OpaqueType != nullptr && "Can't print default Value");
-  Out << "Not implement yet.\n";
+  // We need to get all the results together then print it, since `printType` is
+  // much faster than `printData`.
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+
+  SS << "(";
+  printType(SS);
+  SS << ") ";
+  printData(SS);
+  SS << "\n";
+  Out << Str;
 }
Index: clang/lib/Interpreter/InterpreterUtils.h
===================================================================
--- clang/lib/Interpreter/InterpreterUtils.h
+++ clang/lib/Interpreter/InterpreterUtils.h
@@ -49,6 +49,19 @@
 NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
                        const DeclContext *Within);
 
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const NamespaceDecl *Namesp);
+
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const TypedefNameDecl *TD,
+                                               bool FullyQualify);
+
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const TagDecl *TD,
+                                               bool FullyQualify);
+
+QualType GetFullyQualifiedType(QualType QT, const ASTContext &Ctx);
+
 std::string GetFullTypeName(ASTContext &Ctx, QualType QT);
 } // namespace clang
 
Index: clang/lib/Interpreter/InterpreterUtils.cpp
===================================================================
--- clang/lib/Interpreter/InterpreterUtils.cpp
+++ clang/lib/Interpreter/InterpreterUtils.cpp
@@ -102,10 +102,408 @@
   return nullptr;
 }
 
+static NestedNameSpecifier *CreateOuterNNS(const ASTContext &Ctx, const Decl *D,
+                                           bool FullyQualify) {
+  const DeclContext *DC = D->getDeclContext();
+  if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+    while (NS && NS->isInline()) {
+      // Ignore inline namespace;
+      NS = dyn_cast_or_null<NamespaceDecl>(NS->getDeclContext());
+    }
+    if (NS && NS->getDeclName())
+      return CreateNestedNameSpecifier(Ctx, NS);
+    return nullptr; // no starting '::', no anonymous
+  }
+  if (const auto *TD = dyn_cast<TagDecl>(DC)) {
+    return CreateNestedNameSpecifier(Ctx, TD, FullyQualify);
+  }
+  if (const TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(DC)) {
+    return CreateNestedNameSpecifier(Ctx, TDD, FullyQualify);
+  }
+  return nullptr; // no starting '::'
+}
+
+static NestedNameSpecifier *
+CreateNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *D,
+                                    bool FullyQualified) {
+  // Create a nested name specifier for the declaring context of the type.
+
+  assert(D);
+
+  const NamedDecl *Outer =
+      llvm::dyn_cast_or_null<NamedDecl>(D->getDeclContext());
+  const NamespaceDecl *OuterNs =
+      llvm::dyn_cast_or_null<NamespaceDecl>(D->getDeclContext());
+  if (Outer && !(OuterNs && OuterNs->isAnonymousNamespace())) {
+
+    if (const CXXRecordDecl *CXXD =
+            llvm::dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+
+      if (ClassTemplateDecl *clTempl = CXXD->getDescribedClassTemplate()) {
+        // We are in the case of a type(def) that was declared in a
+        // class template but is *not* type dependent.  In clang, it gets
+        // attached to the class template declaration rather than any
+        // specific class template instantiation.   This result in 'odd'
+        // fully qualified typename:
+        //    vector<_Tp,_Alloc>::size_type
+        // Make the situation is 'useable' but looking a bit odd by
+        // picking a random instance as the declaring context.
+        // FIXME: We should not use the iterators here to check if we are in
+        // a template specialization. clTempl != cxxdecl already tell us that
+        // is the case. It seems that we rely on a side-effect from triggering
+        // deserializations to support 'some' use-case. See ROOT-9709.
+        if (clTempl->spec_begin() != clTempl->spec_end()) {
+          D = *(clTempl->spec_begin());
+          Outer = llvm::dyn_cast<NamedDecl>(D);
+          OuterNs = llvm::dyn_cast<NamespaceDecl>(D);
+        }
+      }
+    }
+
+    if (OuterNs) {
+      return CreateNestedNameSpecifier(Ctx, OuterNs);
+    }
+    if (const auto *TD = llvm::dyn_cast<TagDecl>(Outer)) {
+      return CreateNestedNameSpecifier(Ctx, TD, FullyQualified);
+    }
+  }
+  return nullptr;
+}
+
+static NestedNameSpecifier *
+CreateNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr,
+                                    bool FullyQualified) {
+  // Create a nested name specifier for the declaring context of the type.
+
+  if (!TypePtr)
+    return nullptr;
+
+  Decl *D = nullptr;
+  if (const auto *TDT = llvm::dyn_cast<TypedefType>(TypePtr)) {
+    D = TDT->getDecl();
+  } else {
+    // There are probably other cases ...
+    if (const auto *TT = llvm::dyn_cast_or_null<TagType>(TypePtr))
+      D = TT->getDecl();
+    else
+      D = TypePtr->getAsCXXRecordDecl();
+  }
+
+  if (!D)
+    return nullptr;
+
+  return CreateNestedNameSpecifierForScopeOf(Ctx, D, FullyQualified);
+}
+
+static NestedNameSpecifier *
+GetFullyQualifiedNameSpecifier(const ASTContext &Ctx,
+                               NestedNameSpecifier *Scope) {
+  // Return a fully qualified version of this name specifier
+  if (Scope->getKind() == NestedNameSpecifier::Global) {
+    // Already fully qualified.
+    return Scope;
+  }
+
+  if (const Type *Type = Scope->getAsType()) {
+    // Find decl context.
+    const TagDecl *TD = nullptr;
+    if (const TagType *tagdecltype = dyn_cast<TagType>(Type)) {
+      TD = tagdecltype->getDecl();
+    } else {
+      TD = Type->getAsCXXRecordDecl();
+    }
+    if (TD) {
+      return CreateNestedNameSpecifier(Ctx, TD, true /*FullyQualified*/);
+    }
+    if (const TypedefType *TDD = dyn_cast<TypedefType>(Type)) {
+      return CreateNestedNameSpecifier(Ctx, TDD->getDecl(),
+                                       true /*FullyQualified*/);
+    }
+  } else if (const NamespaceDecl *NS = Scope->getAsNamespace()) {
+    return CreateNestedNameSpecifier(Ctx, NS);
+  } else if (const NamespaceAliasDecl *alias = Scope->getAsNamespaceAlias()) {
+    const NamespaceDecl *CanonNS = alias->getNamespace()->getCanonicalDecl();
+    return CreateNestedNameSpecifier(Ctx, CanonNS);
+  }
+
+  return Scope;
+}
+
+static bool GetFullyQualifiedTemplateName(const ASTContext &Ctx,
+                                          TemplateName &Name) {
+
+  bool Changed = false;
+  NestedNameSpecifier *NNS = nullptr;
+
+  TemplateDecl *TD = Name.getAsTemplateDecl();
+  QualifiedTemplateName *qtname = Name.getAsQualifiedTemplateName();
+
+  if (qtname && !qtname->hasTemplateKeyword()) {
+    NNS = qtname->getQualifier();
+    NestedNameSpecifier *qNNS = GetFullyQualifiedNameSpecifier(Ctx, NNS);
+    if (qNNS != NNS) {
+      Changed = true;
+      NNS = qNNS;
+    } else {
+      NNS = nullptr;
+    }
+  } else {
+    NNS = CreateNestedNameSpecifierForScopeOf(Ctx, TD, true);
+  }
+  if (NNS) {
+    Name = Ctx.getQualifiedTemplateName(NNS,
+                                        /*TemplateKeyword=*/false,
+                                        TemplateName(TD));
+    Changed = true;
+  }
+  return Changed;
+}
+
+static bool GetFullyQualifiedTemplateArgument(const ASTContext &Ctx,
+                                              TemplateArgument &Arg) {
+  bool Changed = false;
+
+  // Note: we do not handle TemplateArgument::Expression, to replace it
+  // we need the information for the template instance decl.
+  // See GetPartiallyDesugaredTypeImpl
+
+  if (Arg.getKind() == TemplateArgument::Template) {
+    TemplateName Name = Arg.getAsTemplate();
+    Changed = GetFullyQualifiedTemplateName(Ctx, Name);
+    if (Changed) {
+      Arg = TemplateArgument(Name);
+    }
+  } else if (Arg.getKind() == TemplateArgument::Type) {
+    QualType SubTy = Arg.getAsType();
+    // Check if the type needs more desugaring and recurse.
+    QualType QTFQ = GetFullyQualifiedType(SubTy, Ctx);
+    if (QTFQ != SubTy) {
+      Arg = TemplateArgument(QTFQ);
+      Changed = true;
+    }
+  } else if (Arg.getKind() == TemplateArgument::Pack) {
+    SmallVector<TemplateArgument, 2> desArgs;
+    for (auto I = Arg.pack_begin(), E = Arg.pack_end(); I != E; ++I) {
+      TemplateArgument PackArg(*I);
+      Changed = GetFullyQualifiedTemplateArgument(Ctx, PackArg);
+      desArgs.push_back(PackArg);
+    }
+    if (Changed) {
+      // The allocator in ASTContext is mutable ...
+      // Keep the argument const to be inline will all the other interfaces
+      // like:  NestedNameSpecifier::Create
+      ASTContext &MutableCtx(const_cast<ASTContext &>(Ctx));
+      Arg = TemplateArgument::CreatePackCopy(MutableCtx, desArgs);
+    }
+  }
+  return Changed;
+}
+
+static const Type *GetFullyQualifiedLocalType(const ASTContext &Ctx,
+                                              const Type *Typeptr) {
+  // We really just want to handle the template parameter if any ....
+  // In case of template specializations iterate over the arguments and
+  // fully qualify them as well.
+  if (const auto *TST =
+          llvm::dyn_cast<const TemplateSpecializationType>(Typeptr)) {
+
+    bool MightHaveChanged = false;
+    llvm::SmallVector<TemplateArgument, 4> desArgs;
+    for (auto &I : TST->template_arguments()) {
+
+      // cheap to copy and potentially modified by
+      // GetFullyQualifedTemplateArgument
+      TemplateArgument arg(I);
+      MightHaveChanged |= GetFullyQualifiedTemplateArgument(Ctx, arg);
+      desArgs.push_back(arg);
+    }
+
+    // If desugaring happened allocate new type in the AST.
+    if (MightHaveChanged) {
+      QualType QT = Ctx.getTemplateSpecializationType(
+          TST->getTemplateName(), desArgs, TST->getCanonicalTypeInternal());
+      return QT.getTypePtr();
+    }
+  } else if (const auto *TSTRecord =
+                 llvm::dyn_cast<const RecordType>(Typeptr)) {
+    // We are asked to fully qualify and we have a Record Type,
+    // which can point to a template instantiation with no sugar in any of
+    // its template argument, however we still need to fully qualify them.
+
+    if (const auto *TSTdecl = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
+            TSTRecord->getDecl())) {
+      const TemplateArgumentList &templateArgs = TSTdecl->getTemplateArgs();
+
+      bool MightHaveChanged = false;
+      llvm::SmallVector<TemplateArgument, 4> desArgs;
+      for (unsigned int I = 0, E = templateArgs.size(); I != E; ++I) {
+
+        // cheap to copy and potentially modified by
+        // GetFullyQualifedTemplateArgument
+        TemplateArgument arg(templateArgs[I]);
+        MightHaveChanged |= GetFullyQualifiedTemplateArgument(Ctx, arg);
+        desArgs.push_back(arg);
+      }
+
+      // If desugaring happened allocate new type in the AST.
+      if (MightHaveChanged) {
+        TemplateName TN(TSTdecl->getSpecializedTemplate());
+        QualType QT = Ctx.getTemplateSpecializationType(
+            TN, desArgs, TSTRecord->getCanonicalTypeInternal());
+        return QT.getTypePtr();
+      }
+    }
+  }
+  return Typeptr;
+}
+
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const NamespaceDecl *NSD) {
+  while (NSD && NSD->isInline()) {
+    // Ignore inline namespace;
+    NSD = dyn_cast_or_null<NamespaceDecl>(NSD->getDeclContext());
+  }
+  if (!NSD)
+    return nullptr;
+
+  bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces
+  return NestedNameSpecifier::Create(
+      Ctx, CreateOuterNNS(Ctx, NSD, FullyQualified), NSD);
+}
+
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const TypedefNameDecl *TD,
+                                               bool FullyQualify) {
+  return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, TD, FullyQualify),
+                                     /*Template=*/true, TD->getTypeForDecl());
+}
+
+NestedNameSpecifier *CreateNestedNameSpecifier(const ASTContext &Ctx,
+                                               const TagDecl *TD,
+                                               bool FullyQualify) {
+  const Type *Ty = Ctx.getTypeDeclType(TD).getTypePtr();
+  if (FullyQualify)
+    Ty = GetFullyQualifiedLocalType(Ctx, Ty);
+  return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, TD, FullyQualify),
+                                     /*Template=*/false, Ty);
+}
+
+QualType GetFullyQualifiedType(QualType QT, const ASTContext &Ctx) {
+  // Return the fully qualified type, if we need to recurse through any
+  // template parameter, this needs to be merged somehow with
+  // GetPartialDesugaredType.
+
+  // In case of myType* we need to strip the pointer first, fully qualifiy
+  // and attach the pointer once again.
+  if (llvm::isa<PointerType>(QT.getTypePtr())) {
+    // Get the qualifiers.
+    Qualifiers Quals = QT.getQualifiers();
+    QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx);
+    QT = Ctx.getPointerType(QT);
+    // Add back the qualifiers.
+    QT = Ctx.getQualifiedType(QT, Quals);
+    return QT;
+  }
+
+  // In case of myType& we need to strip the pointer first, fully qualifiy
+  // and attach the pointer once again.
+  if (llvm::isa<ReferenceType>(QT.getTypePtr())) {
+    // Get the qualifiers.
+    bool IsLValueRefTy = llvm::isa<LValueReferenceType>(QT.getTypePtr());
+    Qualifiers Quals = QT.getQualifiers();
+    QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx);
+    // Add the r- or l-value reference type back to the desugared one.
+    if (IsLValueRefTy)
+      QT = Ctx.getLValueReferenceType(QT);
+    else
+      QT = Ctx.getRValueReferenceType(QT);
+    // Add back the qualifiers.
+    QT = Ctx.getQualifiedType(QT, Quals);
+    return QT;
+  }
+
+  // Strip deduced types.
+  if (const auto *AutoTy = dyn_cast<AutoType>(QT.getTypePtr())) {
+    if (!AutoTy->getDeducedType().isNull())
+      return GetFullyQualifiedType(AutoTy->getDeducedType(), Ctx);
+  }
+
+  // Remove the part of the type related to the type being a template
+  // parameter (we won't report it as part of the 'type name' and it is
+  // actually make the code below to be more complex (to handle those)
+  while (llvm::isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
+    // Get the qualifiers.
+    Qualifiers Quals = QT.getQualifiers();
+
+    QT = llvm::cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
+
+    // Add back the qualifiers.
+    QT = Ctx.getQualifiedType(QT, Quals);
+  }
+
+  NestedNameSpecifier *Prefix = nullptr;
+  Qualifiers PrefixQualifiers;
+  if (const auto *EType = llvm::dyn_cast<ElaboratedType>(QT.getTypePtr())) {
+    // Intentionally, we do not care about the other compononent of
+    // the elaborated type (the keyword) as part of the partial
+    // desugaring (and/or name normalization) is to remove it.
+    Prefix = EType->getQualifier();
+    if (Prefix) {
+      const NamespaceDecl *NS = Prefix->getAsNamespace();
+      if (Prefix != NestedNameSpecifier::GlobalSpecifier(Ctx) &&
+          !(NS && NS->isAnonymousNamespace())) {
+        PrefixQualifiers = QT.getLocalQualifiers();
+        Prefix = GetFullyQualifiedNameSpecifier(Ctx, Prefix);
+        QT = QualType(EType->getNamedType().getTypePtr(), 0);
+      } else {
+        Prefix = nullptr;
+      }
+    }
+  } else {
+
+    // Create a nested name specifier if needed (i.e. if the decl context
+    // is not the global scope.
+    Prefix = CreateNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
+                                                 true /*FullyQualified*/);
+
+    // move the qualifiers on the outer type (avoid 'std::const string'!)
+    if (Prefix) {
+      PrefixQualifiers = QT.getLocalQualifiers();
+      QT = QualType(QT.getTypePtr(), 0);
+    }
+  }
+
+  // In case of template specializations iterate over the arguments and
+  // fully qualify them as well.
+  if (llvm::isa<const TemplateSpecializationType>(QT.getTypePtr())) {
+
+    Qualifiers Qualifiers = QT.getLocalQualifiers();
+    const Type *TypePtr = GetFullyQualifiedLocalType(Ctx, QT.getTypePtr());
+    QT = Ctx.getQualifiedType(TypePtr, Qualifiers);
+
+  } else if (llvm::isa<const RecordType>(QT.getTypePtr())) {
+    // We are asked to fully qualify and we have a Record Type,
+    // which can point to a template instantiation with no sugar in any of
+    // its template argument, however we still need to fully qualify them.
+
+    Qualifiers Qualifiers = QT.getLocalQualifiers();
+    const Type *TypePtr = GetFullyQualifiedLocalType(Ctx, QT.getTypePtr());
+    QT = Ctx.getQualifiedType(TypePtr, Qualifiers);
+  }
+  if (Prefix) {
+    // We intentionally always use ETK_None, we never want
+    // the keyword (humm ... what about anonymous types?)
+    QT = Ctx.getElaboratedType(ETK_None, Prefix, QT);
+    QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
+  }
+  return QT;
+}
+
 std::string GetFullTypeName(ASTContext &Ctx, QualType QT) {
+  QualType FQT = GetFullyQualifiedType(QT, Ctx);
   PrintingPolicy Policy(Ctx.getPrintingPolicy());
   Policy.SuppressScope = false;
   Policy.AnonymousTagLocations = false;
-  return QT.getAsString(Policy);
+  return FQT.getAsString(Policy);
 }
 } // namespace clang
Index: clang/lib/Interpreter/Interpreter.cpp
===================================================================
--- clang/lib/Interpreter/Interpreter.cpp
+++ clang/lib/Interpreter/Interpreter.cpp
@@ -33,6 +33,7 @@
 #include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "clang/Interpreter/Value.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Parse/Parser.h"
 #include "clang/Sema/Lookup.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
@@ -240,6 +241,8 @@
   return IncrParser->getCI();
 }
 
+Parser &Interpreter::getParser() const { return IncrParser->getParser(); }
+
 llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
   if (!IncrExecutor) {
     if (auto Err = CreateExecutor())
@@ -279,6 +282,22 @@
   return Err;
 }
 
+llvm::Error Interpreter::ExecuteModule(std::unique_ptr<llvm::Module> &M) {
+  if (!IncrExecutor) {
+    auto Err = CreateExecutor();
+    if (Err)
+      return Err;
+  }
+  // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
+  if (auto Err = IncrExecutor->addModule(M))
+    return Err;
+
+  if (auto Err = IncrExecutor->runCtors())
+    return Err;
+
+  return llvm::Error::success();
+}
+
 llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
   if (!IncrExecutor) {
     auto Err = CreateExecutor();
@@ -401,6 +420,37 @@
   return AddrOrErr;
 }
 
+std::unique_ptr<llvm::Module> Interpreter::GenModule() {
+  return IncrParser->GenModule();
+}
+
+llvm::Expected<llvm::JITTargetAddress> Interpreter::CompileDecl(Decl *D) {
+  assert(D && "The Decl being compiled can't be null");
+
+  ASTConsumer &Consumer = getCompilerInstance()->getASTConsumer();
+  Consumer.HandleTopLevelDecl(DeclGroupRef(D));
+  getCompilerInstance()->getSema().PerformPendingInstantiations();
+  Consumer.HandleTranslationUnit(getASTContext());
+
+  if (std::unique_ptr<llvm::Module> M = GenModule()) {
+    if (llvm::Error Err = ExecuteModule(M))
+      return Err;
+    ASTNameGenerator ASTNameGen(getASTContext());
+    llvm::Expected<llvm::JITTargetAddress> AddrOrErr =
+        getSymbolAddressFromLinkerName(ASTNameGen.getName(D));
+
+    return AddrOrErr;
+  }
+  return llvm::JITTargetAddress{};
+}
+
+std::string Interpreter::CreateUniqName(std::string Base) {
+  static size_t I = 0;
+  Base += std::to_string(I);
+  I += 1;
+  return Base;
+}
+
 static constexpr llvm::StringRef MagicRuntimeInterface[] = {
     "__InterpreterSetValueNoAlloc", "__InterpreterSetValueWithAlloc",
     "__InterpreterSetValueCopyArr"};
Index: clang/lib/Interpreter/IncrementalParser.h
===================================================================
--- clang/lib/Interpreter/IncrementalParser.h
+++ clang/lib/Interpreter/IncrementalParser.h
@@ -76,6 +76,8 @@
 
   std::list<PartialTranslationUnit> &getPTUs() { return PTUs; }
 
+  Parser &getParser() { return *P; }
+
   std::unique_ptr<llvm::Module> GenModule();
 
 private:
Index: clang/lib/Interpreter/IncrementalExecutor.h
===================================================================
--- clang/lib/Interpreter/IncrementalExecutor.h
+++ clang/lib/Interpreter/IncrementalExecutor.h
@@ -47,6 +47,7 @@
                       const clang::TargetInfo &TI);
   ~IncrementalExecutor();
 
+  llvm::Error addModule(std::unique_ptr<llvm::Module> &M);
   llvm::Error addModule(PartialTranslationUnit &PTU);
   llvm::Error removeModule(PartialTranslationUnit &PTU);
   llvm::Error runCtors() const;
Index: clang/lib/Interpreter/IncrementalExecutor.cpp
===================================================================
--- clang/lib/Interpreter/IncrementalExecutor.cpp
+++ clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -47,6 +47,10 @@
 
 IncrementalExecutor::~IncrementalExecutor() {}
 
+llvm::Error IncrementalExecutor::addModule(std::unique_ptr<llvm::Module> &M) {
+  return Jit->addIRModule({std::move(M), TSCtx});
+}
+
 llvm::Error IncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
   llvm::orc::ResourceTrackerSP RT =
       Jit->getMainJITDylib().createResourceTracker();
Index: clang/lib/Interpreter/CMakeLists.txt
===================================================================
--- clang/lib/Interpreter/CMakeLists.txt
+++ clang/lib/Interpreter/CMakeLists.txt
@@ -12,8 +12,9 @@
   IncrementalExecutor.cpp
   IncrementalParser.cpp
   Interpreter.cpp
-  Value.cpp
   InterpreterUtils.cpp
+  Value.cpp
+  ValuePrinter.cpp
 
   DEPENDS
   intrinsics_gen
Index: clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
===================================================================
--- /dev/null
+++ clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
@@ -0,0 +1,274 @@
+//===--- RuntimePrintValue.h - Incremental Compiation and Execution---*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines runtime functions used to print STL components in
+// clang-repl. They are very heavy so we should only include it once and on
+// demand.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
+#define LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
+
+#include <memory>
+#include <string>
+#include <type_traits>
+
+// We should include it somewhere instead of duplicating it...
+#if __has_attribute(visibility) &&                                             \
+    (!(defined(_WIN32) || defined(__CYGWIN__)) ||                              \
+     (defined(__MINGW32__) && defined(__clang__)))
+#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
+#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
+#else
+#define REPL_EXTERNAL_VISIBILITY
+#endif
+#else
+#if defined(_WIN32)
+#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
+#endif
+#endif
+
+// Below overloads are all defined in the library itself.
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const void *Ptr);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const void **Ptr);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const bool *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const signed char *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned char *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const short *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned short *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const int *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const unsigned int *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long long *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned long *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string
+PrintValueRuntime(const unsigned long long *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const float *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const double *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const long double *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char *const *Val);
+
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const char **Val);
+
+namespace rep_runtime_internal {
+REPL_EXTERNAL_VISIBILITY
+extern const char *const kEmptyCollection;
+} // namespace rep_runtime_internal
+
+namespace collections_printer_internal {
+
+// Forward declaration, so recursion of containers possible.
+template <typename T>
+REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const T *V,
+                                                       const void * = nullptr);
+
+template <typename T>
+inline std::string PrintValueRuntime(
+    const T &V,
+    typename std::enable_if_t<std::is_pointer_v<decltype(&V)>> * = nullptr) {
+  return PrintValueRuntime(&V);
+}
+
+template <typename T0, typename T1>
+inline std::string PrintValueRuntime(const std::pair<T1, T0> *V,
+                                     const void *AsMap = nullptr) {
+  if (AsMap)
+    return PrintValueRuntime(&V->first) + " => " +
+           PrintValueRuntime(&V->second);
+  return "{" + PrintValueRuntime(&V->first) + " , " +
+         PrintValueRuntime(&V->second) + "}";
+}
+
+// For std::vector<bool> elements
+inline std::string PrintValueRuntime(const bool &B, const void * = nullptr) {
+  return PrintValueRuntime(&B);
+}
+
+struct TypeTest {
+  template <class T>
+  static constexpr const void *
+  isMap(const T *M, const typename T::mapped_type *V = nullptr) {
+    return M;
+  }
+  static constexpr const void *isMap(const void *M) { return nullptr; }
+};
+
+// vector, set, deque etc.
+template <typename CollectionType>
+inline auto PrintValueRuntimeImpl(
+    const CollectionType *Obj,
+    typename std::enable_if_t<std::is_reference_v<decltype(*std::begin(*Obj))>>
+        * = nullptr) -> decltype(std::end(*Obj), std::string()) {
+  auto Iter = Obj->begin(), IterEnd = Obj->end();
+  if (Iter == IterEnd)
+    return rep_runtime_internal::kEmptyCollection;
+
+  const void *M = TypeTest::isMap(Obj);
+
+  std::string str("{ ");
+  str += PrintValueRuntime(&(*Iter), M);
+  while (++Iter != IterEnd) {
+    str += ", ";
+    str += PrintValueRuntime(&(*Iter), M);
+  }
+  return str + " }";
+}
+
+// As above, but without ability to take address of elements.
+template <typename CollectionType>
+inline auto PrintValueRuntimeImpl(
+    const CollectionType *Obj,
+    typename std::enable_if_t<!std::is_reference_v<decltype(*(Obj->begin()))>>
+        * = nullptr) -> decltype(++(Obj->begin()), Obj->end(), std::string()) {
+  auto iter = Obj->begin(), IterEnd = Obj->end();
+  if (iter == IterEnd)
+    return rep_runtime_internal::kEmptyCollection;
+
+  std::string str("{ ");
+  str += PrintValueRuntime(*iter);
+  while (++iter != IterEnd) {
+    str += ", ";
+    str += PrintValueRuntime(*iter);
+  }
+  return str + " }";
+}
+} // namespace collections_printer_internal
+
+// Collections
+template <typename CollectionType>
+inline auto PrintValueRuntime(const CollectionType *Obj)
+    -> decltype(collections_printer_internal::PrintValueRuntimeImpl(Obj),
+                std::string()) {
+  return collections_printer_internal::PrintValueRuntimeImpl(Obj);
+}
+
+// Arrays
+template <typename T, size_t N>
+inline std::string PrintValueRuntime(const T (*Obj)[N]) {
+  if (N == 0)
+    return rep_runtime_internal::kEmptyCollection;
+
+  std::string str = "{ ";
+  str += PrintValueRuntime(*Obj + 0);
+  for (size_t i = 1; i < N; ++i) {
+    str += ", ";
+    str += PrintValueRuntime(*Obj + i);
+  }
+  return str + " }";
+}
+
+// Tuples
+template <class... Args>
+inline std::string PrintValueRuntime(std::tuple<Args...> *);
+
+namespace collections_printer_internal {
+// We loop at compile time from element 0 to element Tuple_SIZE - 1
+// of the tuple. The running index is N which has as initial value
+// Tuple_SIZE. We can therefore stop the iteration and account for the
+// empty tuple case with one single specialisation.
+template <class Tuple, std::size_t N = std::tuple_size<Tuple>(),
+          std::size_t TupleSize = std::tuple_size<Tuple>()>
+struct tuplePrinter {
+  static std::string print(Tuple *t) {
+    constexpr std::size_t elementNumber = TupleSize - N;
+    std::string ret;
+    if (elementNumber)
+      ret += ", ";
+    ret += PrintValueRuntime(&std::get<elementNumber>(*t));
+    // If N+1 is not smaller than the size of the tuple,
+    // reroute the call to the printing function to the
+    // no-op specialisation to stop recursion.
+    constexpr std::size_t Nm1 = N - 1;
+    ret += tuplePrinter<Tuple, Nm1>::print((Tuple *)t);
+    return ret;
+  }
+};
+
+// Special case: no op if last element reached or empty tuple
+template <class Tuple, std::size_t TupleSize>
+struct tuplePrinter<Tuple, 0, TupleSize> {
+  static std::string print(Tuple *t) { return ""; }
+};
+
+template <class T> inline std::string tuplePairPrintValue(T *val) {
+  std::string ret("{ ");
+  ret += collections_printer_internal::tuplePrinter<T>::print(val);
+  ret += " }";
+  return ret;
+}
+} // namespace collections_printer_internal
+
+template <class... Args>
+inline std::string PrintValueRuntime(std::tuple<Args...> *val) {
+  using T = std::tuple<Args...>;
+  if (std::tuple_size<T>::value == 0)
+    return rep_runtime_internal::kEmptyCollection;
+  return collections_printer_internal::tuplePairPrintValue<T>(val);
+}
+
+template <class... Args>
+inline std::string PrintValueRuntime(std::pair<Args...> *val) {
+  using T = std::pair<Args...>;
+  return collections_printer_internal::tuplePairPrintValue<T>(val);
+}
+
+namespace collections_printer_internal {
+// Keep this last to allow picking up all specializations above.
+template <typename T> std::string PrintValueRuntime(const T *V, const void *) {
+  return PrintValueRuntime(V);
+}
+} // namespace collections_printer_internal
+
+// unique_ptr<T>:
+template <class T>
+inline std::string PrintValueRuntime(std::unique_ptr<T> *val) {
+  auto ptr = val->get();
+  // PrintValueRuntime dereference its argument. use cast to 'const void**' to
+  // get the same printout as a regular pointer.
+  return "std::unique_ptr -> " + PrintValueRuntime((const void **)&ptr);
+}
+
+// shared_ptr<T>:
+template <class T>
+inline std::string PrintValueRuntime(std::shared_ptr<T> *val) {
+  auto ptr = val->get();
+  // PrintValueRuntime dereference its argument. use cast to 'const void**' to
+  // get the same printout as a regular pointer.
+  return "std::shared_ptr -> " + PrintValueRuntime((const void **)&ptr);
+}
+
+// weak_ptr<T>:
+template <class T> inline std::string PrintValueRuntime(std::weak_ptr<T> *val) {
+  auto ptr = val->lock().get();
+  // PrintValueRuntime dereference its argument. use cast to 'const void**' to
+  // get the same printout as a regular pointer.
+  return "std::weak_ptr -> " + PrintValueRuntime((const void **)&ptr);
+}
+#endif
Index: clang/lib/Headers/CMakeLists.txt
===================================================================
--- clang/lib/Headers/CMakeLists.txt
+++ clang/lib/Headers/CMakeLists.txt
@@ -19,6 +19,7 @@
   tgmath.h
   unwind.h
   varargs.h
+  __clang_interpreter_runtime_printvalue.h
   )
 
 set(arm_common_files
Index: clang/include/clang/Interpreter/Interpreter.h
===================================================================
--- clang/include/clang/Interpreter/Interpreter.h
+++ clang/include/clang/Interpreter/Interpreter.h
@@ -34,6 +34,7 @@
 
 namespace clang {
 
+class Parser;
 class CompilerInstance;
 class IncrementalExecutor;
 class IncrementalParser;
@@ -67,9 +68,12 @@
   llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine();
 
   llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
+  llvm::Error ExecuteModule(std::unique_ptr<llvm::Module> &M);
   llvm::Error Execute(PartialTranslationUnit &T);
   llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
   llvm::Expected<llvm::JITTargetAddress> CompileDtorCall(CXXRecordDecl *CXXRD);
+  llvm::Expected<llvm::JITTargetAddress> CompileDecl(Decl *D);
+  std::string CreateUniqName(std::string Base);
 
   /// Undo N previous incremental inputs.
   llvm::Error Undo(unsigned N = 1);
@@ -92,6 +96,7 @@
   getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
 
   size_t getEffectivePTUSize() const;
+  Parser &getParser() const;
 
   enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
 
@@ -104,6 +109,8 @@
 private:
   bool FindRuntimeInterface();
 
+  std::unique_ptr<llvm::Module> GenModule();
+
   llvm::DenseMap<CXXRecordDecl *, llvm::JITTargetAddress> Dtors;
 
   llvm::SmallVector<Expr *, 3> ValuePrintingInfo;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to