Skip to content

Commit 899519f

Browse files
committed
[clang-repl] Lay the basic infrastructure for pretty printing of types.
The idea is to store a type-value pair in clang::Value which is updated by the interpreter runtime. The class copies builtin types and boxes non-builtin types to provide some lifetime control. The patch enables default printers for C and C++ using a very minimalistic approach. We handle enums, arrays and user types. Once we land this we can focus on enabling user-defined pretty-printers which take control over printing of types The work started as part of https://reviews.llvm.org/D146809, then we created a giant in #84769
1 parent ce8c19f commit 899519f

File tree

13 files changed

+609
-73
lines changed

13 files changed

+609
-73
lines changed

clang/include/clang/AST/ASTContext.h

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

11941194
TranslationUnitDecl *getTranslationUnitDecl() const {
1195+
assert(TUDecl->getMostRecentDecl() == TUDecl &&
1196+
"The active TU is not current one!");
11951197
return TUDecl->getMostRecentDecl();
11961198
}
11971199
void addTranslationUnitDecl() {

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,23 +175,15 @@ class Interpreter {
175175
llvm::Expected<llvm::orc::ExecutorAddr>
176176
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
177177

178-
const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
179-
return ValuePrintingInfo;
180-
}
181-
182-
Expr *SynthesizeExpr(Expr *E);
178+
std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
179+
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
180+
std::unique_ptr<llvm::Module> M = {},
181+
IncrementalAction *Action = nullptr);
183182

184183
private:
185184
size_t getEffectivePTUSize() const;
186185
void markUserCodeStart();
187186
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
188-
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
189-
190-
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
191-
std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
192-
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
193-
std::unique_ptr<llvm::Module> M = {},
194-
IncrementalAction *Action = nullptr);
195187

196188
// A cache for the compiled destructors used to for de-allocation of managed
197189
// clang::Values.
@@ -200,6 +192,24 @@ class Interpreter {
200192
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
201193

202194
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;
195+
196+
/// @}
197+
/// @name Value and pretty printing support
198+
/// @{
199+
200+
std::string ValueDataToString(const Value &V);
201+
std::string ValueTypeToString(const Value &V) const;
202+
203+
llvm::Expected<Expr *> convertExprToValue(Expr *E);
204+
205+
// When we deallocate clang::Value we need to run the destructor of the type.
206+
// This function forces emission of the needed dtor.
207+
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
208+
209+
/// @}
210+
/// @name Code generation
211+
/// @{
212+
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
203213
};
204214
} // namespace clang
205215

clang/include/clang/Interpreter/Value.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ class REPL_EXTERNAL_VISIBILITY Value {
119119
~Value();
120120

121121
void printType(llvm::raw_ostream &Out) const;
122-
void printData(llvm::raw_ostream &Out) const;
123-
void print(llvm::raw_ostream &Out) const;
124-
void dump() const;
122+
void printData(llvm::raw_ostream &Out);
123+
void print(llvm::raw_ostream &Out);
124+
void dump();
125125
void clear();
126126

127127
ASTContext &getASTContext();
@@ -205,6 +205,5 @@ template <> inline void *Value::as() const {
205205
return Data.m_Ptr;
206206
return (void *)as<uintptr_t>();
207207
}
208-
209208
} // namespace clang
210209
#endif

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_clang_library(clangInterpreter
2929
InterpreterUtils.cpp
3030
RemoteJITUtils.cpp
3131
Value.cpp
32+
InterpreterValuePrinter.cpp
3233
${WASM_SRC}
3334
PARTIAL_SOURCES_INTENDED
3435

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class InProcessPrintingASTConsumer final : public MultiplexConsumer {
264264
if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
265265
if (TLSD && TLSD->isSemiMissing()) {
266266
auto ExprOrErr =
267-
Interp.ExtractValueFromExpr(cast<Expr>(TLSD->getStmt()));
267+
Interp.convertExprToValue(cast<Expr>(TLSD->getStmt()));
268268
if (llvm::Error E = ExprOrErr.takeError()) {
269269
llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),
270270
"Value printing failed: ");
@@ -416,6 +416,8 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
416416
return;
417417
}
418418
}
419+
420+
ValuePrintingInfo.resize(4);
419421
}
420422

421423
Interpreter::~Interpreter() {
@@ -440,11 +442,10 @@ const char *const Runtimes = R"(
440442
#define __CLANG_REPL__ 1
441443
#ifdef __cplusplus
442444
#define EXTERN_C extern "C"
443-
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
444445
struct __clang_Interpreter_NewTag{} __ci_newtag;
445446
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
446447
template <class T, class = T (*)() /*disable for arrays*/>
447-
void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
448+
void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
448449
for (auto Idx = 0; Idx < Size; ++Idx)
449450
new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
450451
}
@@ -454,8 +455,12 @@ const char *const Runtimes = R"(
454455
}
455456
#else
456457
#define EXTERN_C extern
458+
EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
459+
EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
460+
memcpy(Placement, Src, Size);
461+
}
457462
#endif // __cplusplus
458-
463+
EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
459464
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
460465
)";
461466

