Skip to content

Commit 7091dfc

Browse files
authored
[clang-repl] Lay the foundation of pretty printing for C. (#89811)
1 parent 6c9bce8 commit 7091dfc

File tree

3 files changed

+100
-78
lines changed

3 files changed

+100
-78
lines changed

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 91 additions & 74 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
@@ -270,14 +273,10 @@ Interpreter::~Interpreter() {
270273
// can't find the precise resource directory in unittests so we have to hard
271274
// code them.
272275
const char *const Runtimes = R"(
276+
#define __CLANG_REPL__ 1
273277
#ifdef __cplusplus
278+
#define EXTERN_C extern "C"
274279
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
275-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
276-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
277-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
278-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
279-
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
280-
void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
281280
struct __clang_Interpreter_NewTag{} __ci_newtag;
282281
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
283282
template <class T, class = T (*)() /*disable for arrays*/>
@@ -289,7 +288,11 @@ const char *const Runtimes = R"(
289288
void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
290289
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
291290
}
291+
#else
292+
#define EXTERN_C extern
292293
#endif // __cplusplus
294+
295+
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
293296
)";
294297

295298
llvm::Expected<std::unique_ptr<Interpreter>>
@@ -588,15 +591,17 @@ std::unique_ptr<RuntimeInterfaceBuilder> Interpreter::FindRuntimeInterface() {
588591
if (!LookupInterface(ValuePrintingInfo[NoAlloc],
589592
MagicRuntimeInterface[NoAlloc]))
590593
return nullptr;
591-
if (!LookupInterface(ValuePrintingInfo[WithAlloc],
592-
MagicRuntimeInterface[WithAlloc]))
593-
return nullptr;
594-
if (!LookupInterface(ValuePrintingInfo[CopyArray],
595-
MagicRuntimeInterface[CopyArray]))
596-
return nullptr;
597-
if (!LookupInterface(ValuePrintingInfo[NewTag],
598-
MagicRuntimeInterface[NewTag]))
599-
return nullptr;
594+
if (Ctx.getLangOpts().CPlusPlus) {
595+
if (!LookupInterface(ValuePrintingInfo[WithAlloc],
596+
MagicRuntimeInterface[WithAlloc]))
597+
return nullptr;
598+
if (!LookupInterface(ValuePrintingInfo[CopyArray],
599+
MagicRuntimeInterface[CopyArray]))
600+
return nullptr;
601+
if (!LookupInterface(ValuePrintingInfo[NewTag],
602+
MagicRuntimeInterface[NewTag]))
603+
return nullptr;
604+
}
600605

601606
return createInProcessRuntimeInterfaceBuilder(*this, Ctx, S);
602607
}
@@ -855,69 +860,81 @@ __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
855860
return VRef.getPtr();
856861
}
857862

858-
// Pointers, lvalue struct that can take as a reference.
859-
REPL_EXTERNAL_VISIBILITY void
860-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
861-
void *Val) {
863+
extern "C" void REPL_EXTERNAL_VISIBILITY __clang_Interpreter_SetValueNoAlloc(
864+
void *This, void *OutVal, void *OpaqueType, ...) {
862865
Value &VRef = *(Value *)OutVal;
863-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
864-
VRef.setPtr(Val);
865-
}
866+
Interpreter *I = static_cast<Interpreter *>(This);
867+
VRef = Value(I, OpaqueType);
868+
if (VRef.isVoid())
869+
return;
866870

867-
REPL_EXTERNAL_VISIBILITY void
868-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
869-
void *OpaqueType) {
870-
Value &VRef = *(Value *)OutVal;
871-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
872-
}
871+
va_list args;
872+
va_start(args, /*last named param*/ OpaqueType);
873873

