[clang] [clang-repl] Implement value printing of custom types (PR #84769)
Vassil Vassilev via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 21 07:03:52 PDT 2024
https://github.com/vgvassilev updated https://github.com/llvm/llvm-project/pull/84769
>From a1639ef21a6085f12383e815ce2ed31976f78cfa Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Sun, 16 Jul 2023 21:18:26 +0000
Subject: [PATCH 1/2] [clang-repl] Implement value printing of custom types.
Differential revision: https://reviews.llvm.org/D146809
---
clang/include/clang/Interpreter/Interpreter.h | 6 +
.../Interpreter/PartialTranslationUnit.h | 2 +
clang/include/clang/Interpreter/Value.h | 7 +-
clang/lib/Headers/CMakeLists.txt | 1 +
.../__clang_interpreter_runtime_printvalue.h | 261 ++++++++
clang/lib/Interpreter/CMakeLists.txt | 1 +
clang/lib/Interpreter/DeviceOffload.cpp | 4 +-
clang/lib/Interpreter/DeviceOffload.h | 4 +-
clang/lib/Interpreter/IncrementalExecutor.cpp | 8 +-
clang/lib/Interpreter/IncrementalExecutor.h | 7 +-
clang/lib/Interpreter/IncrementalParser.cpp | 5 +-
clang/lib/Interpreter/IncrementalParser.h | 5 +-
clang/lib/Interpreter/Interpreter.cpp | 28 +-
clang/lib/Interpreter/InterpreterUtils.cpp | 399 ++++++++++++-
clang/lib/Interpreter/InterpreterUtils.h | 22 +-
clang/lib/Interpreter/Value.cpp | 33 +-
clang/lib/Interpreter/ValuePrinter.cpp | 564 ++++++++++++++++++
clang/test/Interpreter/pretty-print.cpp | 206 +++++++
clang/tools/clang-repl/CMakeLists.txt | 59 ++
clang/tools/clang-repl/ClangRepl.cpp | 21 +-
.../Interpreter/CodeCompletionTest.cpp | 10 +-
.../InterpreterExceptionTest.cpp | 5 +-
.../IncrementalCompilerBuilderTest.cpp | 4 +-
.../Interpreter/IncrementalProcessingTest.cpp | 5 +-
.../Interpreter/InterpreterExtensionsTest.cpp | 9 +-
.../unittests/Interpreter/InterpreterTest.cpp | 5 +-
26 files changed, 1627 insertions(+), 54 deletions(-)
create mode 100644 clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
create mode 100644 clang/lib/Interpreter/ValuePrinter.cpp
create mode 100644 clang/test/Interpreter/pretty-print.cpp
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 970e0245417b51..43331b0fe92c96 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -38,6 +38,8 @@ class ThreadSafeContext;
namespace clang {
class CompilerInstance;
+
+namespace caas {
class IncrementalExecutor;
class IncrementalParser;
@@ -150,6 +152,7 @@ class Interpreter {
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);
@@ -182,6 +185,8 @@ class Interpreter {
Expr *SynthesizeExpr(Expr *E);
+ std::unique_ptr<llvm::Module> GenModule();
+
private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();
@@ -190,6 +195,7 @@ class Interpreter {
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
};
+} // namespace caas
} // namespace clang
#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H
diff --git a/clang/include/clang/Interpreter/PartialTranslationUnit.h b/clang/include/clang/Interpreter/PartialTranslationUnit.h
index bf91d559452b8a..d28cd30010cb92 100644
--- a/clang/include/clang/Interpreter/PartialTranslationUnit.h
+++ b/clang/include/clang/Interpreter/PartialTranslationUnit.h
@@ -24,6 +24,7 @@ namespace clang {
class TranslationUnitDecl;
+namespace caas {
/// The class keeps track of various objects created as part of processing
/// incremental inputs.
struct PartialTranslationUnit {
@@ -32,6 +33,7 @@ struct PartialTranslationUnit {
/// The llvm IR produced for the input.
std::unique_ptr<llvm::Module> TheModule;
};
+} // namespace caas
} // namespace clang
#endif // LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H
diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h
index d70e8f8719026b..6b737c05846fff 100644
--- a/clang/include/clang/Interpreter/Value.h
+++ b/clang/include/clang/Interpreter/Value.h
@@ -49,9 +49,11 @@ class raw_ostream;
namespace clang {
class ASTContext;
-class Interpreter;
class QualType;
+namespace caas {
+class Interpreter;
+
#if defined(_WIN32)
// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
// at runtime. On Windows, this requires them to be exported from any of the
@@ -138,6 +140,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
void *getPtr() const;
+ void **getPtrAddress() const;
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
#define X(type, name) \
@@ -204,6 +207,6 @@ template <> inline void *Value::as() const {
return Data.m_Ptr;
return (void *)as<uintptr_t>();
}
-
+} // namespace caas
} // namespace clang
#endif
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index e6ae4e19e81db9..15b34d33b01afd 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -34,6 +34,7 @@ set(core_files
tgmath.h
unwind.h
varargs.h
+ __clang_interpreter_runtime_printvalue.h
)
set(arm_common_files
diff --git a/clang/lib/Headers/__clang_interpreter_runtime_printvalue.h b/clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
new file mode 100644
index 00000000000000..707eb0723f092d
--- /dev/null
+++ b/clang/lib/Headers/__clang_interpreter_runtime_printvalue.h
@@ -0,0 +1,261 @@
+//===--- __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>
+#include <vector>
+
+// 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.
+template <class T,
+ typename std::enable_if<!std::is_pointer<T>::value>::type * = nullptr>
+inline std::string PrintValueRuntime(const T &) {
+ 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 {
+
+// Custom void_t implementation for C++11 compatibility
+template <typename... Ts> struct __repl_void_impl { typedef void type; };
+
+// Helper to deduce the type of the expression 'std::begin(std::declval<T &>())'
+template <typename T>
+using __repl_begin_result = decltype(std::begin(std::declval<T &>()));
+
+// Helper to deduce the type of the expression 'std::end(std::declval<T &>())'
+template <typename T>
+using __repl_end_result = decltype(std::end(std::declval<T &>()));
+
+// Type trait to check if a type is iterable
+template <typename T, typename = void>
+struct __is_iterable : std::false_type {};
+
+template <typename T>
+struct __is_iterable<T, typename __repl_void_impl<__repl_begin_result<T>,
+ __repl_end_result<T>>::type>
+ : std::true_type {};
+
+// Type trait to check if a type is std::pair
+template <typename T> struct __is_pair : std::false_type {};
+
+template <typename T, typename U>
+struct __is_pair<std::pair<T, U>> : std::true_type {};
+
+// Type trait to check if a type is std::map (or any associative container with
+// mapped_type)
+template <typename T, typename = void> struct __is_map : std::false_type {};
+
+template <typename T>
+struct __is_map<T, typename __repl_void_impl<typename T::mapped_type>::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;
+}
+
+struct __StdVectorBool {
+ bool Value;
+ __StdVectorBool(bool V) : Value(V) {}
+};
+template <typename T>
+std::string __PrintCollectionElt(const __StdVectorBool &Val) {
+ return PrintValueRuntime(&Val.Value);
+}
+
+} // 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);
+}
+
+// std::vector<bool>
+inline std::string PrintValueRuntime(const std::vector<bool> *Val) {
+ // Try our best to fix std::vector<bool> without too much of templated code.
+ std::vector<__repl_runtime_detail::__StdVectorBool> ValFixed(Val->begin(),
+ Val->end());
+ return PrintValueRuntime<decltype(ValFixed)>(&ValFixed);
+}
+
+// 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
diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt
index 9065f998f73c47..ea00bdc80f595d 100644
--- a/clang/lib/Interpreter/CMakeLists.txt
+++ b/clang/lib/Interpreter/CMakeLists.txt
@@ -20,6 +20,7 @@ add_clang_library(clangInterpreter
Interpreter.cpp
InterpreterUtils.cpp
Value.cpp
+ ValuePrinter.cpp
DEPENDS
intrinsics_gen
diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp
index fb42964e4936f2..9bbcce0ac0fe30 100644
--- a/clang/lib/Interpreter/DeviceOffload.cpp
+++ b/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 @@ llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
IncrementalCUDADeviceParser::~IncrementalCUDADeviceParser() {}
-} // namespace clang
+} // namespace clang::caas
diff --git a/clang/lib/Interpreter/DeviceOffload.h b/clang/lib/Interpreter/DeviceOffload.h
index ce4f218c94c79d..204f85b872cf64 100644
--- a/clang/lib/Interpreter/DeviceOffload.h
+++ b/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 @@ class IncrementalCUDADeviceParser : public IncrementalParser {
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
};
-} // namespace clang
+} // namespace clang::caas
#endif // LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 6f036107c14a9c..54f5d798384cb1 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -35,7 +35,7 @@ LLVM_ATTRIBUTE_USED void linkComponents() {
<< (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
}
-namespace clang {
+namespace clang::caas {
llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
IncrementalExecutor::createDefaultJITBuilder(
@@ -68,6 +68,10 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
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();
@@ -116,4 +120,4 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
return SymOrErr->getAddress();
}
-} // end namespace clang
+} // namespace clang::caas
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index b4347209e14fe3..b6e7ddae401869 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -32,9 +32,11 @@ class ThreadSafeContext;
namespace clang {
-struct PartialTranslationUnit;
class TargetInfo;
+namespace caas {
+struct PartialTranslationUnit;
+
class IncrementalExecutor {
using CtorDtorIterator = llvm::orc::CtorDtorIterator;
std::unique_ptr<llvm::orc::LLJIT> Jit;
@@ -50,6 +52,7 @@ class IncrementalExecutor {
llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
~IncrementalExecutor();
+ llvm::Error addModule(std::unique_ptr<llvm::Module> &M);
llvm::Error addModule(PartialTranslationUnit &PTU);
llvm::Error removeModule(PartialTranslationUnit &PTU);
llvm::Error runCtors() const;
@@ -62,7 +65,7 @@ class IncrementalExecutor {
static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
};
-
+} // namespace caas
} // end namespace clang
#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index ef90fe9e6f5451..0d96dbe77cdd3b 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -29,7 +29,7 @@
#include <sstream>
-namespace clang {
+namespace clang::caas {
class IncrementalASTConsumer final : public ASTConsumer {
Interpreter &Interp;
@@ -414,4 +414,5 @@ llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
assert(CG);
return CG->GetMangledName(GD);
}
-} // end namespace clang
+
+} // end namespace clang::caas
diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h
index f63bce50acd3b9..46bf6aa4051f8e 100644
--- a/clang/lib/Interpreter/IncrementalParser.h
+++ b/clang/lib/Interpreter/IncrementalParser.h
@@ -31,9 +31,11 @@ namespace clang {
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.
///
@@ -91,6 +93,7 @@ class IncrementalParser {
private:
llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
};
+} // namespace caas
} // end namespace clang
#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index b20e6efcebfd10..eb8b6592750467 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -43,7 +43,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 {
@@ -270,6 +270,7 @@ const char *const Runtimes = R"(
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
}
#endif // __cplusplus
+ #define __CLANG_REPL__ 1
)";
llvm::Expected<std::unique_ptr<Interpreter>>
@@ -409,6 +410,23 @@ llvm::Error Interpreter::CreateExecutor() {
void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
+
+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) {
@@ -532,6 +550,10 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
return AddrOrErr;
}
+std::unique_ptr<llvm::Module> Interpreter::GenModule() {
+ return IncrParser->GenModule();
+}
+
static constexpr llvm::StringRef MagicRuntimeInterface[] = {
"__clang_Interpreter_SetValueNoAlloc",
"__clang_Interpreter_SetValueWithAlloc",
@@ -589,8 +611,8 @@ class InterfaceKindVisitor
llvm::SmallVector<Expr *, 3> Args;
public:
- InterfaceKindVisitor(ASTContext &Ctx, Sema &S, Expr *E)
- : Ctx(Ctx), S(S), E(E) {}
+InterfaceKindVisitor(ASTContext &Ctx, Sema &S, Expr *E)
+ : Ctx(Ctx), S(S), E(E) {}
Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
return Interpreter::InterfaceKind::WithAlloc;
diff --git a/clang/lib/Interpreter/InterpreterUtils.cpp b/clang/lib/Interpreter/InterpreterUtils.cpp
index 45f6322b8461ed..86838c671192f1 100644
--- a/clang/lib/Interpreter/InterpreterUtils.cpp
+++ b/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 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
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 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
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 ElaboratedTypeKeyword::None, we never want
+ // the keyword (humm ... what about anonymous types?)
+ QT = Ctx.getElaboratedType(ElaboratedTypeKeyword::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
diff --git a/clang/lib/Interpreter/InterpreterUtils.h b/clang/lib/Interpreter/InterpreterUtils.h
index 8df158c17d4919..61c1cab822208c 100644
--- a/clang/lib/Interpreter/InterpreterUtils.h
+++ b/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 @@ NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name,
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
diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp
index eb2ce9c9fd3302..50e3fa3ff6fadc 100644
--- a/clang/lib/Interpreter/Value.cpp
+++ b/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"
@@ -22,6 +23,9 @@
#include <cstdint>
#include <utility>
+using namespace clang;
+using namespace clang::caas;
+
namespace {
// This is internal buffer maintained by Value, used to hold temporaries.
@@ -231,6 +235,11 @@ void *Value::getPtr() const {
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);
}
@@ -256,14 +265,32 @@ const ASTContext &Value::getASTContext() const {
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;
}
} // namespace clang
diff --git a/clang/lib/Interpreter/ValuePrinter.cpp b/clang/lib/Interpreter/ValuePrinter.cpp
new file mode 100644
index 00000000000000..565b170b04e29d
--- /dev/null
+++ b/clang/lib/Interpreter/ValuePrinter.cpp
@@ -0,0 +1,564 @@
+//===--- 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/Lex/Preprocessor.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;
+ }
+ }
+
+ llvm::SmallString<24> ApStr;
+ AP.toString(ApStr, /*Radix=*/10);
+
+ SS << " : " << PrintQualType(Ctx, ED->getIntegerType()) << " " << ApStr;
+ 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;
+}
+
+// FIXME: Encodings. Handle unprintable characters such as control characters.
+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
diff --git a/clang/test/Interpreter/pretty-print.cpp b/clang/test/Interpreter/pretty-print.cpp
new file mode 100644
index 00000000000000..6a489d3550aa0b
--- /dev/null
+++ b/clang/test/Interpreter/pretty-print.cpp
@@ -0,0 +1,206 @@
+// 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 -std=c++11 -Xcc -fno-delayed-template-parsing | FileCheck %s
+extern "C" int printf(const char*,...);
+
+char c = 'a';
+c
+// CHECK: (char) 'a'
+
+struct NonPOD { \
+ static int sI; \
+ int I; \
+ NonPOD(): I(sI++) {} \
+};
+const char* PrintValueRuntime(const NonPOD* type) { \
+ switch (type->I) { \
+ default: return "out-of-bounds"; \
+ case 0: return "0"; case 1: return "1"; case 2: return "2"; \
+ case 3: return "3"; case 4: return "4"; case 5: return "5"; \
+ } \
+}
+
+int NonPOD::sI = 0;
+
+NonPOD non_pod_arr[2][3];
+// Check array order after the value printing transformation. Also make sure we
+// can handle the forward declaration of operator new with placement.
+non_pod_arr
+// CHECK-NEXT: (NonPOD[2][3]) { { 0, 1, 2 }, { 3, 4, 5 } }
+
+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 *) @0x{{[0-9a-f]+}}
+
+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 &) @0x{{[0-9a-f]+}}
+
+S1{}
+// CHECK-NEXT: (S1) @0x{{[0-9a-f]+}}
+
+struct S2 {int d;} E = {22};
+E
+// CHECK-NEXT: (struct S2 &) @0x{{[0-9a-f]+}}
+E.d
+// CHECK-NEXT: (int) 22
+
+struct S3 { int* p; S3() { p = new int(42); } ~S3() { delete p; } };
+S3{}
+// CHECK-NEXT: (S3) @0x{{[0-9a-f]+}}
+S3 s3;
+s3
+// CHECK-NEXT: (S3 &) @0x{{[0-9a-f]+}}
+
+struct S4 { ~S4() { printf("~S4()\n"); }};
+S4{}
+// CHECK-NEXT: (S4) @0x{{[0-9a-f]+}}
+
+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
+
+// Arrays.
+
+int arr[3] = {1,2,3};
+arr
+// CHECK-NEXT: (int[3]) { 1, 2, 3 }
+
+
+// Lambdas.
+
+auto Lambda1 = []{};
+Lambda1
+// CHECK-NEXT: ((lambda) &) @0x{{[0-9a-f]+}}
+[]{}
+// CHECK-NEXT: ((lambda at input_line_{{[0-9]+}}:1:1)) @0x{{[0-9a-f]+}}
+
+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_{{[0-9]+}}: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 @0x{{[0-9a-f]+}}
+
+#include <memory>
+
+auto p1 = std::make_shared<int>(42);
+p1
+// CHECK-NEXT: (std::shared_ptr<int> &) std::shared_ptr -> @0x{{[0-9a-f]+}}
+
+std::unique_ptr<int> p2(new int(42));
+p2
+// CHECK-NEXT: (std::unique_ptr<int> &) std::unique_ptr -> @0x{{[0-9a-f]+}}
+
+#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
+
diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt
index d3dec1984b78d2..2b7d5f01418919 100644
--- a/clang/tools/clang-repl/CMakeLists.txt
+++ b/clang/tools/clang-repl/CMakeLists.txt
@@ -11,6 +11,65 @@ add_clang_tool(clang-repl
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 at std@@3Unothrow_t at 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 at YAPEAX_K@Z
+ ??3 at YAXPEAX@Z
+ ??_U at YAPEAX_K@Z
+ ??_V at YAXPEAX@Z
+ ??3 at YAXPEAX_K@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QEAAAEAV01 at H@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QEAAAEAV01 at M@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QEAAAEAV01 at N@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QEAAAEAV01 at PEBX@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QEAAAEAV01 at P6AAEAV01@AEAV01@@Z at Z
+ ??$?6U?$char_traits at D@std@@@std@@YAAEAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AEAV10@D at Z
+ ??$?6U?$char_traits at D@std@@@std@@YAAEAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AEAV10@PEBD at Z
+ ?_Facet_Register at std@@YAXPEAV_Facet_base at 1@@Z
+ )
+ else()
+ set(clang_repl_exports ${clang_repl_exports}
+ ??2 at YAPAXI@Z
+ ??3 at YAXPAX@Z
+ ??3 at YAXPAXI@Z
+ ??_U at YAPAXI@Z
+ ??_V at YAXPAX@Z
+ ??_V at YAXPAXI@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QAEAAV01 at H@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QAEAAV01 at M@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QAEAAV01 at N@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QAEAAV01 at PBX@Z
+ ??6?$basic_ostream at DU?$char_traits at D@std@@@std@@QAEAAV01 at P6AAAV01@AAV01@@Z at Z
+ ??$?6U?$char_traits at D@std@@@std@@YAAAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AAV10@D at Z
+ ??$?6U?$char_traits at D@std@@@std@@YAAAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AAV10@PBD at Z
+ ?_Facet_Register at std@@YAXPAV_Facet_base at 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
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index aecf61b97fc719..022ab35c93312c 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -82,10 +82,10 @@ static int checkDiagErrors(const clang::CompilerInstance *CI, bool HasError) {
}
struct ReplListCompleter {
- clang::IncrementalCompilerBuilder &CB;
- clang::Interpreter &MainInterp;
- ReplListCompleter(clang::IncrementalCompilerBuilder &CB,
- clang::Interpreter &Interp)
+ clang::caas::IncrementalCompilerBuilder &CB;
+ clang::caas::Interpreter &MainInterp;
+ ReplListCompleter(clang::caas::IncrementalCompilerBuilder &CB,
+ clang::caas::Interpreter &Interp)
: CB(CB), MainInterp(Interp){};
std::vector<llvm::LineEditor::Completion> operator()(llvm::StringRef Buffer,
@@ -117,7 +117,7 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos,
size_t Lines =
std::count(Buffer.begin(), std::next(Buffer.begin(), Pos), '\n') + 1;
- auto Interp = clang::Interpreter::create(std::move(*CI));
+ auto Interp = clang::caas::Interpreter::create(std::move(*CI));
if (auto Err = Interp.takeError()) {
// log the error and returns an empty vector;
@@ -165,7 +165,7 @@ int main(int argc, const char **argv) {
return 0;
}
- clang::IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
CB.SetCompilerArgs(ClangArgv);
std::unique_ptr<clang::CompilerInstance> DeviceCI;
@@ -200,11 +200,10 @@ int main(int argc, const char **argv) {
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"));
@@ -213,7 +212,7 @@ int main(int argc, const char **argv) {
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))
diff --git a/clang/unittests/Interpreter/CodeCompletionTest.cpp b/clang/unittests/Interpreter/CodeCompletionTest.cpp
index 873fbda32f0579..f487530f66a778 100644
--- a/clang/unittests/Interpreter/CodeCompletionTest.cpp
+++ b/clang/unittests/Interpreter/CodeCompletionTest.cpp
@@ -13,14 +13,14 @@
using namespace clang;
namespace {
-auto CB = clang::IncrementalCompilerBuilder();
+auto CB = clang::caas::IncrementalCompilerBuilder();
-static std::unique_ptr<Interpreter> createInterpreter() {
+static std::unique_ptr<clang::caas::Interpreter> createInterpreter() {
auto CI = cantFail(CB.CreateCpp());
- return cantFail(clang::Interpreter::create(std::move(CI)));
+ return cantFail(clang::caas::Interpreter::create(std::move(CI)));
}
-static std::vector<std::string> runComp(clang::Interpreter &MainInterp,
+static std::vector<std::string> runComp(clang::caas::Interpreter &MainInterp,
llvm::StringRef Input,
llvm::Error &ErrR) {
auto CI = CB.CreateCpp();
@@ -29,7 +29,7 @@ static std::vector<std::string> runComp(clang::Interpreter &MainInterp,
return {};
}
- auto Interp = clang::Interpreter::create(std::move(*CI));
+ auto Interp = clang::caas::Interpreter::create(std::move(*CI));
if (auto Err = Interp.takeError()) {
// log the error and returns an empty vector;
ErrR = std::move(Err);
diff --git a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
index 2f1c4efb381f00..be9c5f7c01a517 100644
--- a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
+++ b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
@@ -38,6 +38,7 @@ LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
#endif
using namespace clang;
+using namespace clang::caas;
namespace {
using Args = std::vector<const char *>;
@@ -46,12 +47,12 @@ createInterpreter(const Args &ExtraArgs = {},
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) {
diff --git a/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp b/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp
index f729566f7efde6..4e9b0270a80a4e 100644
--- a/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp
+++ b/clang/unittests/Interpreter/IncrementalCompilerBuilderTest.cpp
@@ -29,7 +29,7 @@ static void cleanupRemappedFileBuffers(CompilerInstance &CI) {
TEST(IncrementalCompilerBuilder, SetCompilerArgs) {
std::vector<const char *> ClangArgv = {"-Xclang", "-ast-dump-all"};
- auto CB = clang::IncrementalCompilerBuilder();
+ auto CB = clang::caas::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgv);
auto CI = cantFail(CB.CreateCpp());
EXPECT_TRUE(CI->getFrontendOpts().ASTDumpAll);
@@ -37,7 +37,7 @@ TEST(IncrementalCompilerBuilder, SetCompilerArgs) {
}
TEST(IncrementalCompilerBuilder, SetTargetTriple) {
- auto CB = clang::IncrementalCompilerBuilder();
+ auto CB = clang::caas::IncrementalCompilerBuilder();
CB.SetTargetTriple("armv6-none-eabi");
auto CI = cantFail(CB.CreateCpp());
EXPECT_EQ(CI->getTargetOpts().Triple, "armv6-none-unknown-eabi");
diff --git a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp
index accdf682896340..7f64c5378a21fb 100644
--- a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp
+++ b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp
@@ -27,6 +27,7 @@
using namespace llvm;
using namespace clang;
+using namespace clang::caas;
namespace {
@@ -52,12 +53,12 @@ const Function *getGlobalInit(llvm::Module *M) {
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);
diff --git a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
index b971cd550dc507..47a9600e99f910 100644
--- a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
@@ -35,6 +35,7 @@
#endif
using namespace clang;
+using namespace clang::caas;
namespace {
static bool HostSupportsJit() {
@@ -104,7 +105,7 @@ TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
if (!HostSupportsJit())
GTEST_SKIP();
- clang::IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
llvm::Error ErrOut = llvm::Error::success();
TestCreateResetExecutor Interp(cantFail(CB.CreateCpp()), ErrOut);
cantFail(std::move(ErrOut));
@@ -156,7 +157,7 @@ class RecordRuntimeIBMetrics : public Interpreter {
};
TEST(InterpreterExtensionsTest, FindRuntimeInterface) {
- clang::IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
llvm::Error ErrOut = llvm::Error::success();
RecordRuntimeIBMetrics Interp(cantFail(CB.CreateCpp()), ErrOut);
cantFail(std::move(ErrOut));
@@ -203,7 +204,7 @@ TEST(InterpreterExtensionsTest, DefaultCrossJIT) {
if (!IsARMTargetRegistered())
GTEST_SKIP();
- IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
CB.SetTargetTriple("armv6-none-eabi");
auto CI = cantFail(CB.CreateCpp());
llvm::Error ErrOut = llvm::Error::success();
@@ -222,7 +223,7 @@ TEST(InterpreterExtensionsTest, CustomCrossJIT) {
std::string TargetTriple = "armv6-none-eabi";
- IncrementalCompilerBuilder CB;
+ clang::caas::IncrementalCompilerBuilder CB;
CB.SetTargetTriple(TargetTriple);
auto CI = cantFail(CB.CreateCpp());
llvm::Error ErrOut = llvm::Error::success();
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index 69bc2da242884e..53c51809ca7319 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/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 @@ createInterpreter(const Args &ExtraArgs = {},
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) {
>From 8a5190882a8863badefe302a45580c3ef0704abb Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Thu, 20 Jul 2023 19:51:25 +0000
Subject: [PATCH 2/2] Store state
---
clang/include/clang/AST/ASTContext.h | 2 ++
clang/include/clang/Interpreter/Interpreter.h | 10 ++++++++++
clang/lib/Interpreter/IncrementalExecutor.cpp | 4 ----
clang/lib/Interpreter/IncrementalExecutor.h | 1 -
clang/lib/Interpreter/Interpreter.cpp | 1 -
clang/lib/Interpreter/ValuePrinter.cpp | 17 ++++++++++-------
6 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 28f8d67811f0a2..9c4638cd6cccab 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1071,6 +1071,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; }
TranslationUnitDecl *getTranslationUnitDecl() const {
+ assert(TUDecl->getMostRecentDecl() == TUDecl &&
+ "The active TU is not current one!");
return TUDecl->getMostRecentDecl();
}
void addTranslationUnitDecl() {
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 43331b0fe92c96..0df53c13bddbdb 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -140,6 +140,14 @@ class Interpreter {
public:
virtual ~Interpreter();
+ class SynthesizingCodeRAII {
+
+ };
+
+ SynthesizingCodeRAII EnterCodeSynthesisScope() {
+
+ }
+
static llvm::Expected<std::unique_ptr<Interpreter>>
create(std::unique_ptr<CompilerInstance> CI);
static llvm::Expected<std::unique_ptr<Interpreter>>
@@ -187,6 +195,8 @@ class Interpreter {
std::unique_ptr<llvm::Module> GenModule();
+
+
private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 54f5d798384cb1..490ad21fdde722 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -68,10 +68,6 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
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();
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index b6e7ddae401869..c2073a72156c10 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -52,7 +52,6 @@ class IncrementalExecutor {
llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
~IncrementalExecutor();
- llvm::Error addModule(std::unique_ptr<llvm::Module> &M);
llvm::Error addModule(PartialTranslationUnit &PTU);
llvm::Error removeModule(PartialTranslationUnit &PTU);
llvm::Error runCtors() const;
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index eb8b6592750467..1469cf757add5a 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -410,7 +410,6 @@ llvm::Error Interpreter::CreateExecutor() {
void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
-
llvm::Error Interpreter::ExecuteModule(std::unique_ptr<llvm::Module> &M) {
if (!IncrExecutor) {
auto Err = CreateExecutor();
diff --git a/clang/lib/Interpreter/ValuePrinter.cpp b/clang/lib/Interpreter/ValuePrinter.cpp
index 565b170b04e29d..3f8c9a6f26cbbf 100644
--- a/clang/lib/Interpreter/ValuePrinter.cpp
+++ b/clang/lib/Interpreter/ValuePrinter.cpp
@@ -115,11 +115,9 @@ static std::string PrintEnum(const Value &V) {
IsFirst = false;
}
}
-
- llvm::SmallString<24> ApStr;
- AP.toString(ApStr, /*Radix=*/10);
-
- SS << " : " << PrintQualType(Ctx, ED->getIntegerType()) << " " << ApStr;
+ llvm::SmallString<64> APStr;
+ AP.toString(APStr, /*Radix=*/10);
+ SS << " : " << PrintQualType(Ctx, ED->getIntegerType()) << " " << APStr;
return Str;
}
@@ -279,10 +277,15 @@ static llvm::Expected<llvm::orc::ExecutorAddr> CompileDecl(Interpreter &Interp,
ASTConsumer &Consumer = Interp.getCompilerInstance()->getASTConsumer();
Consumer.HandleTopLevelDecl(DeclGroupRef(D));
Interp.getCompilerInstance()->getSema().PerformPendingInstantiations();
- Consumer.HandleTranslationUnit(Interp.getASTContext());
+ ASTContext &C = Interp.getASTContext();
+ TranslationUnitDecl *TUPart = C.getTranslationUnitDecl();
+ assert(!TUPart->containsDecl(D) && "Decl already added!");
+ TUPart->addDecl(D);
+ Consumer.HandleTranslationUnit(C);
if (std::unique_ptr<llvm::Module> M = Interp.GenModule()) {
- if (llvm::Error Err = Interp.ExecuteModule(M))
+ PartialTranslationUnit PTU = {TUPart, std::move(M)};
+ if (llvm::Error Err = Interp.Execute(PTU))
return Err;
ASTNameGenerator ASTNameGen(Interp.getASTContext());
llvm::Expected<llvm::orc::ExecutorAddr> AddrOrErr =
More information about the cfe-commits
mailing list