@@ -470,12 +475,12 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI,
470475

471476
// Add runtime code and set a marker to hide it from user code. Undo will not
472477
// go through that.
473-
auto PTU = Interp->Parse(Runtimes);
474-
if (!PTU)
475-
return PTU.takeError();
478+
Err = Interp->ParseAndExecute(Runtimes);
479+
if (Err)
480+
return std::move(Err);
481+
476482
Interp->markUserCodeStart();
477483

478-
Interp->ValuePrintingInfo.resize(4);
479484
return std::move(Interp);
480485
}
481486

@@ -524,12 +529,11 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
524529
return std::move(Interp);
525530
}
526531

532+
CompilerInstance *Interpreter::getCompilerInstance() { return CI.get(); }
527533
const CompilerInstance *Interpreter::getCompilerInstance() const {
528-
return CI.get();
534+
return const_cast<Interpreter *>(this)->getCompilerInstance();
529535
}
530536

531-
CompilerInstance *Interpreter::getCompilerInstance() { return CI.get(); }
532-
533537
llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
534538
if (!IncrExecutor) {
535539
if (auto Err = CreateExecutor())
@@ -610,7 +614,14 @@ Interpreter::Parse(llvm::StringRef Code) {
610614
if (!TuOrErr)
611615
return TuOrErr.takeError();
612616

613-
return RegisterPTU(*TuOrErr);
617+
PTUs.emplace_back(PartialTranslationUnit());
618+
PartialTranslationUnit &LastPTU = PTUs.back();
619+
LastPTU.TUPart = *TuOrErr;
620+
621+
if (std::unique_ptr<llvm::Module> M = GenModule())
622+
LastPTU.TheModule = std::move(M);
623+
624+
return LastPTU;
614625
}
615626

616627
static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
@@ -806,13 +817,13 @@ Interpreter::GenModule(IncrementalAction *Action) {
806817
// of the module which does not map well to CodeGen's design. To work this
807818
// around we created an empty module to make CodeGen happy. We should make
808819
// sure it always stays empty.
809-
assert(((!CachedInCodeGenModule ||
810-
!getCompilerInstance()->getPreprocessorOpts().Includes.empty()) ||
811-
(CachedInCodeGenModule->empty() &&
820+
assert((!CachedInCodeGenModule ||
821+
!getCompilerInstance()->getPreprocessorOpts().Includes.empty()) ||
822+
((CachedInCodeGenModule->empty() &&
812823
CachedInCodeGenModule->global_empty() &&
813824
CachedInCodeGenModule->alias_empty() &&
814825
CachedInCodeGenModule->ifunc_empty())) &&
815-
"CodeGen wrote to a readonly module");
826+
"CodeGen wrote to a readonly module");
816827
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
817828
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
818829
return M;
@@ -828,4 +839,4 @@ CodeGenerator *Interpreter::getCodeGen(IncrementalAction *Action) const {
828839
return nullptr;
829840
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
830841
}
831-
} // namespace clang
842+
} // end namespace clang

clang/lib/Interpreter/InterpreterUtils.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "InterpreterUtils.h"
14+
#include "clang/AST/QualTypeNames.h"
1415

1516
namespace clang {
1617

@@ -81,7 +82,7 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
8182
else {
8283
const DeclContext *PrimaryWithin = nullptr;
8384
if (const auto *TD = dyn_cast<TagDecl>(Within))
84-
PrimaryWithin = llvm::dyn_cast_or_null<DeclContext>(TD->getDefinition());
85+
PrimaryWithin = dyn_cast_if_present<DeclContext>(TD->getDefinition());
8586
else
8687
PrimaryWithin = Within->getPrimaryContext();
8788

@@ -97,15 +98,16 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
9798
R.resolveKind();
9899

99100
if (R.isSingleResult())
100-
return llvm::dyn_cast<NamedDecl>(R.getFoundDecl());
101+
return dyn_cast<NamedDecl>(R.getFoundDecl());
101102

102103
return nullptr;
103104
}
104105

105106
std::string GetFullTypeName(ASTContext &Ctx, QualType QT) {
107+
QualType FQT = TypeName::getFullyQualifiedType(QT, Ctx);
106108
PrintingPolicy Policy(Ctx.getPrintingPolicy());
107109
Policy.SuppressScope = false;
108110
Policy.AnonymousTagLocations = false;
109-
return QT.getAsString(Policy);
111+
return FQT.getAsString(Policy);
110112
}
111113
} // namespace clang

clang/lib/Interpreter/InterpreterUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name,
4545
const DeclContext *Within = nullptr);
4646

4747
NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
48-
const DeclContext *Within);
48+
const DeclContext *Within = nullptr);
4949

5050
std::string GetFullTypeName(ASTContext &Ctx, QualType QT);
5151
} // namespace clang

0 commit comments

Comments
 (0)