Skip to content

Commit 0007e48

Browse files
vgvassilevgiordano
authored andcommitted
[clang-repl] Add a interpreter-specific overload of operator new for C++ (llvm#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#69072. (cherry picked from commit 1566f1f)
1 parent d01c08c commit 0007e48

File tree

4 files changed

+36
-33
lines changed

4 files changed

+36
-33
lines changed

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class Interpreter {
128128
llvm::Expected<llvm::orc::ExecutorAddr>
129129
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
130130

131-
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
131+
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
132132

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

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

146-
llvm::SmallVector<Expr *, 3> ValuePrintingInfo;
146+
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
147147
};
148148
} // namespace clang
149149

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,23 +250,26 @@ Interpreter::~Interpreter() {
250250
// can't find the precise resource directory in unittests so we have to hard
251251
// code them.
252252
const char *const Runtimes = R"(
253-
void* operator new(__SIZE_TYPE__, void* __p) noexcept;
253+
#ifdef __cplusplus
254254
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
255255
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*);
256256
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*);
257257
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float);
258258
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double);
259259
void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double);
260260
void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long);
261+
struct __clang_Interpreter_NewTag{} __ci_newtag;
262+
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
261263
template <class T, class = T (*)() /*disable for arrays*/>
262264
void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
263265
for (auto Idx = 0; Idx < Size; ++Idx)
264-
new ((void*)(((T*)Placement) + Idx)) T(Src[Idx]);
266+
new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
265267
}
266268
template <class T, unsigned long N>
267269
void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
268270
__clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
269271
}
272+
#endif // __cplusplus
270273
)";
271274

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

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

502505
bool Interpreter::FindRuntimeInterface() {
503506
if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
@@ -527,6 +530,9 @@ bool Interpreter::FindRuntimeInterface() {
527530
if (!LookupInterface(ValuePrintingInfo[CopyArray],
528531
MagicRuntimeInterface[CopyArray]))
529532
return false;
533+
if (!LookupInterface(ValuePrintingInfo[NewTag],
534+
MagicRuntimeInterface[NewTag]))
535+
return false;
530536
return true;
531537
}
532538

@@ -604,7 +610,9 @@ class RuntimeInterfaceBuilder
604610
.getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
605611
SourceLocation(), Args, SourceLocation());
606612
}
607-
Expr *Args[] = {AllocCall.get()};
613+
Expr *Args[] = {
614+
AllocCall.get(),
615+
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
608616
ExprResult CXXNewCall = S.BuildCXXNew(
609617
E->getSourceRange(),
610618
/*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
@@ -625,8 +633,9 @@ class RuntimeInterfaceBuilder
625633
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
626634
E->getBeginLoc(), Args, E->getEndLoc());
627635
}
636+
default:
637+
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
628638
}
629-
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
630639
}
631640

632641
Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
@@ -811,3 +820,15 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
811820
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
812821
VRef.setLongDouble(Val);
813822
}
823+
824+
// A trampoline to work around the fact that operator placement new cannot
825+
// really be forward declared due to libc++ and libstdc++ declaration mismatch.
826+
// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
827+
// definition in the interpreter runtime. We should move it in a runtime header
828+
// which gets included by the interpreter and here.
829+
struct __clang_Interpreter_NewTag {};
830+
REPL_EXTERNAL_VISIBILITY void *
831+
operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
832+
// Just forward to the standard operator placement new.
833+
return operator new(__sz, __p);
834+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
// RUN: clang-repl -Xcc -E
2-
// RUN: clang-repl -Xcc -emit-llvm
2+
// RUN: clang-repl -Xcc -emit-llvm
3+
// RUN: clang-repl -Xcc -xc
34
// expected-no-diagnostics

clang/unittests/Interpreter/InterpreterTest.cpp

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -248,28 +248,10 @@ TEST(IncrementalProcessing, FindMangledNameSymbol) {
248248
#endif // _WIN32
249249
}
250250

251-
static void *AllocateObject(TypeDecl *TD, Interpreter &Interp) {
251+
static Value AllocateObject(TypeDecl *TD, Interpreter &Interp) {
252252
std::string Name = TD->getQualifiedNameAsString();
253-
const clang::Type *RDTy = TD->getTypeForDecl();
254-
clang::ASTContext &C = Interp.getCompilerInstance()->getASTContext();
255-
size_t Size = C.getTypeSize(RDTy);
256-
void *Addr = malloc(Size);
257-
258-
// Tell the interpreter to call the default ctor with this memory. Synthesize:
259-
// new (loc) ClassName;
260-
static unsigned Counter = 0;
261-
std::stringstream SS;
262-
SS << "auto _v" << Counter++ << " = "
263-
<< "new ((void*)"
264-
// Windows needs us to prefix the hexadecimal value of a pointer with '0x'.
265-
<< std::hex << std::showbase << (size_t)Addr << ")" << Name << "();";
266-
267-
auto R = Interp.ParseAndExecute(SS.str());
268-
if (!R) {
269-
free(Addr);
270-
return nullptr;
271-
}
272-
253+
Value Addr;
254+
cantFail(Interp.ParseAndExecute("new " + Name + "()", &Addr));
273255
return Addr;
274256
}
275257

@@ -317,7 +299,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) {
317299
}
318300

319301
TypeDecl *TD = cast<TypeDecl>(LookupSingleName(*Interp, "A"));
320-
void *NewA = AllocateObject(TD, *Interp);
302+
Value NewA = AllocateObject(TD, *Interp);
321303

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

335316
#ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC

0 commit comments

Comments
 (0)