From 0fca5b2ad0a6859286b3d7c73f34a433ae2282a5 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Tue, 7 May 2024 22:03:07 +0900 Subject: [PATCH] Apply [PATCH] [clang-repl] Add a interpreter-specific overload of operator new for C++. --- clang/include/clang/Interpreter/Interpreter.h | 4 +-- clang/lib/Interpreter/Interpreter.cpp | 33 +++++++++++++++---- clang/test/Interpreter/incremental-mode.cpp | 3 +- .../unittests/Interpreter/InterpreterTest.cpp | 29 +++------------- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 43573fb1a4b891..c1f118153fb87b 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -128,7 +128,7 @@ class Interpreter { llvm::Expected getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; - enum InterfaceKind { NoAlloc, WithAlloc, CopyArray }; + enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag }; const llvm::SmallVectorImpl &getValuePrintingInfo() const { return ValuePrintingInfo; @@ -143,7 +143,7 @@ class Interpreter { llvm::DenseMap Dtors; - llvm::SmallVector ValuePrintingInfo; + llvm::SmallVector ValuePrintingInfo; }; } // namespace clang diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 4e1045298537b1..28799f04c82b19 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -250,7 +250,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*); @@ -258,15 +258,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 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 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) { __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size); } +#endif // __cplusplus )"; llvm::Expected> @@ -280,7 +283,7 @@ Interpreter::create(std::unique_ptr 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'. @@ -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; })) @@ -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; } @@ -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, @@ -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) { @@ -811,3 +820,15 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, VRef = Value(static_cast(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); +} diff --git a/clang/test/Interpreter/incremental-mode.cpp b/clang/test/Interpreter/incremental-mode.cpp index e6350d237ef578..d63cee0dd6d15f 100644 --- a/clang/test/Interpreter/incremental-mode.cpp +++ b/clang/test/Interpreter/incremental-mode.cpp @@ -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 diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index 5f2911e9a7adad..1e0854b3c4af46 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -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; } @@ -317,7 +299,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { } TypeDecl *TD = cast(LookupSingleName(*Interp, "A")); - void *NewA = AllocateObject(TD, *Interp); + Value NewA = AllocateObject(TD, *Interp); // Find back the template specialization VarDecl *VD = static_cast(*PTUDeclRange.begin()); @@ -328,8 +310,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { typedef int (*TemplateSpecFn)(void *); auto fn = cantFail(Interp->getSymbolAddress(MangledName)).toPtr(); - EXPECT_EQ(42, fn(NewA)); - free(NewA); + EXPECT_EQ(42, fn(NewA.getPtr())); } #ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC