Skip to content

Commit a618d30

Browse files
committed
[clang-repl] Implement value printing of custom types.
Differential revision: https://reviews.llvm.org/D146809
1 parent b4feb26 commit a618d30

22 files changed

+1487
-19
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
10991099
bool isInSameModule(const Module *M1, const Module *M2);
11001100

11011101
TranslationUnitDecl *getTranslationUnitDecl() const {
1102+
assert(TUDecl->getMostRecentDecl() == TUDecl &&
1103+
"The active TU is not current one!");
11021104
return TUDecl->getMostRecentDecl();
11031105
}
11041106
void addTranslationUnitDecl() {

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class ThreadSafeContext;
3838
namespace clang {
3939

4040
class CompilerInstance;
41+
4142
class IncrementalExecutor;
4243
class IncrementalParser;
4344

@@ -131,6 +132,14 @@ class Interpreter {
131132
public:
132133
virtual ~Interpreter();
133134

135+
// class SynthesizingCodeRAII {
136+
137+
// };
138+
139+
// SynthesizingCodeRAII EnterCodeSynthesisScope() {
140+
141+
// }
142+
134143
static llvm::Expected<std::unique_ptr<Interpreter>>
135144
create(std::unique_ptr<CompilerInstance> CI);
136145
static llvm::Expected<std::unique_ptr<Interpreter>>
@@ -175,6 +184,8 @@ class Interpreter {
175184

176185
Expr *SynthesizeExpr(Expr *E);
177186

187+
std::unique_ptr<llvm::Module> GenModule();
188+
178189
private:
179190
size_t getEffectivePTUSize() const;
180191
void markUserCodeStart();

clang/include/clang/Interpreter/Value.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ class raw_ostream;
4949
namespace clang {
5050

5151
class ASTContext;
52-
class Interpreter;
5352
class QualType;
5453

54+
class Interpreter;
55+
5556
#if defined(_WIN32)
5657
// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
5758
// at runtime. On Windows, this requires them to be exported from any of the
@@ -138,6 +139,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
138139
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
139140

140141
void *getPtr() const;
142+
void **getPtrAddress() const;
141143
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
142144

143145
#define X(type, name) \
@@ -204,6 +206,5 @@ template <> inline void *Value::as() const {
204206
return Data.m_Ptr;
205207
return (void *)as<uintptr_t>();
206208
}
207-
208209
} // namespace clang
209210
#endif

clang/lib/Headers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(core_files
3636
tgmath.h
3737
unwind.h
3838
varargs.h
39+
__clang_interpreter_runtime_printvalue.h
3940
)
4041

4142
set(arm_common_files
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
//===--- __clang_interpreter_runtime_printvalue.h ---*- C++
2+
//-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines runtime functions used to print STL components in
11+
// clang-repl. They are very heavy so we should only include it once and on
12+
// demand.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
#ifndef LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
16+
#define LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
17+
18+
#if !defined(__CLANG_REPL__)
19+
#error "This file should only be included by clang-repl!"
20+
#endif
21+
22+
namespace caas {
23+
namespace runtime {}
24+
} // namespace caas
25+
using namespace caas::runtime;
26+
27+
#include <memory>
28+
#include <string>
29+
#include <tuple>
30+
#include <type_traits>
31+
#include <vector>
32+
33+
// FIXME: We should include it somewhere instead of duplicating it...
34+
#if __has_attribute(visibility) && \
35+
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
36+
(defined(__MINGW32__) && defined(__clang__)))
37+
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
38+
#define __REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
39+
#else
40+
#define __REPL_EXTERNAL_VISIBILITY
41+
#endif
42+
#else
43+
#if defined(_WIN32)
44+
#define __REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
45+
#endif
46+
#endif
47+
48+
// Fallback.
49+
template <class T,
50+
typename std::enable_if<!std::is_pointer<T>::value>::type * = nullptr>
51+
inline std::string PrintValueRuntime(const T &) {
52+
return "{not representable}";
53+
}
54+
55+
// Forward declare the pre-compiled printing functions.
56+
#ifndef __DECL_PRINT_VALUE_RUNTIME
57+
#define __DECL_PRINT_VALUE_RUNTIME(type) \
58+
__REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const type *__Ptr)
59+
__DECL_PRINT_VALUE_RUNTIME(void); //
60+
__DECL_PRINT_VALUE_RUNTIME(void *); //
61+
__DECL_PRINT_VALUE_RUNTIME(char *const); //
62+
__DECL_PRINT_VALUE_RUNTIME(char *); //
63+
__DECL_PRINT_VALUE_RUNTIME(bool);
64+
__DECL_PRINT_VALUE_RUNTIME(char);
65+
__DECL_PRINT_VALUE_RUNTIME(signed char);
66+
__DECL_PRINT_VALUE_RUNTIME(short);
67+
__DECL_PRINT_VALUE_RUNTIME(unsigned short);
68+
__DECL_PRINT_VALUE_RUNTIME(int);
69+
__DECL_PRINT_VALUE_RUNTIME(unsigned int);
70+
__DECL_PRINT_VALUE_RUNTIME(long);
71+
__DECL_PRINT_VALUE_RUNTIME(unsigned long);
72+
__DECL_PRINT_VALUE_RUNTIME(long long);
73+
__DECL_PRINT_VALUE_RUNTIME(unsigned long long);
74+
__DECL_PRINT_VALUE_RUNTIME(float);
75+
__DECL_PRINT_VALUE_RUNTIME(double);
76+
__DECL_PRINT_VALUE_RUNTIME(long double);
77+
#endif
78+
79+
namespace __repl_runtime_detail {
80+
81+
// Custom void_t implementation for C++11 compatibility
82+
template <typename... Ts> struct __repl_void_impl {
83+
typedef void type;
84+
};
85+
86+
// Helper to deduce the type of the expression 'std::begin(std::declval<T &>())'
87+
template <typename T>
88+
using __repl_begin_result = decltype(std::begin(std::declval<T &>()));
89+
90+
// Helper to deduce the type of the expression 'std::end(std::declval<T &>())'
91+
template <typename T>
92+
using __repl_end_result = decltype(std::end(std::declval<T &>()));
93+
94+
// Type trait to check if a type is iterable
95+
template <typename T, typename = void>
96+
struct __is_iterable : std::false_type {};
97+
98+
template <typename T>
99+
struct __is_iterable<T, typename __repl_void_impl<__repl_begin_result<T>,
100+
__repl_end_result<T>>::type>
101+
: std::true_type {};
102+
103+
// Type trait to check if a type is std::pair
104+
template <typename T> struct __is_pair : std::false_type {};
105+
106+
template <typename T, typename U>
107+
struct __is_pair<std::pair<T, U>> : std::true_type {};
108+
109+
// Type trait to check if a type is std::map (or any associative container with
110+
// mapped_type)
111+
template <typename T, typename = void> struct __is_map : std::false_type {};
112+
113+
template <typename T>
114+
struct __is_map<T, typename __repl_void_impl<typename T::mapped_type>::type>
115+
: std::true_type {};
116+
117+
// The type of the elements is std::pair, and the container is a map like type.
118+
template <
119+
typename Container, typename Elt,
120+
typename std::enable_if<__is_pair<Elt>::value && __is_map<Container>::value,
121+
bool>::type = true>
122+
std::string __PrintCollectionElt(const Elt &Val) {
123+
return PrintValueRuntime(&Val.first) + " => " +
124+
PrintValueRuntime(&Val.second);
125+
}
126+
127+
// The type of the elements is std::pair, and the container isn't a map-like
128+
// type.
129+
template <typename Container, typename Elt,
130+
typename std::enable_if<__is_pair<Elt>::value &&
131+
!__is_map<Container>::value,
132+
bool>::type = true>
133+
std::string __PrintCollectionElt(const Elt &Val) {
134+
return TuplePairPrintValue(&Val);
135+
}
136+
137+
template <typename Container, typename Elt,
138+
typename std::enable_if<!__is_pair<Elt>::value, bool>::type = true>
139+
std::string __PrintCollectionElt(const Elt &Val) {
140+
return PrintValueRuntime(&Val);
141+
}
142+
143+
template <class Tuple, std::size_t N = std::tuple_size<Tuple>(),
144+
std::size_t TupleSize = std::tuple_size<Tuple>()>
145+
struct __TupleLikePrinter {
146+
static std::string print(const Tuple *T) {
147+
constexpr std::size_t EltNum = TupleSize - N;
148+
std::string Str;
149+
// Not the first element.
150+
if (EltNum != 0)
151+
Str += ", ";
152+
Str += PrintValueRuntime(&std::get<EltNum>(*T));
153+
// If N+1 is not smaller than the size of the tuple,
154+
// reroute the call to the printing function to the
155+
// no-op specialisation to stop recursion.
156+
constexpr std::size_t Nm1 = N - 1;
157+
Str += __TupleLikePrinter<Tuple, Nm1>::print((const Tuple *)T);
158+
return Str;
159+
}
160+
};
161+
162+
template <class Tuple, std::size_t TupleSize>
163+
struct __TupleLikePrinter<Tuple, 0, TupleSize> {
164+
static std::string print(const Tuple *T) { return ""; }
165+
};
166+
167+
template <class T> inline std::string TuplePairPrintValue(const T *Val) {
168+
std::string Str("{ ");
169+
Str += __TupleLikePrinter<T>::print(Val);
170+
Str += " }";
171+
return Str;
172+
}
173+
174+
struct __StdVectorBool {
175+
bool Value;
176+
__StdVectorBool(bool V) : Value(V) {}
177+
};
178+
template <typename T>
179+
std::string __PrintCollectionElt(const __StdVectorBool &Val) {
180+
return PrintValueRuntime(&Val.Value);
181+
}
182+
183+
} // namespace __repl_runtime_detail
184+
185+
template <typename Container,
186+
typename std::enable_if<
187+
__repl_runtime_detail::__is_iterable<Container>::value,
188+
bool>::type = true>
189+
inline std::string PrintValueRuntime(const Container *C) {
190+
std::string Str("{ ");
191+
192+
for (auto Beg = C->begin(), End = C->end(); Beg != End; Beg++) {
193+
if (Beg != C->begin())
194+
Str += ", ";
195+
Str += __repl_runtime_detail::__PrintCollectionElt<Container>(*Beg);
196+
}
197+
Str += " }";
198+
return Str;
199+
}
200+
201+
template <typename T, size_t N>
202+
inline std::string PrintValueRuntime(const T (*Obj)[N]) {
203+
if (N == 0)
204+
return "{}";
205+
206+
std::string Str = "{ ";
207+
for (size_t Idx = 0; Idx < N; ++Idx) {
208+
Str += PrintValueRuntime(*Obj + Idx);
209+
if (Idx < N - 1)
210+
Str += ", ";
211+
}
212+
return Str + " }";
213+
}
214+
215+
template <size_t N> inline std::string PrintValueRuntime(const char (*Obj)[N]) {
216+
const auto *Str = reinterpret_cast<const char *const>(Obj);
217+
return PrintValueRuntime(&Str);
218+
}
219+
220+
// std::vector<bool>
221+
inline std::string PrintValueRuntime(const std::vector<bool> *Val) {
222+
// Try our best to fix std::vector<bool> without too much of templated code.
223+
std::vector<__repl_runtime_detail::__StdVectorBool> ValFixed(Val->begin(),
224+
Val->end());
225+
return PrintValueRuntime<decltype(ValFixed)>(&ValFixed);
226+
}
227+
228+
// tuple
229+
template <typename... Ts>
230+
inline std::string PrintValueRuntime(const std::tuple<Ts...> *Val) {
231+
using T = std::tuple<Ts...>;
232+
return __repl_runtime_detail::TuplePairPrintValue<T>(Val);
233+
}
234+
235+
// pair
236+
template <typename... Ts>
237+
inline std::string PrintValueRuntime(const std::pair<Ts...> *Val) {
238+
using T = std::pair<Ts...>;
239+
return __repl_runtime_detail::TuplePairPrintValue<T>(Val);
240+
}
241+
242+
// unique_ptr
243+
template <class T>
244+
inline std::string PrintValueRuntime(const std::unique_ptr<T> *Val) {
245+
auto Ptr = Val->get();
246+
return "std::unique_ptr -> " + PrintValueRuntime((const void **)&Ptr);
247+
}
248+
249+
// shared_ptr
250+
template <class T>
251+
inline std::string PrintValueRuntime(const std::shared_ptr<T> *Val) {
252+
auto Ptr = Val->get();
253+
return "std::shared_ptr -> " + PrintValueRuntime((const void **)&Ptr);
254+
}
255+
256+
// weak_ptr
257+
template <class T>
258+
inline std::string PrintValueRuntime(const std::weak_ptr<T> *Val) {
259+
auto Ptr = Val->lock().get();
260+
return "std::weak_ptr -> " + PrintValueRuntime((const void **)&Ptr);
261+
}
262+
263+
// string
264+
template <class T>
265+
inline std::string PrintValueRuntime(const std::basic_string<T> *Val) {
266+
const char *Chars = Val->c_str();
267+
return PrintValueRuntime((const char **)&Chars);
268+
}
269+
#endif

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_clang_library(clangInterpreter
2424
Interpreter.cpp
2525
InterpreterUtils.cpp
2626
Value.cpp
27+
ValuePrinter.cpp
2728
${WASM_SRC}
2829
PARTIAL_SOURCES_INTENDED
2930

clang/lib/Interpreter/IncrementalExecutor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,4 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
118118
return SymOrErr->getAddress();
119119
}
120120

121-
} // end namespace clang
121+
} // namespace clang

clang/lib/Interpreter/IncrementalExecutor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ class ThreadSafeContext;
3232

3333
namespace clang {
3434

35-
struct PartialTranslationUnit;
3635
class TargetInfo;
3736

37+
struct PartialTranslationUnit;
38+
3839
class IncrementalExecutor {
3940
using CtorDtorIterator = llvm::orc::CtorDtorIterator;
4041
std::unique_ptr<llvm::orc::LLJIT> Jit;
@@ -65,7 +66,6 @@ class IncrementalExecutor {
6566
static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
6667
createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
6768
};
68-
6969
} // end namespace clang
7070

7171
#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H

clang/lib/Interpreter/IncrementalParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,4 +424,5 @@ llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
424424
assert(CG);
425425
return CG->GetMangledName(GD);
426426
}
427+
427428
} // end namespace clang

clang/lib/Interpreter/IncrementalParser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ namespace clang {
3131
class ASTConsumer;
3232
class CodeGenerator;
3333
class CompilerInstance;
34+
class Parser;
35+
3436
class IncrementalAction;
3537
class Interpreter;
36-
class Parser;
3738
/// Provides support for incremental compilation. Keeps track of the state
3839
/// changes between the subsequent incremental input.
3940
///

0 commit comments

Comments
 (0)