Skip to content

Commit 0ff8aca

Browse files
committed
[clang-repl] Lay the foundation of pretty printing for C.
1 parent 253c28f commit 0ff8aca

File tree

3 files changed

+103
-80
lines changed

3 files changed

+103
-80
lines changed

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 94 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
#include "llvm/Support/ErrorHandling.h"
4343
#include "llvm/Support/raw_ostream.h"
4444
#include "llvm/TargetParser/Host.h"
45+
46+
#include <cstdarg>
47+
4548
using namespace clang;
4649

4750
// FIXME: Figure out how to unify with namespace init_convenience from
@@ -250,14 +253,10 @@ Interpreter::~Interpreter() {
250253
// can't find the precise resource directory in unittests so we have to hard
251254
// code them.
252255
const char *const Runtimes = R"(
256+
#define __CLANG_REPL__ 1
253257
#ifdef __cplusplus
258+
#define EXTERN_C extern "C"
254259
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
255-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
256-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
257-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
258-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
259-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
260-
void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
261260
struct __clang_Interpreter_NewTag{} __ci_newtag;
262261
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
263262
template <class T, class = T (*)() /*disable for arrays*/>
@@ -269,7 +268,11 @@ const char *const Runtimes = R"(
269268
void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
270269
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
271270
}
271+
#else
272+
#define EXTERN_C extern
272273
#endif // __cplusplus
274+
275+
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
273276
)";
274277

275278
llvm::Expected<std::unique_ptr<Interpreter>>
@@ -564,15 +567,17 @@ std::unique_ptr<RuntimeInterfaceBuilder> Interpreter::FindRuntimeInterface() {
564567
if (!LookupInterface(ValuePrintingInfo[NoAlloc],
565568
MagicRuntimeInterface[NoAlloc]))
566569
return nullptr;
567-
if (!LookupInterface(ValuePrintingInfo[WithAlloc],
568-
MagicRuntimeInterface[WithAlloc]))
569-
return nullptr;
570-
if (!LookupInterface(ValuePrintingInfo[CopyArray],
571-
MagicRuntimeInterface[CopyArray]))
572-
return nullptr;
573-
if (!LookupInterface(ValuePrintingInfo[NewTag],
574-
MagicRuntimeInterface[NewTag]))
575-
return nullptr;
570+
if (Ctx.getLangOpts().CPlusPlus) {
571+
if (!LookupInterface(ValuePrintingInfo[WithAlloc],
572+
MagicRuntimeInterface[WithAlloc]))
573+
return nullptr;
574+
if (!LookupInterface(ValuePrintingInfo[CopyArray],
575+
MagicRuntimeInterface[CopyArray]))
576+
return nullptr;
577+
if (!LookupInterface(ValuePrintingInfo[NewTag],
578+
MagicRuntimeInterface[NewTag]))
579+
return nullptr;
580+
}
576581

577582
return createInProcessRuntimeInterfaceBuilder(*this, Ctx, S);
578583
}
@@ -831,69 +836,82 @@ __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
831836
return VRef.getPtr();
832837
}
833838

