junaire updated this revision to Diff 526566.
junaire marked 2 inline comments as done.
junaire added a comment.
Add LLVM preamble
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/PartialTranslationUnit.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/DeviceOffload.cpp
clang/lib/Interpreter/DeviceOffload.h
clang/lib/Interpreter/IncrementalExecutor.cpp
clang/lib/Interpreter/IncrementalExecutor.h
clang/lib/Interpreter/IncrementalParser.cpp
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
clang/tools/clang-repl/ClangRepl.cpp
clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
clang/unittests/Interpreter/IncrementalProcessingTest.cpp
clang/unittests/Interpreter/InterpreterTest.cpp
Index: clang/unittests/Interpreter/InterpreterTest.cpp
===================================================================
--- clang/unittests/Interpreter/InterpreterTest.cpp
+++ clang/unittests/Interpreter/InterpreterTest.cpp
@@ -29,6 +29,7 @@
#include "gtest/gtest.h"
using namespace clang;
+using namespace caas;
#if defined(_AIX)
#define CLANG_INTERPRETER_NO_SUPPORT_EXEC
@@ -46,12 +47,12 @@
DiagnosticConsumer *Client = nullptr) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
- auto CB = clang::IncrementalCompilerBuilder();
+ auto CB = clang::caas::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgs);
auto CI = cantFail(CB.CreateCpp());
if (Client)
CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false);
- return cantFail(clang::Interpreter::create(std::move(CI)));
+ return cantFail(clang::caas::Interpreter::create(std::move(CI)));
}
static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
Index: clang/unittests/Interpreter/IncrementalProcessingTest.cpp
===================================================================
--- clang/unittests/Interpreter/IncrementalProcessingTest.cpp
+++ clang/unittests/Interpreter/IncrementalProcessingTest.cpp
@@ -27,6 +27,7 @@
using namespace llvm;
using namespace clang;
+using namespace clang::caas;
namespace {
@@ -52,12 +53,12 @@
TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
std::vector<const char *> ClangArgv = {"-Xclang", "-emit-llvm-only"};
- auto CB = clang::IncrementalCompilerBuilder();
+ auto CB = clang::caas::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgv);
auto CI = cantFail(CB.CreateCpp());
auto Interp = llvm::cantFail(Interpreter::create(std::move(CI)));
- std::array<clang::PartialTranslationUnit *, 2> PTUs;
+ std::array<clang::caas::PartialTranslationUnit *, 2> PTUs;
PTUs[0] = &llvm::cantFail(Interp->Parse(TestProgram1));
ASSERT_TRUE(PTUs[0]->TheModule);
Index: clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
===================================================================
--- clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
+++ clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
@@ -30,6 +30,7 @@
#include "gtest/gtest.h"
using namespace clang;
+using namespace clang::caas;
namespace {
using Args = std::vector<const char *>;
@@ -38,12 +39,12 @@
DiagnosticConsumer *Client = nullptr) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
- auto CB = clang::IncrementalCompilerBuilder();
+ auto CB = clang::caas::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgs);
auto CI = cantFail(CB.CreateCpp());
if (Client)
CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false);
- return cantFail(clang::Interpreter::create(std::move(CI)));
+ return cantFail(clang::caas::Interpreter::create(std::move(CI)));
}
TEST(InterpreterTest, CatchException) {
Index: clang/tools/clang-repl/ClangRepl.cpp
===================================================================
--- clang/tools/clang-repl/ClangRepl.cpp
+++ clang/tools/clang-repl/ClangRepl.cpp
@@ -97,7 +97,7 @@
return 0;
}
- clang::IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
CB.SetCompilerArgs(ClangArgv);
std::unique_ptr<clang::CompilerInstance> DeviceCI;
@@ -132,10 +132,10 @@
if (CudaEnabled)
DeviceCI->LoadRequestedPlugins();
- std::unique_ptr<clang::Interpreter> Interp;
+ std::unique_ptr<clang::caas::Interpreter> Interp;
if (CudaEnabled) {
- Interp = ExitOnErr(
- clang::Interpreter::createWithCUDA(std::move(CI), std::move(DeviceCI)));
+ Interp = ExitOnErr(clang::caas::Interpreter::createWithCUDA(
+ std::move(CI), std::move(DeviceCI)));
if (CudaPath.empty()) {
ExitOnErr(Interp->LoadDynamicLibrary("libcudart.so"));
@@ -144,7 +144,7 @@
ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
}
} else
- Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
+ Interp = ExitOnErr(clang::caas::Interpreter::create(std::move(CI)));
for (const std::string &input : OptInputs) {
if (auto Err = Interp->ParseAndExecute(input))
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_83: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_86: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,561 @@
+//===--- ValuePrinter.cpp - Utils for value printing --------*- 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 implements routines for value printing in clang-repl.
+//
+//===----------------------------------------------------------------------===//
+#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/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;
+using namespace clang::caas;
+
+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;
+}
+
+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::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 llvm::Expected<llvm::orc::ExecutorAddr> CompileDecl(Interpreter &Interp,
+ Decl *D) {
+ assert(D && "The Decl being compiled can't be null");
+
+ ASTConsumer &Consumer = Interp.getCompilerInstance()->getASTConsumer();
+ Consumer.HandleTopLevelDecl(DeclGroupRef(D));
+ Interp.getCompilerInstance()->getSema().PerformPendingInstantiations();
+ Consumer.HandleTranslationUnit(Interp.getASTContext());
+
+ if (std::unique_ptr<llvm::Module> M = Interp.GenModule()) {
+ if (llvm::Error Err = Interp.ExecuteModule(M))
+ return Err;
+ ASTNameGenerator ASTNameGen(Interp.getASTContext());
+ llvm::Expected<llvm::orc::ExecutorAddr> AddrOrErr =
+ Interp.getSymbolAddressFromLinkerName(ASTNameGen.getName(D));
+
+ return AddrOrErr;
+ }
+ return llvm::orc::ExecutorAddr{};
+}
+
+static std::string CreateUniqName(std::string Base) {
+ static size_t I = 0;
+ Base += std::to_string(I);
+ I += 1;
+ return Base;
+}
+
+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 this header once and on demand. Because it's very heavy.
+ 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(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 = CompileDecl(Interp, 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);
+}
+
+namespace clang::caas {
+std::string ReplPrintDataImpl(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;
+}
+
+std::string ReplPrintTypeImpl(const Value &V) {
+ ASTContext &Ctx = const_cast<ASTContext &>(V.getASTContext());
+ QualType QT = V.getType();
+
+ return PrintQualType(Ctx, QT);
+}
+} // namespace clang::caas
Index: clang/lib/Interpreter/Value.cpp
===================================================================
--- clang/lib/Interpreter/Value.cpp
+++ clang/lib/Interpreter/Value.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Interpreter/Value.h"
+#include "InterpreterUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
#include "clang/Interpreter/Interpreter.h"
@@ -23,6 +24,7 @@
#include <utility>
using namespace clang;
+using namespace clang::caas;
namespace {
@@ -230,6 +232,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);
}
@@ -255,12 +262,30 @@
void Value::dump() const { print(llvm::outs()); }
void Value::printType(llvm::raw_ostream &Out) const {
- Out << "Not implement yet.\n";
+ Out << ReplPrintTypeImpl(*this);
}
+
void Value::printData(llvm::raw_ostream &Out) const {
- Out << "Not implement yet.\n";
+ Out << ReplPrintDataImpl(*this);
}
+// FIXME: We do not support the multiple inheritance case where one of the base
+// classes has a pretty-printer and the other does not.
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
@@ -33,7 +33,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/TargetParser/Host.h"
-namespace clang {
+namespace clang::caas {
IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val);
Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E);
@@ -48,7 +48,25 @@
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
+
+class Value;
+
+std::string ReplPrintTypeImpl(const Value &);
+std::string ReplPrintDataImpl(const Value &);
+} // namespace clang::caas
#endif
Index: clang/lib/Interpreter/InterpreterUtils.cpp
===================================================================
--- clang/lib/Interpreter/InterpreterUtils.cpp
+++ clang/lib/Interpreter/InterpreterUtils.cpp
@@ -12,7 +12,7 @@
#include "InterpreterUtils.h"
-namespace clang {
+namespace clang::caas {
IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val) {
return IntegerLiteral::Create(C, llvm::APSInt::getUnsigned(Val),
@@ -81,7 +81,7 @@
else {
const DeclContext *PrimaryWithin = nullptr;
if (const auto *TD = dyn_cast<TagDecl>(Within))
- PrimaryWithin = llvm::dyn_cast_or_null<DeclContext>(TD->getDefinition());
+ PrimaryWithin = dyn_cast_if_present<DeclContext>(TD->getDefinition());
else
PrimaryWithin = Within->getPrimaryContext();
@@ -97,15 +97,404 @@
R.resolveKind();
if (R.isSingleResult())
- return llvm::dyn_cast<NamedDecl>(R.getFoundDecl());
+ return dyn_cast<NamedDecl>(R.getFoundDecl());
return nullptr;
}
+static NestedNameSpecifier *CreateOuterNNS(const ASTContext &Ctx, const Decl *D,
+ bool FullyQualify) {
+ const DeclContext *DC = D->getDeclContext();
+ if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
+ while (NS && NS->isInline()) {
+ // Ignore inline namespace;
+ NS = dyn_cast_if_present<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 auto *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 auto *Outer = dyn_cast_if_present<NamedDecl>(D->getDeclContext());
+ const auto *OuterNs = dyn_cast_if_present<NamespaceDecl>(D->getDeclContext());
+ if (Outer && !(OuterNs && OuterNs->isAnonymousNamespace())) {
+
+ if (const auto *CXXD = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+
+ if (ClassTemplateDecl *CTD = 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 (CTD->spec_begin() != CTD->spec_end()) {
+ D = *(CTD->spec_begin());
+ Outer = dyn_cast<NamedDecl>(D);
+ OuterNs = dyn_cast<NamespaceDecl>(D);
+ }
+ }
+ }
+
+ if (OuterNs)
+ return CreateNestedNameSpecifier(Ctx, OuterNs);
+
+ if (const auto *TD = 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 = dyn_cast<TypedefType>(TypePtr)) {
+ D = TDT->getDecl();
+ } else {
+ // There are probably other cases ...
+ if (const auto *TT = dyn_cast_if_present<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 auto *TT = dyn_cast<TagType>(Type))
+ TD = TT->getDecl();
+ else
+ TD = Type->getAsCXXRecordDecl();
+
+ if (TD)
+ return CreateNestedNameSpecifier(Ctx, TD, true /*FullyQualified*/);
+
+ if (const auto *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 auto *Alias = Scope->getAsNamespaceAlias())
+ return CreateNestedNameSpecifier(Ctx,
+ Alias->getNamespace()->getCanonicalDecl());
+
+ return Scope;
+}
+
+static bool GetFullyQualifiedTemplateName(const ASTContext &Ctx,
+ TemplateName &Name) {
+
+ bool Changed = false;
+ NestedNameSpecifier *NNS = nullptr;
+
+ TemplateDecl *TD = Name.getAsTemplateDecl();
+ QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
+
+ if (QTN && !QTN->hasTemplateKeyword()) {
+ NNS = QTN->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 = 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 = 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 =
+ 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_if_present<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 (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 (isa<ReferenceType>(QT.getTypePtr())) {
+ // Get the qualifiers.
+ bool IsLValueRefTy = 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 (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
+ // Get the qualifiers.
+ Qualifiers Quals = QT.getQualifiers();
+
+ QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
+
+ // Add back the qualifiers.
+ QT = Ctx.getQualifiedType(QT, Quals);
+ }
+
+ NestedNameSpecifier *Prefix = nullptr;
+ Qualifiers PrefixQualifiers;
+ if (const auto *EType = 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 (isa<const TemplateSpecializationType>(QT.getTypePtr())) {
+
+ Qualifiers Qualifiers = QT.getLocalQualifiers();
+ const Type *TypePtr = GetFullyQualifiedLocalType(Ctx, QT.getTypePtr());
+ QT = Ctx.getQualifiedType(TypePtr, Qualifiers);
+
+ } else if (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
+} // namespace clang::caas
Index: clang/lib/Interpreter/Interpreter.cpp
===================================================================
--- clang/lib/Interpreter/Interpreter.cpp
+++ clang/lib/Interpreter/Interpreter.cpp
@@ -44,7 +44,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
using namespace clang;
-
+using namespace clang::caas;
// FIXME: Figure out how to unify with namespace init_convenience from
// tools/clang-import-test/clang-import-test.cpp
namespace {
@@ -267,6 +267,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>>
@@ -371,6 +372,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) {
@@ -494,6 +511,10 @@
return AddrOrErr;
}
+std::unique_ptr<llvm::Module> Interpreter::GenModule() {
+ return IncrParser->GenModule();
+}
+
static constexpr llvm::StringRef MagicRuntimeInterface[] = {
"__clang_Interpreter_SetValueNoAlloc",
"__clang_Interpreter_SetValueWithAlloc",
@@ -534,15 +555,15 @@
class RuntimeInterfaceBuilder
: public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
- clang::Interpreter &Interp;
+ clang::caas::Interpreter &Interp;
ASTContext &Ctx;
Sema &S;
Expr *E;
llvm::SmallVector<Expr *, 3> Args;
public:
- RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
- Expr *VE, ArrayRef<Expr *> FixedArgs)
+ RuntimeInterfaceBuilder(clang::caas::Interpreter &In, ASTContext &C,
+ Sema &SemaRef, Expr *VE, ArrayRef<Expr *> FixedArgs)
: Interp(In), Ctx(C), S(SemaRef), E(VE) {
// The Interpreter* parameter and the out parameter `OutVal`.
for (Expr *E : FixedArgs)
Index: clang/lib/Interpreter/IncrementalParser.h
===================================================================
--- clang/lib/Interpreter/IncrementalParser.h
+++ clang/lib/Interpreter/IncrementalParser.h
@@ -30,9 +30,11 @@
class ASTConsumer;
class CodeGenerator;
class CompilerInstance;
+class Parser;
+
+namespace caas {
class IncrementalAction;
class Interpreter;
-class Parser;
/// Provides support for incremental compilation. Keeps track of the state
/// changes between the subsequent incremental input.
///
@@ -86,6 +88,7 @@
private:
llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
};
+} // namespace caas
} // end namespace clang
#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
Index: clang/lib/Interpreter/IncrementalParser.cpp
===================================================================
--- clang/lib/Interpreter/IncrementalParser.cpp
+++ clang/lib/Interpreter/IncrementalParser.cpp
@@ -28,7 +28,7 @@
#include <sstream>
-namespace clang {
+namespace clang::caas {
class IncrementalASTConsumer final : public ASTConsumer {
Interpreter &Interp;
@@ -399,4 +399,4 @@
return CG->GetMangledName(GD);
}
-} // end namespace clang
+} // namespace clang::caas
Index: clang/lib/Interpreter/IncrementalExecutor.h
===================================================================
--- clang/lib/Interpreter/IncrementalExecutor.h
+++ clang/lib/Interpreter/IncrementalExecutor.h
@@ -30,9 +30,11 @@
namespace clang {
-struct PartialTranslationUnit;
class TargetInfo;
+namespace caas {
+struct PartialTranslationUnit;
+
class IncrementalExecutor {
using CtorDtorIterator = llvm::orc::CtorDtorIterator;
std::unique_ptr<llvm::orc::LLJIT> Jit;
@@ -48,6 +50,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;
@@ -57,7 +60,7 @@
llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; }
};
-
+} // namespace caas
} // end namespace clang
#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H
Index: clang/lib/Interpreter/IncrementalExecutor.cpp
===================================================================
--- clang/lib/Interpreter/IncrementalExecutor.cpp
+++ clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -33,7 +33,7 @@
<< (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
}
-namespace clang {
+namespace clang::caas {
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
llvm::Error &Err,
@@ -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();
@@ -100,4 +104,4 @@
return Sym;
}
-} // end namespace clang
+} // namespace clang::caas
Index: clang/lib/Interpreter/DeviceOffload.h
===================================================================
--- clang/lib/Interpreter/DeviceOffload.h
+++ clang/lib/Interpreter/DeviceOffload.h
@@ -17,7 +17,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/VirtualFileSystem.h"
-namespace clang {
+namespace clang::caas {
class IncrementalCUDADeviceParser : public IncrementalParser {
public:
@@ -46,6 +46,6 @@
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
};
-} // namespace clang
+} // namespace clang::caas
#endif // LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H
Index: clang/lib/Interpreter/DeviceOffload.cpp
===================================================================
--- clang/lib/Interpreter/DeviceOffload.cpp
+++ clang/lib/Interpreter/DeviceOffload.cpp
@@ -20,7 +20,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
-namespace clang {
+namespace clang::caas {
IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
@@ -173,4 +173,4 @@
IncrementalCUDADeviceParser::~IncrementalCUDADeviceParser() {}
-} // namespace clang
+} // namespace clang::caas
Index: clang/lib/Interpreter/CMakeLists.txt
===================================================================
--- clang/lib/Interpreter/CMakeLists.txt
+++ clang/lib/Interpreter/CMakeLists.txt
@@ -18,6 +18,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,232 @@
+//===--- __clang_interpreter_runtime_printvalue.h ---*- 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>
+
+// FIXME: 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}";
+}
+#ifndef __DECL_PRINT_VALUE_RUNTIME
+#define __DECL_PRINT_VALUE_RUNTIME(type) \
+ __REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const type *__Ptr)
+__DECL_PRINT_VALUE_RUNTIME(void);
+__DECL_PRINT_VALUE_RUNTIME(void *);
+__DECL_PRINT_VALUE_RUNTIME(bool);
+__DECL_PRINT_VALUE_RUNTIME(char);
+__DECL_PRINT_VALUE_RUNTIME(signed char);
+__DECL_PRINT_VALUE_RUNTIME(short);
+__DECL_PRINT_VALUE_RUNTIME(unsigned short);
+__DECL_PRINT_VALUE_RUNTIME(int);
+__DECL_PRINT_VALUE_RUNTIME(unsigned int);
+__DECL_PRINT_VALUE_RUNTIME(long);
+__DECL_PRINT_VALUE_RUNTIME(long long);
+__DECL_PRINT_VALUE_RUNTIME(unsigned long);
+__DECL_PRINT_VALUE_RUNTIME(unsigned long long);
+__DECL_PRINT_VALUE_RUNTIME(float);
+__DECL_PRINT_VALUE_RUNTIME(double);
+__DECL_PRINT_VALUE_RUNTIME(long double);
+__DECL_PRINT_VALUE_RUNTIME(char *const);
+__DECL_PRINT_VALUE_RUNTIME(char *);
+#endif
+
+namespace __repl_runtime_detail {
+
+// Avoid using C++17 std::void_t because clang-repl can be used with lower
+// standards.
+template <typename... T> struct __repl_make_void { typedef void __type; };
+
+template <typename... T>
+using repl_void_t = typename __repl_make_void<T...>::__type;
+
+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, repl_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, repl_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
@@ -49,9 +49,11 @@
namespace clang {
class ASTContext;
-class Interpreter;
class QualType;
+namespace caas {
+class Interpreter;
+
#if __has_attribute(visibility) && \
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
(defined(__MINGW32__) && defined(__clang__)))
@@ -131,6 +133,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) \
@@ -197,6 +200,6 @@
return Data.m_Ptr;
return (void *)as<uintptr_t>();
}
-
+} // namespace caas
} // namespace clang
#endif
Index: clang/include/clang/Interpreter/PartialTranslationUnit.h
===================================================================
--- clang/include/clang/Interpreter/PartialTranslationUnit.h
+++ clang/include/clang/Interpreter/PartialTranslationUnit.h
@@ -24,6 +24,7 @@
class TranslationUnitDecl;
+namespace caas {
/// The class keeps track of various objects created as part of processing
/// incremental inputs.
struct PartialTranslationUnit {
@@ -32,6 +33,7 @@
/// The llvm IR produced for the input.
std::unique_ptr<llvm::Module> TheModule;
};
+} // namespace caas
} // namespace clang
#endif // LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H
Index: clang/include/clang/Interpreter/Interpreter.h
===================================================================
--- clang/include/clang/Interpreter/Interpreter.h
+++ clang/include/clang/Interpreter/Interpreter.h
@@ -36,6 +36,8 @@
namespace clang {
class CompilerInstance;
+
+namespace caas {
class IncrementalExecutor;
class IncrementalParser;
@@ -104,6 +106,7 @@
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);
@@ -136,6 +139,8 @@
Expr *SynthesizeExpr(Expr *E);
+ std::unique_ptr<llvm::Module> GenModule();
+
private:
size_t getEffectivePTUSize() const;
@@ -145,6 +150,7 @@
llvm::SmallVector<Expr *, 3> ValuePrintingInfo;
};
+} // namespace caas
} // namespace clang
#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits