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

- include <tuple> to avoid incorrect lookup on Windows
- Add `-Xcc -fno-delayed-template-parsing` to fix failure on Windows


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/include/clang/Interpreter/Value.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
  clang/tools/clang-repl/CMakeLists.txt

Index: clang/tools/clang-repl/CMakeLists.txt
===================================================================
--- clang/tools/clang-repl/CMakeLists.txt
+++ clang/tools/clang-repl/CMakeLists.txt
@@ -11,6 +11,65 @@
   ClangRepl.cpp
   )
 
+if(MSVC)
+  set_target_properties(clang-repl PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS 1)
+
+  # RTTI/C++ symbols
+  set(clang_repl_exports ${clang_repl_exports} ??_7type_info@@6B@
+    ?__type_info_root_node@@3U__type_info_node@@A
+    ?nothrow@std@@3Unothrow_t@1@B
+  )
+
+  # Compiler added symbols for static variables. NOT for VStudio < 2015
+  set(clang_repl_exports ${clang_repl_exports} _Init_thread_abort _Init_thread_epoch
+    _Init_thread_footer _Init_thread_header _tls_index
+  )
+
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # new/delete variants needed when linking to static msvc runtime (esp. Debug)
+    set(clang_repl_exports ${clang_repl_exports}
+      ??2@YAPEAX_K@Z
+      ??3@YAXPEAX@Z
+      ??_U@YAPEAX_K@Z
+      ??_V@YAXPEAX@Z
+      ??3@YAXPEAX_K@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@H@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@M@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@N@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@PEBX@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@P6AAEAV01@AEAV01@@Z@Z
+      ??$?6U?$char_traits@D@std@@@std@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@0@AEAV10@D@Z
+      ??$?6U?$char_traits@D@std@@@std@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@0@AEAV10@PEBD@Z
+      ?_Facet_Register@std@@YAXPEAV_Facet_base@1@@Z
+    )
+  else()
+    set(clang_repl_exports ${clang_repl_exports}
+      ??2@YAPAXI@Z
+      ??3@YAXPAX@Z
+      ??3@YAXPAXI@Z
+      ??_U@YAPAXI@Z
+      ??_V@YAXPAX@Z
+      ??_V@YAXPAXI@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@M@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@N@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@PBX@Z
+      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
+      ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@D@Z
+      ??$?6U?$char_traits@D@std@@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z
+      ?_Facet_Register@std@@YAXPAV_Facet_base@1@@Z
+    )
+  endif()
+
+  # List to '/EXPORT:sym0 /EXPORT:sym1 /EXPORT:sym2 ...'
+  foreach(sym ${clang_repl_exports})
+    set(clang_repl_link_str "${clang_repl_link_str} /EXPORT:${sym}")
+  endforeach(sym ${clang_repl_exports})
+
+  set_property(TARGET clang-repl APPEND_STRING PROPERTY LINK_FLAGS ${clang_repl_link_str})
+
+endif(MSVC)
+
 clang_target_link_libraries(clang-repl PRIVATE
   clangAST
   clangBasic
Index: clang/test/Interpreter/pretty-print.cpp
===================================================================
--- /dev/null
+++ clang/test/Interpreter/pretty-print.cpp
@@ -0,0 +1,180 @@
+// 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 -Xcc -fno-delayed-template-parsing | FileCheck %s
+extern "C" int printf(const char*,...);
+
+char c = 'a';
+c
+// CHECK: (char) 'a'
+
+const char* c_str = "Goodbye, world!";
+c_str
+// CHECK-NEXT: (const char *) "Goodbye, world!"
+
+const char* c_null_str = 0;
+c_null_str
+// CHECK-NEXT: (const char *) nullptr
+
+"Hello, world"
+// CHECK-NEXT: (const char[13]) "Hello, world"
+
+int x = 42;
+x
+// CHECK-NEXT: (int) 42
+
+&x
+// CHECK-NEXT: (int *) [[Addr:@0x.*]]
+
+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 S1{};
+S1 s1;
+s1
+// CHECK-NEXT: (S1 &) [[Addr:@0x.*]]
+
+S1{}
+// CHECK-NEXT: (S1) [[Addr:@0x.*]]
+
+struct S2 {int d;} E = {22};
+E
+// CHECK-NEXT: (struct S2 &) [[Addr:@0x.*]]
+E.d
+// CHECK-NEXT: (int) 22
+
+struct S3 { int* p; S3() { p = new int(42); } ~S3() { delete p; } };
+S3{}
+// CHECK-NEXT: (S3) [[Addr:@0x.*]]
+S3 s3;
+s3
+// CHECK-NEXT: (S3 &) [[Addr:@0x.*]]
+
+struct S4 { ~S4() { printf("~S4()\n"); }};
+S4{}
+// CHECK-NEXT: (S4) [[Addr:@0x.*]]
+
+enum Enum{ e1 = -12, e2, e3=33, e4, e5 = 33};
+e2
+// CHECK-NEXT: (Enum) (e2) : int -11
+::e1
+// CHECK-NEXT: (Enum) (e1) : int -12
+
+enum class Color { Black = 0, Red, Green };
+Color::Black
+// CHECK-NEXT: (Color) (Color::Black) : int 0
+
+int arr[3] = {1,2,3};
+arr
+// CHECK-NEXT: (int[3]) { 1, 2, 3 }
+
+auto Lambda1 = []{};
+Lambda1
+// CHECK-NEXT: ((lambda) &) [[Addr:@0x.*]]
+[]{}
+// CHECK-NEXT: ((lambda at input_line_84:1:1)) [[Addr:@0x.*]]
+
+template<int n> struct F{ enum {RET=F<n-1>::RET*n} ; };
+template<> struct F<0> { enum {RET = 1}; };
+F<7>::RET
+// CHECK-NEXT: (F<7>::(unnamed enum at input_line_87:1:27)) (F<7>::RET) : unsigned int 5040
+
+int foo() { return 42; }
+foo()
+// CHECK-NEXT: (int) 42
+
+void bar() {}
+bar()
+
+struct S5 { int foo() { return 42; }};
+&S5::foo
+// CHECK-NEXT: (int (S5::*)()) Function [[Addr:@0x.*]]
+
+#include <memory>
+
+auto p1 = std::make_shared<int>(42);
+p1
+// CHECK-NEXT: (std::shared_ptr<int> &) std::shared_ptr -> [[Addr:@0x.*]]
+
+auto p2 = std::make_unique<int>(42);
+p2
+// CHECK-NEXT: (std::unique_ptr<int, std::default_delete<int> > &) std::unique_ptr -> [[Addr:@0x.*]]
+
+#include <array>
+std::array<int, 3> a{1, 2, 3};
+a
+// CHECK-NEXT: (std::array<int, 3> &) { 1, 2, 3 }
+
+#include <vector>
+std::vector<int> v1 = {7, 5, 16, 8};
+v1
+// CHECK-NEXT: (std::vector<int> &) { 7, 5, 16, 8 }
+
+std::vector<bool> v = {true, false, true};
+v
+// CHECK-NEXT: (std::vector<bool> &) { true, false, true }
+
+#include <deque>
+std::deque<int> dq = {7, 5, 16, 8};
+dq
+// CHECK-NEXT: (std::deque<int> &) { 7, 5, 16, 8 }
+
+#include <forward_list>
+std::forward_list<int> fl {3,4,5,6};
+fl
+// CHECK-NEXT: (std::forward_list<int> &) { 3, 4, 5, 6 }
+
+#include <set>
+std::set<int> z1 = {2,4,6,8};
+z1
+// CHECK-NEXT: (std::set<int> &) { 2, 4, 6, 8 }
+
+#include <unordered_set>
+std::unordered_set<int> z2 = {8,2,4,6};
+z2
+// CHECK-NEXT: (std::unordered_set<int> &) { [[Num:[0-9]+]], [[Num:[0-9]+]], [[Num:[0-9]+]], [[Num:[0-9]+]] }
+
+std::multiset<int> e {3,2,1,2,4,7,3};
+e
+// CHECK-NEXT: (std::multiset<int> &) { 1, 2, 2, 3, 3, 4, 7 }
+
+#include <string>
+std::string std_str = "Hello, world!";
+std_str
+// CHECK-NEXT: (std::string &) "Hello, world!"
+
+#include <utility>
+std::pair<int,char> pr(42,'a');
+pr
+// CHECK-NEXT: (std::pair<int, char> &) { 42, 'a' }
+
+#include <tuple>
+std::tuple<int,double,char> tu(42,3.14,'a');
+tu
+// CHECK-NEXT: (std::tuple<int, double, char> &) { 42, 3.14000000000, 'a' }
+
+#include <map>
+std::map<const char*, int> m1{{"CPU", 10}, {"GPU", 15}, {"RAM", 20}};
+m1
+// CHECK-NEXT: (std::map<const char *, int> &) { "CPU" => 10, "GPU" => 15, "RAM" => 20 }
+
+#include <unordered_map>
+std::unordered_map<int, int> m2 = { {1,2}, {3,4}};
+m2
+// CHECK-NEXT: (std::unordered_map<int, int> &) { [[Num:[0-9]+]] => [[Num:[0-9]+]], [[Num:[0-9]+]] => [[Num:[0-9]+]] }
+
+struct MyType {};
+std::string PrintValueRuntime(const MyType*) { return "My pretty printer!"; }
+MyType{}
+// CHECK-NEXT: (MyType) My pretty printer!
+%quit
+
Index: clang/lib/Interpreter/ValuePrinter.cpp
===================================================================
--- /dev/null
+++ clang/lib/Interpreter/ValuePrinter.cpp
@@ -0,0 +1,526 @@
+#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;
+
+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 = const_cast<ASTContext &>(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 = const_cast<ASTContext &>(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 PrintFunction(const Value &V, const void *Ptr) {
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+  SS << "Function @" << Ptr;
+
+  const FunctionDecl *FD = nullptr;
+
+  auto Decls = V.getASTContext().getTranslationUnitDecl()->decls();
+  assert(std::distance(Decls.begin(), Decls.end()) == 1 &&
+         "TU should only contain one Decl");
+  auto *TLSD = llvm::cast<TopLevelStmtDecl>(*Decls.begin());
+
+  // Get __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void
+  // *OpaqueType, void *Val);
+  if (auto *InterfaceCall = llvm::dyn_cast<CallExpr>(TLSD->getStmt())) {
+    const auto *Arg = InterfaceCall->getArg(/*Val*/ 3);
+    // Get rid of cast nodes.
+    while (const CastExpr *CastE = llvm::dyn_cast<CastExpr>(Arg))
+      Arg = CastE->getSubExpr();
+    if (const DeclRefExpr *DeclRefExp = llvm::dyn_cast<DeclRefExpr>(Arg))
+      FD = llvm::dyn_cast<FunctionDecl>(DeclRefExp->getDecl());
+
+    if (FD) {
+      SS << '\n';
+      const clang::FunctionDecl *FDef;
+      if (FD->hasBody(FDef))
+        FDef->print(SS);
+    }
+  }
+  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());
+
+  if (const auto *AT = llvm::dyn_cast<AutoType>(QT.getTypePtr())) {
+    if (AT->isDeduced())
+      QT = AT->getDeducedType().getDesugaredType(Ctx);
+  }
+
+  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 = const_cast<Interpreter &>(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);
+
+  void *ValPtr = V.getPtr();
+  if (!V.isManuallyAlloc())
+    ValPtr = V.getPtrAddress();
+
+  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 = AddrOrErr->toPtr<std::string (*)()>())
+    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);
+}
+
+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())
+    return PrintFunction(V, &V);
+  else if ((NonRefTy->isPointerType() || NonRefTy->isMemberPointerType()) &&
+           NonRefTy->getPointeeType()->isFunctionProtoType())
+    return PrintFunction(V, V.getPtr());
+  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
@@ -230,6 +230,11 @@
   return Data.m_Ptr;
 }
 
