Skip to content

Commit 1566f1f

Browse files
authored
[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 #69072.
1 parent e6a6a90 commit 1566f1f

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
@@ -129,7 +129,7 @@ class Interpreter {
129129
llvm::Expected<llvm::orc::ExecutorAddr>
130130
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
131131

132-
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
132+
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
133133

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

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

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

clang/lib/Interpreter/Interpreter.cpp

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

271274
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'.
@@ -501,7 +504,7 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
501504
static constexpr llvm::StringRef MagicRuntimeInterface[] = {
502505
"__clang_Interpreter_SetValueNoAlloc",
503506
"__clang_Interpreter_SetValueWithAlloc",
504-
"__clang_Interpreter_SetValueCopyArr"};
507+
"__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
505508

506509
bool Interpreter::FindRuntimeInterface() {
507510
if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
@@ -531,6 +534,9 @@ bool Interpreter::FindRuntimeInterface() {
531534
if (!LookupInterface(ValuePrintingInfo[CopyArray],
532535
MagicRuntimeInterface[CopyArray]))
533536
return false;
537+
if (!LookupInterface(ValuePrintingInfo[NewTag],
538+
MagicRuntimeInterface[NewTag]))
539+
return false;
534540
return true;
535541
}
536542

@@ -608,7 +614,9 @@ class RuntimeInterfaceBuilder
608614
.getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
609615
SourceLocation(), Args, SourceLocation());
610616
}
611-
Expr *Args[] = {AllocCall.get()};
617+
Expr *Args[] = {
618+
AllocCall.get(),
619+
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
612620
ExprResult CXXNewCall = S.BuildCXXNew(
613621
E->getSourceRange(),
614622
/*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
@@ -629,8 +637,9 @@ class RuntimeInterfaceBuilder
629637
Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
630638
E->getBeginLoc(), Args, E->getEndLoc());
631639
}
640+
default:
641+
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
632642
}
633-
llvm_unreachable("Unhandled Interpreter::InterfaceKind");
634643
}
635644

636645
Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
@@ -815,3 +824,15 @@ __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
815824
VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
816825
VRef.setLongDouble(Val);
817826
}
827+
828+
// A trampoline to work around the fact that operator placement new cannot
829+
// really be forward declared due to libc++ and libstdc++ declaration mismatch.
830+
// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
831+
// definition in the interpreter runtime. We should move it in a runtime header
832+
// which gets included by the interpreter and here.
833+
struct __clang_Interpreter_NewTag {};
834+
REPL_EXTERNAL_VISIBILITY void *
835+
operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
836+
// Just forward to the standard operator placement new.
837+
return operator new(__sz, __p);
838+
}
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)