874-
static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) {
875-
QualType QT = V.getType();
876-
if (const auto *ET = QT->getAs<EnumType>())
877-
QT = ET->getDecl()->getIntegerType();
878-
879-
switch (QT->castAs<BuiltinType>()->getKind()) {
880-
default:
881-
llvm_unreachable("unknown type kind!");
882-
#define X(type, name) \
883-
case BuiltinType::name: \
884-
V.set##name(Data); \
885-
break;
886-
REPL_BUILTIN_TYPES
887-
#undef X
874+
QualType QT = VRef.getType();
875+
if (VRef.getKind() == Value::K_PtrOrObj) {
876+
VRef.setPtr(va_arg(args, void *));
877+
} else {
878+
if (const auto *ET = QT->getAs<EnumType>())
879+
QT = ET->getDecl()->getIntegerType();
880+
switch (QT->castAs<BuiltinType>()->getKind()) {
881+
default:
882+
llvm_unreachable("unknown type kind!");
883+
break;
884+
// Types shorter than int are resolved as int, else va_arg has UB.
885+
case BuiltinType::Bool:
886+
VRef.setBool(va_arg(args, int));
887+
break;
888+
case BuiltinType::Char_S:
889+
VRef.setChar_S(va_arg(args, int));
890+
break;
891+
case BuiltinType::SChar:
892+
VRef.setSChar(va_arg(args, int));
893+
break;
894+
case BuiltinType::Char_U:
895+
VRef.setChar_U(va_arg(args, unsigned));
896+
break;
897+
case BuiltinType::UChar:
898+
VRef.setUChar(va_arg(args, unsigned));
899+
break;
900+
case BuiltinType::Short:
901+
VRef.setShort(va_arg(args, int));
902+
break;
903+
case BuiltinType::UShort:
904+
VRef.setUShort(va_arg(args, unsigned));
905+
break;
906+
case BuiltinType::Int:
907+
VRef.setInt(va_arg(args, int));
908+
break;
909+
case BuiltinType::UInt:
910+
VRef.setUInt(va_arg(args, unsigned));
911+
break;
912+
case BuiltinType::Long:
913+
VRef.setLong(va_arg(args, long));
914+
break;
915+
case BuiltinType::ULong:
916+
VRef.setULong(va_arg(args, unsigned long));
917+
break;
918+
case BuiltinType::LongLong:
919+
VRef.setLongLong(va_arg(args, long long));
920+
break;
921+
case BuiltinType::ULongLong:
922+
VRef.setULongLong(va_arg(args, unsigned long long));
923+
break;
924+
// Types shorter than double are resolved as double, else va_arg has UB.
925+
case BuiltinType::Float:
926+
VRef.setFloat(va_arg(args, double));
927+
break;
928+
case BuiltinType::Double:
929+
VRef.setDouble(va_arg(args, double));
930+
break;
931+
case BuiltinType::LongDouble:
932+
VRef.setLongDouble(va_arg(args, long double));
933+
break;
934+
// See REPL_BUILTIN_TYPES.
935+
}
888936
}
889-
}
890-
891-
REPL_EXTERNAL_VISIBILITY void
892-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
893-
unsigned long long Val) {
894-
Value &VRef = *(Value *)OutVal;
895-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
896-
SetValueDataBasedOnQualType(VRef, Val);
897-
}
898-
899-
REPL_EXTERNAL_VISIBILITY void
900-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
901-
float Val) {
902-
Value &VRef = *(Value *)OutVal;
903-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
904-
VRef.setFloat(Val);
905-
}
906-
907-
REPL_EXTERNAL_VISIBILITY void
908-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
909-
double Val) {
910-
Value &VRef = *(Value *)OutVal;
911-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
912-
VRef.setDouble(Val);
913-
}
914-
915-
REPL_EXTERNAL_VISIBILITY void
916-
__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
917-
long double Val) {
918-
Value &VRef = *(Value *)OutVal;
919-
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
920-
VRef.setLongDouble(Val);
937+
va_end(args);
921938
}
922939

923940
// 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
@@ -571,11 +571,8 @@ StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) {
571571
}
572572

573573
Token *CurTok = nullptr;
574-
// If the semicolon is missing at the end of REPL input, consider if
575-
// we want to do value printing. Note this is only enabled in C++ mode
576-
// since part of the implementation requires C++ language features.
577574
// Note we shouldn't eat the token since the callback needs it.
578-
if (Tok.is(tok::annot_repl_input_end) && Actions.getLangOpts().CPlusPlus)
575+
if (Tok.is(tok::annot_repl_input_end))
579576
CurTok = &Tok;
580577
else
581578
// 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)