+void **Value::getPtrAddress() const {
+  assert(ValueKind == K_PtrOrObj);
+  return &const_cast<Value *>(this)->Data.m_Ptr;
+}
+
 QualType Value::getType() const {
   return QualType::getFromOpaquePtr(OpaqueType);
 }
@@ -254,13 +259,30 @@
 
 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";
+
+  // Don't even try to print a void or an invalid type, it doesn't make sense.
+  if (getType()->isVoidType() || !isValid())
+    return;
+
+  // 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
@@ -48,6 +48,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,409 @@
   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().getDesugaredType(Ctx), 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"
@@ -217,6 +218,7 @@
     void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
       __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
     }
+    #define __CLANG_REPL__ 1
 )";
 
 llvm::Expected<std::unique_ptr<Interpreter>>
@@ -241,6 +243,8 @@
   return IncrParser->getCI();
 }
 
+Parser &Interpreter::getParser() const { return IncrParser->getParser(); }
+
 llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
   if (!IncrExecutor) {
     if (auto Err = CreateExecutor())
@@ -284,6 +288,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) {
   assert(T.TheModule);
   if (!IncrExecutor) {
@@ -407,6 +427,37 @@
   return AddrOrErr;
 }
 
+std::unique_ptr<llvm::Module> Interpreter::GenModule() {
+  return IncrParser->GenModule();
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr> 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::orc::ExecutorAddr> AddrOrErr =
+        getSymbolAddressFromLinkerName(ASTNameGen.getName(D));
+
+    return AddrOrErr;
+  }
+  return llvm::orc::ExecutorAddr{};
+}
+
+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[] = {
     "__clang_Interpreter_SetValueNoAlloc",
     "__clang_Interpreter_SetValueWithAlloc",
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
@@ -48,6 +48,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
@@ -59,6 +59,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
@@ -16,6 +16,7 @@
   Interpreter.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,246 @@
+//===--- __clang_interpreter_runtime_printvalue.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
+
+#if !defined(__CLANG_REPL__)
+#error "This file should only be included by clang-repl!"
+#endif
+
+#include <memory>
+#include <string>
+#include <tuple>
+#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
+
+// Fallback for e.g. vector<bool>'s bit iterator:
+template <class T, class = typename std::enable_if_t<!std::is_pointer_v<T>>>
+inline std::string PrintValueRuntime(const T &Val) {
+  return "{not representable}";
+}
+
+// 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 repl_runtime_detail {
+template <typename T, typename = void> struct is_iterable : std::false_type {};
+
+// this gets used only when we can call std::begin() and std::end() on that type
+template <typename T>
+struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T &>())),
+                                  decltype(std::end(std::declval<T &>()))>>
+    : std::true_type {};
+
+template <typename> struct is_pair : std::false_type {};
+
+template <typename T, typename U>
+struct is_pair<std::pair<T, U>> : std::true_type {};
+
+template <typename T, typename = void> struct is_map : std::false_type {};
+
+template <typename T>
+struct is_map<T, std::void_t<typename T::mapped_type>> : std::true_type {};
+
+// The type of the elements is std::pair, and the container is a map like type.
+template <
+    typename Container, typename Elt,
+    typename std::enable_if<is_pair<Elt>::value && is_map<Container>::value,
+                            bool>::type = true>
+std::string PrintCollectionElt(const Elt &Val) {
+  return PrintValueRuntime(&Val.first) + " => " +
+         PrintValueRuntime(&Val.second);
+}
+
+// The type of the elements is std::pair, and the container isn't a map like
+// type.
+template <
+    typename Container, typename Elt,
+    typename std::enable_if<is_pair<Elt>::value && !is_map<Container>::value,
+                            bool>::type = true>
+std::string PrintCollectionElt(const Elt &Val) {
+  return TuplePairPrintValue(&Val);
+}
+
+template <typename Container, typename Elt,
+          typename std::enable_if<!is_pair<Elt>::value, bool>::type = true>
+std::string PrintCollectionElt(const Elt &Val) {
+  return PrintValueRuntime(&Val);
+}
+
+template <class Tuple, std::size_t N = std::tuple_size<Tuple>(),
+          std::size_t TupleSize = std::tuple_size<Tuple>()>
+struct TupleLikePrinter {
+  static std::string print(const Tuple *T) {
+    constexpr std::size_t EltNum = TupleSize - N;
+    std::string Str;
+    // Not the first element.
+    if (EltNum != 0)
+      Str += ", ";
+    Str += PrintValueRuntime(&std::get<EltNum>(*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;
+    Str += TupleLikePrinter<Tuple, Nm1>::print((const Tuple *)T);
+    return Str;
+  }
+};
+
+template <class Tuple, std::size_t TupleSize>
+struct TupleLikePrinter<Tuple, 0, TupleSize> {
+  static std::string print(const Tuple *T) { return ""; }
+};
+
+template <class T> inline std::string TuplePairPrintValue(const T *Val) {
+  std::string Str("{ ");
+  Str += TupleLikePrinter<T>::print(Val);
+  Str += " }";
+  return Str;
+}
+
+} // namespace repl_runtime_detail
+
+template <
+    typename Container,
+    typename std::enable_if<repl_runtime_detail::is_iterable<Container>::value,
+                            bool>::type = true>
+inline std::string PrintValueRuntime(const Container *C) {
+  std::string Str("{ ");
+
+  for (auto Beg = C->begin(), End = C->end(); Beg != End; Beg++) {
+    if (Beg != C->begin())
+      Str += ", ";
+    Str += repl_runtime_detail::PrintCollectionElt<Container>(*Beg);
+  }
+  Str += " }";
+  return Str;
+}
+
+template <typename T, size_t N>
+inline std::string PrintValueRuntime(const T (*Obj)[N]) {
+  if (N == 0)
+    return "{}";
+
+  std::string Str = "{ ";
+  for (size_t Idx = 0; Idx < N; ++Idx) {
+    Str += PrintValueRuntime(*Obj + Idx);
+    if (Idx < N - 1)
+      Str += ", ";
+  }
+  return Str + " }";
+}
+
+template <size_t N> inline std::string PrintValueRuntime(const char (*Obj)[N]) {
+  const auto *Str = reinterpret_cast<const char *const>(Obj);
+  return PrintValueRuntime(&Str);
+}
+
+// tuple
+template <typename... Ts>
+inline std::string PrintValueRuntime(const std::tuple<Ts...> *Val) {
+  using T = std::tuple<Ts...>;
+  return repl_runtime_detail::TuplePairPrintValue<T>(Val);
+}
+
+// pair
+template <typename... Ts>
+inline std::string PrintValueRuntime(const std::pair<Ts...> *Val) {
+  using T = std::pair<Ts...>;
+  return repl_runtime_detail::TuplePairPrintValue<T>(Val);
+}
+
+// unique_ptr
+template <class T>
+inline std::string PrintValueRuntime(const std::unique_ptr<T> *Val) {
+  auto Ptr = Val->get();
+  return "std::unique_ptr -> " + PrintValueRuntime((const void **)&Ptr);
+}
+
+// shared_ptr
+template <class T>
+inline std::string PrintValueRuntime(const std::shared_ptr<T> *Val) {
+  auto Ptr = Val->get();
+  return "std::shared_ptr -> " + PrintValueRuntime((const void **)&Ptr);
+}
+
+// weak_ptr
+template <class T>
+inline std::string PrintValueRuntime(const std::weak_ptr<T> *Val) {
+  auto Ptr = Val->lock().get();
+  return "std::weak_ptr -> " + PrintValueRuntime((const void **)&Ptr);
+}
+
+// string
+template <class T>
+inline std::string PrintValueRuntime(const std::basic_string<T> *Val) {
+  const char *Chars = Val->c_str();
+  return PrintValueRuntime((const char **)&Chars);
+}
+#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/Value.h
===================================================================
--- clang/include/clang/Interpreter/Value.h
+++ clang/include/clang/Interpreter/Value.h
@@ -106,6 +106,7 @@
   void setOpaqueType(void *Ty) { OpaqueType = Ty; }
 
   void *getPtr() const;
+  void **getPtrAddress() const;
   void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
 
 #define X(type, name)                                                          \
Index: clang/include/clang/Interpreter/Interpreter.h
===================================================================
--- clang/include/clang/Interpreter/Interpreter.h
+++ clang/include/clang/Interpreter/Interpreter.h
@@ -35,6 +35,7 @@
 
 namespace clang {
 
+class Parser;
 class CompilerInstance;
 class IncrementalExecutor;
 class IncrementalParser;
@@ -72,9 +73,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::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
+  llvm::Expected<llvm::orc::ExecutorAddr> CompileDecl(Decl *D);
+  std::string CreateUniqName(std::string Base);
 
   /// Undo N previous incremental inputs.
   llvm::Error Undo(unsigned N = 1);
@@ -96,6 +100,8 @@
   llvm::Expected<llvm::orc::ExecutorAddr>
   getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
 
+  Parser &getParser() const;
+
   enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
 
   const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
@@ -110,6 +116,7 @@
   bool FindRuntimeInterface();
 
   llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
+  std::unique_ptr<llvm::Module> GenModule();
 
   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