Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply [PATCH] [clang-repl] Add a interpreter-specific overload of op… #28

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class Interpreter {
llvm::Expected<llvm::orc::ExecutorAddr>
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;

enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };

const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
return ValuePrintingInfo;
Expand All @@ -143,7 +143,7 @@ class Interpreter {

llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;

llvm::SmallVector<Expr *, 3> ValuePrintingInfo;
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
};
} // namespace clang

Expand Down
33 changes: 27 additions & 6 deletions clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,26 @@ Interpreter::~Interpreter() {
// can't find the precise resource directory in unittests so we have to hard
// code them.
const char *const Runtimes = R"(
void* operator new(__SIZE_TYPE__, void* __p) noexcept;
#ifdef __cplusplus
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
struct __clang_Interpreter_NewTag{} __ci_newtag;
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
template <class T, class = T (*)() /*disable for arrays*/>
void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
for (auto Idx = 0; Idx < Size; ++Idx)
new ((void*)(((T*)Placement) + Idx)) T(Src[Idx]);
new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
}
template <class T, unsigned long N>
void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
}
#endif // __cplusplus
)";

llvm::Expected<std::unique_ptr<Interpreter>>
Expand All @@ -280,7 +283,7 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
if (!PTU)
return PTU.takeError();

Interp->ValuePrintingInfo.resize(3);
Interp->ValuePrintingInfo.resize(4);
// FIXME: This is a ugly hack. Undo command checks its availability by looking
// at the size of the PTU list. However we have parsed something in the
// beginning of the REPL so we have to mark them as 'Irrevocable'.
Expand Down Expand Up @@ -497,7 +500,7 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
static constexpr llvm::StringRef MagicRuntimeInterface[] = {
"__clang_Interpreter_SetValueNoAlloc",
"__clang_Interpreter_SetValueWithAlloc",
"__clang_Interpreter_SetValueCopyArr"};
"__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};

bool Interpreter::FindRuntimeInterface() {
if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
Expand Down Expand Up @@ -527,6 +530,9 @@ bool Interpreter::FindRuntimeInterface() {
if (!LookupInterface(ValuePrintingInfo[CopyArray],
MagicRuntimeInterface[CopyArray]))
return false;
if (!LookupInterface(ValuePrintingInfo[NewTag],
MagicRuntimeInterface[NewTag]))
return false;
return true;
}

Expand Down Expand Up @@ -604,7 +610,9 @@ class RuntimeInterfaceBuilder
.getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
SourceLocation(), Args, SourceLocation());
}
Expr *Args[] = {AllocCall.get()};
Expr *Args[] = {
AllocCall.get(),
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
ExprResult CXXNewCall = S.BuildCXXNew(
E->getSourceRange(),
/*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
Expand All @@ -625,8 +633,9 @@ class RuntimeInterfaceBuilder
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
E->getBeginLoc(), Args, E->getEndLoc());
}
default:
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
}
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
}

Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
Expand Down Expand Up @@ -811,3 +820,15 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
VRef.setLongDouble(Val);
}

// A trampoline to work around the fact that operator placement new cannot
// really be forward declared due to libc++ and libstdc++ declaration mismatch.
// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
// definition in the interpreter runtime. We should move it in a runtime header
// which gets included by the interpreter and here.
struct __clang_Interpreter_NewTag {};
REPL_EXTERNAL_VISIBILITY void *
operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
// Just forward to the standard operator placement new.
return operator new(__sz, __p);
}
3 changes: 2 additions & 1 deletion clang/test/Interpreter/incremental-mode.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// RUN: clang-repl -Xcc -E
// RUN: clang-repl -Xcc -emit-llvm
// RUN: clang-repl -Xcc -emit-llvm
// RUN: clang-repl -Xcc -xc
// expected-no-diagnostics
29 changes: 5 additions & 24 deletions clang/unittests/Interpreter/InterpreterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,28 +248,10 @@ TEST(IncrementalProcessing, FindMangledNameSymbol) {
#endif // _WIN32
}

static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
static Value AllocateObject(TypeDecl *TD, Interpreter &Interp) {
std::string Name = TD->getQualifiedNameAsString();
const clang::Type *RDTy = TD->getTypeForDecl();
clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
size_t Size = C.getTypeSize(RDTy);
void *Addr = malloc(Size);

// Tell the interpreter to call the default ctor with this memory. Synthesize:
// new (loc) ClassName;
static unsigned Counter = 0;
std::stringstream SS;
SS << "auto _v" << Counter++ << " = "
<< "new ((void*)"
// Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
<< std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";

auto R = Interp.ParseAndExecute(SS.str());
if (!R) {
free(Addr);
return nullptr;
}

Value Addr;
cantFail(Interp.ParseAndExecute("new " + Name + "()", &Addr));
return Addr;
}

Expand Down Expand Up @@ -317,7 +299,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) {
}

TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
void *NewA = AllocateObject(TD, *Interp);
Value NewA = AllocateObject(TD, *Interp);

// Find back the template specialization
VarDecl *VD = static_cast<VarDecl *>(*PTUDeclRange.begin());
Expand All @@ -328,8 +310,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) {
typedef int (*TemplateSpecFn)(void *);
auto fn =
cantFail(Interp->getSymbolAddress(MangledName)).toPtr<TemplateSpecFn>();
EXPECT_EQ(42, fn(NewA));
free(NewA);
EXPECT_EQ(42, fn(NewA.getPtr()));
}

#ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC
Expand Down