diff options
author | Vassil Vassilev <v.g.vassilev@gmail.com> | 2024-01-18 16:06:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-18 16:06:04 +0200 |
commit | 1566f1ffc6b52bee659071d460123c1c4a358d01 (patch) | |
tree | efc4ab60b9841879dde13bf9d0d52adf3b4fc8d8 /clang/lib/Interpreter/Interpreter.cpp | |
parent | e6a6a90fe739d5f792645bf237eb0e540fad8c69 (diff) | |
download | llvm-1566f1ffc6b52bee659071d460123c1c4a358d01.zip llvm-1566f1ffc6b52bee659071d460123c1c4a358d01.tar.gz llvm-1566f1ffc6b52bee659071d460123c1c4a358d01.tar.bz2 |
[clang-repl] Add a interpreter-specific overload of operator new for C++ (#76218)
This patch brings back the basic support for C by inserting the required
for value printing runtime only when we are in C++ mode. Additionally,
it defines a new overload of operator placement new because we can't
really forward declare it in a library-agnostic way.
Fixes the issue described in llvm/llvm-project#69072.
Diffstat (limited to 'clang/lib/Interpreter/Interpreter.cpp')
-rw-r--r-- | clang/lib/Interpreter/Interpreter.cpp | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 734fe90..d1764d0 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -249,7 +249,7 @@ 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*); @@ -257,15 +257,18 @@ const char *const Runtimes = R"( 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>> @@ -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'. @@ -501,7 +504,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; })) @@ -531,6 +534,9 @@ bool Interpreter::FindRuntimeInterface() { if (!LookupInterface(ValuePrintingInfo[CopyArray], MagicRuntimeInterface[CopyArray])) return false; + if (!LookupInterface(ValuePrintingInfo[NewTag], + MagicRuntimeInterface[NewTag])) + return false; return true; } @@ -608,7 +614,9 @@ public: .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, @@ -629,8 +637,9 @@ public: 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) { @@ -815,3 +824,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); +} |