834-
// Pointers, lvalue struct that can take as a reference.
835-
REPL_EXTERNAL_VISIBILITY void
836-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
837-
void *Val) {
838-
Value &VRef = *(Value *)OutVal;
839-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
840-
VRef.setPtr(Val);
841-
}
842-
843-
REPL_EXTERNAL_VISIBILITY void
844-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
845-
void *OpaqueType) {
839+
REPL_EXTERNAL_VISIBILITY
840+
extern "C" void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
841+
void *OpaqueType, ...) {
846842
Value &VRef = *(Value *)OutVal;
847-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
848-
}
849-
850-
static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
851-
QualType QT = V.getType();
852-
if (const auto *ET = QT->getAs<EnumType>())
853-
QT = ET->getDecl()->getIntegerType();
854-
855-
switch (QT->castAs<BuiltinType>()->getKind()) {
856-
default:
857-
llvm_unreachable("unknown type kind!");
858-
#define X(type, name) \
859-
case BuiltinType::name: \
860-
V.set##name(Data); \
861-
break;
862-
REPL_BUILTIN_TYPES
863-
#undef X
843+
Interpreter *I = static_cast<Interpreter *>(This);
844+
VRef = Value(I, OpaqueType);
845+
if (VRef.isVoid())
846+
return;
847+
848+
va_list args;
849+
va_start(args, /*last named param*/ OpaqueType);
850+
851+
QualType QT = VRef.getType();
852+
if (VRef.getKind() == Value::K_PtrOrObj) {
853+
VRef.setPtr(va_arg(args, void *));
854+
} else {
855+
if (const auto *ET = QT->getAs<EnumType>())
856+
QT = ET->getDecl()->getIntegerType();
857+
switch (QT->castAs<BuiltinType>()->getKind()) {
858+
default:
859+
llvm_unreachable("unknown type kind!");
860+
break;
861+
// Types shorter than int are resolved as int, else va_arg has UB.
862+
case BuiltinType::Bool:
863+
VRef.setBool(va_arg(args, int));
864+
break;
865+
case BuiltinType::Char_S:
866+
VRef.setChar_S(va_arg(args, int));
867+
break;
868+
case BuiltinType::SChar:
869+
VRef.setSChar(va_arg(args, int));
870+
break;
871+
case BuiltinType::Char_U:
872+
VRef.setChar_U(va_arg(args, unsigned));
873+
break;
874+
case BuiltinType::UChar:
875+
VRef.setUChar(va_arg(args, unsigned));
876+
break;
877+
case BuiltinType::Short:
878+
VRef.setShort(va_arg(args, int));
879+
break;
880+
case BuiltinType::UShort:
881+
VRef.setUShort(va_arg(args, unsigned));
882+
break;
883+
case BuiltinType::Int:
884+
VRef.setInt(va_arg(args, int));
885+
break;
886+
case BuiltinType::UInt:
887+
VRef.setUInt(va_arg(args, unsigned));
888+
break;
889+
case BuiltinType::Long:
890+
VRef.setLong(va_arg(args, long));
891+
break;
892+
case BuiltinType::ULong:
893+
VRef.setULong(va_arg(args, unsigned long));
894+
break;
895+
case BuiltinType::LongLong:
896+
VRef.setLongLong(va_arg(args, long long));
897+
break;
898+
case BuiltinType::ULongLong:
899+
VRef.setULongLong(va_arg(args, unsigned long long));
900+
break;
901+
// Types shorter than double are resolved as double, else va_arg has UB.
902+
case BuiltinType::Float:
903+
VRef.setFloat(va_arg(args, double));
904+
break;
905+
case BuiltinType::Double:
906+
VRef.setDouble(va_arg(args, double));
907+
break;
908+
case BuiltinType::LongDouble:
909+
VRef.setLongDouble(va_arg(args, long double));
910+
break;
911+
// See REPL_BUILTIN_TYPES.
912+
}
864913
}
865-
}
866-
867-
REPL_EXTERNAL_VISIBILITY void
868-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
869-
unsigned long long Val) {
870-
Value &VRef = *(Value *)OutVal;
871-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
872-
SetValueDataBasedOnQualType(VRef, Val);
873-
}
874-
875-
REPL_EXTERNAL_VISIBILITY void
876-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
877-
float Val) {
878-
Value &VRef = *(Value *)OutVal;
879-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
880-
VRef.setFloat(Val);
881-
}
882-
883-
REPL_EXTERNAL_VISIBILITY void
884-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
885-
double Val) {
886-
Value &VRef = *(Value *)OutVal;
887-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
888-
VRef.setDouble(Val);
889-
}
890-
891-
REPL_EXTERNAL_VISIBILITY void
892-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
893-
long double Val) {
894-
Value &VRef = *(Value *)OutVal;
895-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
896-
VRef.setLongDouble(Val);
914+
va_end(args);
897915
}
898916

899917
// A trampoline to work around the fact that operator placement new cannot

clang/lib/Parse/ParseStmt.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,8 @@ StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) {
563563
}
564564

565565
Token *CurTok = nullptr;
566-
// If the semicolon is missing at the end of REPL input, consider if
567-
// we want to do value printing. Note this is only enabled in C++ mode
568-
// since part of the implementation requires C++ language features.
569566
// Note we shouldn't eat the token since the callback needs it.
570-
if (Tok.is(tok::annot_repl_input_end) && Actions.getLangOpts().CPlusPlus)
567+
if (Tok.is(tok::annot_repl_input_end))
571568
CurTok = &Tok;
572569
else
573570
// Otherwise, eat the semicolon.

clang/test/Interpreter/pretty-print.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// REQUIRES: host-supports-jit
2+
// UNSUPPORTED: system-aix
3+
// RUN: cat %s | clang-repl -Xcc -xc | FileCheck %s
4+
// RUN: cat %s | clang-repl -Xcc -std=c++11 | FileCheck %s
5+
6+
const char* c_str = "Hello, world!"; c_str
7+
8+
// CHECK: Not implement yet.

0 commit comments

Comments
 (0)