aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Interpreter/Interpreter.cpp
diff options
context:
space:
mode:
authorJun Zhang <jun@junz.org>2023-05-16 21:21:52 +0800
committerJun Zhang <jun@junz.org>2023-05-16 21:21:52 +0800
commit7158fd381a0bc0222195d6a07ebb42ea57957bda (patch)
tree478d3238a459fe992133a3e0d3983845abca20ad /clang/lib/Interpreter/Interpreter.cpp
parentf2bb57c19455e77fd71be782f9ee9092f31bd2a9 (diff)
downloadllvm-7158fd381a0bc0222195d6a07ebb42ea57957bda.zip
llvm-7158fd381a0bc0222195d6a07ebb42ea57957bda.tar.gz
llvm-7158fd381a0bc0222195d6a07ebb42ea57957bda.tar.bz2
Revert "[clang-repl] Introduce Value to capture expression results"
This reverts commit a423b7f1d7ca8b263af85944f57a69aa08fc942c. See https://lab.llvm.org/buildbot/#/changes/95083
Diffstat (limited to 'clang/lib/Interpreter/Interpreter.cpp')
-rw-r--r--clang/lib/Interpreter/Interpreter.cpp404
1 files changed, 4 insertions, 400 deletions
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 82eaa85..24fb9da 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -16,11 +16,7 @@
#include "IncrementalExecutor.h"
#include "IncrementalParser.h"
-#include "InterpreterUtils.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/TypeVisitor.h"
-#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
@@ -31,15 +27,13 @@
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
-#include "clang/Interpreter/Value.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Sema/Lookup.h"
-#include "llvm/ExecutionEngine/JITSymbol.h"
+
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Errc.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Host.h"
+
using namespace clang;
// FIXME: Figure out how to unify with namespace init_convenience from
@@ -183,7 +177,7 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
llvm::ErrorAsOutParameter EAO(&Err);
auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
- IncrParser = std::make_unique<IncrementalParser>(*this, std::move(CI),
+ IncrParser = std::make_unique<IncrementalParser>(std::move(CI),
*TSCtx->getContext(), Err);
}
@@ -196,29 +190,6 @@ Interpreter::~Interpreter() {
}
}
-// These better to put in a runtime header but we can't. This is because we
-// 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;
- 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);
- 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]);
- }
- 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);
- }
-)";
-
llvm::Expected<std::unique_ptr<Interpreter>>
Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
llvm::Error Err = llvm::Error::success();
@@ -226,14 +197,6 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
if (Err)
return std::move(Err);
- if (llvm::Error Err = Interp->ParseAndExecute(Runtimes))
- return std::move(Err);
-
- Interp->ValuePrintingInfo.resize(3);
- // 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'.
- Interp->InitPTUSize = Interp->IncrParser->getPTUs().size();
return std::move(Interp);
}
@@ -250,26 +213,8 @@ llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
return IncrExecutor->GetExecutionEngine();
}
-ASTContext &Interpreter::getASTContext() {
- return getCompilerInstance()->getASTContext();
-}
-
-const ASTContext &Interpreter::getASTContext() const {
- return getCompilerInstance()->getASTContext();
-}
-
-size_t Interpreter::getEffectivePTUSize() const {
- std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
- assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
- return PTUs.size() - InitPTUSize;
-}
-
llvm::Expected<PartialTranslationUnit &>
Interpreter::Parse(llvm::StringRef Code) {
- // Tell the interpreter sliently ignore unused expressions since value
- // printing could cause it.
- getCompilerInstance()->getDiagnostics().setSeverity(
- clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
return IncrParser->Parse(Code);
}
@@ -301,25 +246,6 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
return llvm::Error::success();
}
-llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
-
- auto PTU = Parse(Code);
- if (!PTU)
- return PTU.takeError();
- if (PTU->TheModule)
- if (llvm::Error Err = Execute(*PTU))
- return Err;
-
- if (LastValue.isValid()) {
- if (!V) {
- LastValue.dump();
- LastValue.clear();
- } else
- *V = std::move(LastValue);
- }
- return llvm::Error::success();
-}
-
llvm::Expected<llvm::orc::ExecutorAddr>
Interpreter::getSymbolAddress(GlobalDecl GD) const {
if (!IncrExecutor)
@@ -353,7 +279,7 @@ Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
llvm::Error Interpreter::Undo(unsigned N) {
std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
- if (N > getEffectivePTUSize())
+ if (N > PTUs.size())
return llvm::make_error<llvm::StringError>("Operation failed. "
"Too many undos",
std::error_code());
@@ -384,325 +310,3 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
return llvm::Error::success();
}
-
-llvm::Expected<llvm::orc::ExecutorAddr>
-Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
- assert(CXXRD && "Cannot compile a destructor for a nullptr");
- if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())
- return Dtor->getSecond();
-
- if (CXXRD->hasIrrelevantDestructor())
- return llvm::orc::ExecutorAddr{};
-
- CXXDestructorDecl *DtorRD =
- getCompilerInstance()->getSema().LookupDestructor(CXXRD);
-
- llvm::StringRef Name =
- IncrParser->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
- auto AddrOrErr = getSymbolAddress(Name);
- if (!AddrOrErr)
- return AddrOrErr.takeError();
-
- Dtors[CXXRD] = *AddrOrErr;
- return AddrOrErr;
-}
-
-static constexpr llvm::StringRef MagicRuntimeInterface[] = {
- "__clang_Interpreter_SetValueNoAlloc",
- "__clang_Interpreter_SetValueWithAlloc",
- "__clang_Interpreter_SetValueCopyArr"};
-
-bool Interpreter::FindRuntimeInterface() {
- if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
- return true;
-
- Sema &S = getCompilerInstance()->getSema();
- ASTContext &Ctx = S.getASTContext();
-
- auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
- LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
- Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
- S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
- if (R.empty())
- return false;
-
- CXXScopeSpec CSS;
- Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
- return true;
- };
-
- if (!LookupInterface(ValuePrintingInfo[NoAlloc],
- MagicRuntimeInterface[NoAlloc]))
- return false;
- if (!LookupInterface(ValuePrintingInfo[WithAlloc],
- MagicRuntimeInterface[WithAlloc]))
- return false;
- if (!LookupInterface(ValuePrintingInfo[CopyArray],
- MagicRuntimeInterface[CopyArray]))
- return false;
- return true;
-}
-
-namespace {
-
-class RuntimeInterfaceBuilder
- : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> {
- clang::Interpreter &Interp;
- ASTContext &Ctx;
- Sema &S;
- Expr *E;
- llvm::SmallVector<Expr *, 3> Args;
-
-public:
- RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef,
- Expr *VE, ArrayRef<Expr *> FixedArgs)
- : Interp(In), Ctx(C), S(SemaRef), E(VE) {
- // The Interpreter* parameter and the out parameter `OutVal`.
- for (Expr *E : FixedArgs)
- Args.push_back(E);
-
- // Get rid of ExprWithCleanups.
- if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
- E = EWC->getSubExpr();
- }
-
- ExprResult getCall() {
- QualType Ty = E->getType();
- QualType DesugaredTy = Ty.getDesugaredType(Ctx);
-
- // For lvalue struct, we treat it as a reference.
- if (DesugaredTy->isRecordType() && E->isLValue()) {
- DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
- Ty = Ctx.getLValueReferenceType(Ty);
- }
-
- Expr *TypeArg =
- CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
- // The QualType parameter `OpaqueType`, represented as `void*`.
- Args.push_back(TypeArg);
-
- // We push the last parameter based on the type of the Expr. Note we need
- // special care for rvalue struct.
- Interpreter::InterfaceKind Kind = Visit(&*DesugaredTy);
- switch (Kind) {
- case Interpreter::InterfaceKind::WithAlloc:
- case Interpreter::InterfaceKind::CopyArray: {
- // __clang_Interpreter_SetValueWithAlloc.
- ExprResult AllocCall = S.ActOnCallExpr(
- /*Scope=*/nullptr,
- Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
- E->getBeginLoc(), Args, E->getEndLoc());
- assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
-
- TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
-
- // Force CodeGen to emit destructor.
- if (auto *RD = Ty->getAsCXXRecordDecl()) {
- auto *Dtor = S.LookupDestructor(RD);
- Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
- Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
- DeclGroupRef(Dtor));
- }
-
- // __clang_Interpreter_SetValueCopyArr.
- if (Kind == Interpreter::InterfaceKind::CopyArray) {
- const auto *ConstantArrTy =
- cast<ConstantArrayType>(DesugaredTy.getTypePtr());
- size_t ArrSize = Ctx.getConstantArrayElementCount(ConstantArrTy);
- Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
- Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
- return S.ActOnCallExpr(
- /*Scope *=*/nullptr,
- Interp
- .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
- SourceLocation(), Args, SourceLocation());
- }
- Expr *Args[] = {AllocCall.get()};
- ExprResult CXXNewCall = S.BuildCXXNew(
- E->getSourceRange(),
- /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
- /*PlacementRParen=*/SourceLocation(),
- /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
- E->getSourceRange(), E);
-
- assert(!CXXNewCall.isInvalid() &&
- "Can't create runtime placement new call!");
-
- return S.ActOnFinishFullExpr(CXXNewCall.get(),
- /*DiscardedValue=*/false);
- }
- // __clang_Interpreter_SetValueNoAlloc.
- case Interpreter::InterfaceKind::NoAlloc: {
- return S.ActOnCallExpr(
- /*Scope=*/nullptr,
- Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
- E->getBeginLoc(), Args, E->getEndLoc());
- }
- }
- }
-
- Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
- return Interpreter::InterfaceKind::WithAlloc;
- }
-
- Interpreter::InterfaceKind
- VisitMemberPointerType(const MemberPointerType *Ty) {
- return Interpreter::InterfaceKind::WithAlloc;
- }
-
- Interpreter::InterfaceKind
- VisitConstantArrayType(const ConstantArrayType *Ty) {
- return Interpreter::InterfaceKind::CopyArray;
- }
-
- Interpreter::InterfaceKind
- VisitFunctionProtoType(const FunctionProtoType *Ty) {
- HandlePtrType(Ty);
- return Interpreter::InterfaceKind::NoAlloc;
- }
-
- Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) {
- HandlePtrType(Ty);
- return Interpreter::InterfaceKind::NoAlloc;
- }
-
- Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
- ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
- assert(!AddrOfE.isInvalid() && "Can not create unary expression");
- Args.push_back(AddrOfE.get());
- return Interpreter::InterfaceKind::NoAlloc;
- }
-
- Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
- if (Ty->isNullPtrType())
- Args.push_back(E);
- else if (Ty->isFloatingType())
- Args.push_back(E);
- else if (Ty->isIntegralOrEnumerationType())
- HandleIntegralOrEnumType(Ty);
- else if (Ty->isVoidType()) {
- // Do we need to still run `E`?
- }
-
- return Interpreter::InterfaceKind::NoAlloc;
- }
-
- Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) {
- HandleIntegralOrEnumType(Ty);
- return Interpreter::InterfaceKind::NoAlloc;
- }
-
-private:
- // Force cast these types to uint64 to reduce the number of overloads of
- // `__clang_Interpreter_SetValueNoAlloc`.
- void HandleIntegralOrEnumType(const Type *Ty) {
- TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.UnsignedLongLongTy);
- ExprResult CastedExpr =
- S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
- assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
- Args.push_back(CastedExpr.get());
- }
-
- void HandlePtrType(const Type *Ty) {
- TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
- ExprResult CastedExpr =
- S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
- assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
- Args.push_back(CastedExpr.get());
- }
-};
-} // namespace
-
-// This synthesizes a call expression to a speciall
-// function that is responsible for generating the Value.
-// In general, we transform:
-// clang-repl> x
-// To:
-// // 1. If x is a built-in type like int, float.
-// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
-// // 2. If x is a struct, and a lvalue.
-// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
-// &x);
-// // 3. If x is a struct, but a rvalue.
-// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
-// xQualType)) (x);
-
-Expr *Interpreter::SynthesizeExpr(Expr *E) {
- Sema &S = getCompilerInstance()->getSema();
- ASTContext &Ctx = S.getASTContext();
-
- if (!FindRuntimeInterface())
- llvm_unreachable("We can't find the runtime iterface for pretty print!");
-
- // Create parameter `ThisInterp`.
- auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
-
- // Create parameter `OutVal`.
- auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
-
- // Build `__clang_Interpreter_SetValue*` call.
- RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue});
-
- ExprResult Result = Builder.getCall();
- // It could fail, like printing an array type in C. (not supported)
- if (Result.isInvalid())
- return E;
- return Result.get();
-}
-
-// Temporary rvalue struct that need special care.
-REPL_EXTERNAL_VISIBILITY void *
-__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
- void *OpaqueType) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- return VRef.getPtr();
-}
-
-// Pointers, lvalue struct that can take as a reference.
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- void *Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setPtr(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal,
- void *OpaqueType) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- unsigned long long Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setULongLong(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- float Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setFloat(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- double Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setDouble(Val);
-}
-
-REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
- long double Val) {
- Value &VRef = *(Value *)OutVal;
- VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
- VRef.setLongDouble(Val);
-}