diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index e680218452d1c..b3d64458d777c 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -14,15 +14,14 @@ #ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H #define LLVM_CLANG_INTERPRETER_INTERPRETER_H -#include "clang/AST/Decl.h" -#include "clang/AST/GlobalDecl.h" #include "clang/Interpreter/PartialTranslationUnit.h" -#include "clang/Interpreter/Value.h" -#include "llvm/ADT/DenseMap.h" +#include "clang/AST/GlobalDecl.h" + #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" #include "llvm/Support/Error.h" + #include #include @@ -55,26 +54,24 @@ class Interpreter { Interpreter(std::unique_ptr CI, llvm::Error &Err); llvm::Error CreateExecutor(); - unsigned InitPTUSize = 0; - - // This member holds the last result of the value printing. It's a class - // member because we might want to access it after more inputs. If no value - // printing happens, it's in an invalid state. - Value LastValue; public: ~Interpreter(); static llvm::Expected> create(std::unique_ptr CI); - const ASTContext &getASTContext() const; - ASTContext &getASTContext(); const CompilerInstance *getCompilerInstance() const; llvm::Expected getExecutionEngine(); llvm::Expected Parse(llvm::StringRef Code); llvm::Error Execute(PartialTranslationUnit &T); - llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr); - llvm::Expected CompileDtorCall(CXXRecordDecl *CXXRD); + llvm::Error ParseAndExecute(llvm::StringRef Code) { + auto PTU = Parse(Code); + if (!PTU) + return PTU.takeError(); + if (PTU->TheModule) + return Execute(*PTU); + return llvm::Error::success(); + } /// Undo N previous incremental inputs. llvm::Error Undo(unsigned N = 1); @@ -95,23 +92,6 @@ class Interpreter { /// file. llvm::Expected getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; - - enum InterfaceKind { NoAlloc, WithAlloc, CopyArray }; - - const llvm::SmallVectorImpl &getValuePrintingInfo() const { - return ValuePrintingInfo; - } - - Expr *SynthesizeExpr(Expr *E); - -private: - size_t getEffectivePTUSize() const; - - bool FindRuntimeInterface(); - - llvm::DenseMap Dtors; - - llvm::SmallVector ValuePrintingInfo; }; } // namespace clang diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h deleted file mode 100644 index 90a0097e5cc37..0000000000000 --- a/clang/include/clang/Interpreter/Value.h +++ /dev/null @@ -1,200 +0,0 @@ -//===--- Value.h - Definition of interpreter value --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Value is a lightweight struct that is used for carrying execution results in -// clang-repl. It's a special runtime that acts like a messager between compiled -// code and interpreted code. This makes it possible to exchange interesting -// information between the compiled & interpreted world. -// -// A typical usage is like the below: -// -// Value V; -// Interp.ParseAndExecute("int x = 42;"); -// Interp.ParseAndExecute("x", &V); -// V.getType(); // <-- Yields a clang::QualType. -// V.getInt(); // <-- Yields 42. -// -// The current design is still highly experimental and nobody should rely on the -// API being stable because we're hopefully going to make significant changes to -// it in the relatively near future. For example, Value also intends to be used -// as an exchange token for JIT support enabling remote execution on the embed -// devices where the JIT infrastructure cannot fit. To support that we will need -// to split the memory storage in a different place and perhaps add a resource -// header is similar to intrinsics headers which have stricter performance -// constraints. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INTERPRETER_VALUE_H -#define LLVM_CLANG_INTERPRETER_VALUE_H - -#include -// NOTE: Since the REPL itself could also include this runtime, extreme caution -// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW -// HEADERS, like , and etc. (That pulls a large number of -// tokens and will impact the runtime performance of the REPL) - -namespace llvm { -class raw_ostream; - -} // namespace llvm - -namespace clang { - -class ASTContext; -class Interpreter; -class QualType; - -#if __has_attribute(visibility) && \ - (!(defined(_WIN32) || defined(__CYGWIN__)) || \ - (defined(__MINGW32__) && defined(__clang__))) -#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS) -#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default"))) -#else -#define REPL_EXTERNAL_VISIBILITY -#endif -#else -#if defined(_WIN32) -#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport) -#endif -#endif - -#define REPL_BUILTIN_TYPES \ - X(bool, Bool) \ - X(char, Char_S) \ - X(signed char, SChar) \ - X(unsigned char, UChar) \ - X(short, Short) \ - X(unsigned short, UShort) \ - X(int, Int) \ - X(unsigned int, UInt) \ - X(long, Long) \ - X(unsigned long, ULong) \ - X(long long, LongLong) \ - X(unsigned long long, ULongLong) \ - X(float, Float) \ - X(double, Double) \ - X(long double, LongDouble) - -class REPL_EXTERNAL_VISIBILITY Value { - union Storage { -#define X(type, name) type m_##name; - REPL_BUILTIN_TYPES -#undef X - void *m_Ptr; - }; - -public: - enum Kind { -#define X(type, name) K_##name, - REPL_BUILTIN_TYPES -#undef X - - K_Void, - K_PtrOrObj, - K_Unspecified - }; - - Value() = default; - Value(Interpreter *In, void *Ty); - Value(const Value &RHS); - Value(Value &&RHS) noexcept; - Value &operator=(const Value &RHS); - Value &operator=(Value &&RHS) noexcept; - ~Value(); - - void printType(llvm::raw_ostream &Out) const; - void printData(llvm::raw_ostream &Out) const; - void print(llvm::raw_ostream &Out) const; - void dump() const; - void clear(); - - ASTContext &getASTContext(); - const ASTContext &getASTContext() const; - Interpreter &getInterpreter(); - const Interpreter &getInterpreter() const; - QualType getType() const; - - bool isValid() const { return ValueKind != K_Unspecified; } - bool isVoid() const { return ValueKind == K_Void; } - bool hasValue() const { return isValid() && !isVoid(); } - bool isManuallyAlloc() const { return IsManuallyAlloc; } - Kind getKind() const { return ValueKind; } - void setKind(Kind K) { ValueKind = K; } - void setOpaqueType(void *Ty) { OpaqueType = Ty; } - - void *getPtr() const; - void setPtr(void *Ptr) { Data.m_Ptr = Ptr; } - -#define X(type, name) \ - void set##name(type Val) { Data.m_##name = Val; } \ - type get##name() const { return Data.m_##name; } - REPL_BUILTIN_TYPES -#undef X - - /// \brief Get the value with cast. - // - /// Get the value cast to T. This is similar to reinterpret_cast(value), - /// casting the value of builtins (except void), enums and pointers. - /// Values referencing an object are treated as pointers to the object. - template T convertTo() const { - return convertFwd::cast(*this); - } - -protected: - bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; } - - /// \brief Get to the value with type checking casting the underlying - /// stored value to T. - template T as() const { - switch (ValueKind) { - default: - return T(); -#define X(type, name) \ - case Value::K_##name: \ - return (T)Data.m_##name; - REPL_BUILTIN_TYPES -#undef X - } - } - - // Allow convertTo to be partially specialized. - template struct convertFwd { - static T cast(const Value &V) { - if (V.isPointerOrObjectType()) - return (T)(uintptr_t)V.as(); - if (!V.isValid() || V.isVoid()) { - return T(); - } - return V.as(); - } - }; - - template struct convertFwd { - static T *cast(const Value &V) { - if (V.isPointerOrObjectType()) - return (T *)(uintptr_t)V.as(); - return nullptr; - } - }; - - Interpreter *Interp = nullptr; - void *OpaqueType = nullptr; - Storage Data; - Kind ValueKind = K_Unspecified; - bool IsManuallyAlloc = false; -}; - -template <> inline void *Value::as() const { - if (isPointerOrObjectType()) - return Data.m_Ptr; - return (void *)as(); -} - -} // namespace clang -#endif diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 0df0ba6b8b856..721864c0cc1ea 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -14,8 +14,6 @@ add_clang_library(clangInterpreter IncrementalExecutor.cpp IncrementalParser.cpp Interpreter.cpp - InterpreterUtils.cpp - Value.cpp DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index e431890712258..2b932623a5fea 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "IncrementalParser.h" + #include "clang/AST/DeclContextInternals.h" #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/CodeGenAction.h" @@ -18,9 +19,9 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/FrontendTool/Utils.h" -#include "clang/Interpreter/Interpreter.h" #include "clang/Parse/Parser.h" #include "clang/Sema/Sema.h" + #include "llvm/Option/ArgList.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Error.h" @@ -30,79 +31,6 @@ namespace clang { -class IncrementalASTConsumer final : public ASTConsumer { - Interpreter &Interp; - std::unique_ptr Consumer; - -public: - IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr C) - : Interp(InterpRef), Consumer(std::move(C)) {} - - bool HandleTopLevelDecl(DeclGroupRef DGR) override final { - if (DGR.isNull()) - return true; - if (!Consumer) - return true; - - for (Decl *D : DGR) - if (auto *TSD = llvm::dyn_cast(D); - TSD && TSD->isSemiMissing()) - TSD->setStmt(Interp.SynthesizeExpr(cast(TSD->getStmt()))); - - return Consumer->HandleTopLevelDecl(DGR); - } - void HandleTranslationUnit(ASTContext &Ctx) override final { - Consumer->HandleTranslationUnit(Ctx); - } - void HandleInlineFunctionDefinition(FunctionDecl *D) override final { - Consumer->HandleInlineFunctionDefinition(D); - } - void HandleInterestingDecl(DeclGroupRef D) override final { - Consumer->HandleInterestingDecl(D); - } - void HandleTagDeclDefinition(TagDecl *D) override final { - Consumer->HandleTagDeclDefinition(D); - } - void HandleTagDeclRequiredDefinition(const TagDecl *D) override final { - Consumer->HandleTagDeclRequiredDefinition(D); - } - void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final { - Consumer->HandleCXXImplicitFunctionInstantiation(D); - } - void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final { - Consumer->HandleTopLevelDeclInObjCContainer(D); - } - void HandleImplicitImportDecl(ImportDecl *D) override final { - Consumer->HandleImplicitImportDecl(D); - } - void CompleteTentativeDefinition(VarDecl *D) override final { - Consumer->CompleteTentativeDefinition(D); - } - void CompleteExternalDeclaration(VarDecl *D) override final { - Consumer->CompleteExternalDeclaration(D); - } - void AssignInheritanceModel(CXXRecordDecl *RD) override final { - Consumer->AssignInheritanceModel(RD); - } - void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final { - Consumer->HandleCXXStaticMemberVarInstantiation(D); - } - void HandleVTable(CXXRecordDecl *RD) override final { - Consumer->HandleVTable(RD); - } - ASTMutationListener *GetASTMutationListener() override final { - return Consumer->GetASTMutationListener(); - } - ASTDeserializationListener *GetASTDeserializationListener() override final { - return Consumer->GetASTDeserializationListener(); - } - void PrintStats() override final { Consumer->PrintStats(); } - bool shouldSkipFunctionBody(Decl *D) override final { - return Consumer->shouldSkipFunctionBody(D); - } - static bool classof(const clang::ASTConsumer *) { return true; } -}; - /// A custom action enabling the incremental processing functionality. /// /// The usual \p FrontendAction expects one call to ExecuteAction and once it @@ -194,8 +122,7 @@ class IncrementalAction : public WrapperFrontendAction { } }; -IncrementalParser::IncrementalParser(Interpreter &Interp, - std::unique_ptr Instance, +IncrementalParser::IncrementalParser(std::unique_ptr Instance, llvm::LLVMContext &LLVMCtx, llvm::Error &Err) : CI(std::move(Instance)) { @@ -204,9 +131,6 @@ IncrementalParser::IncrementalParser(Interpreter &Interp, if (Err) return; CI->ExecuteAction(*Act); - std::unique_ptr IncrConsumer = - std::make_unique(Interp, CI->takeASTConsumer()); - CI->setASTConsumer(std::move(IncrConsumer)); Consumer = &CI->getASTConsumer(); P.reset( new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); @@ -343,20 +267,15 @@ IncrementalParser::Parse(llvm::StringRef input) { "Lexer must be EOF when starting incremental parse!"); } - if (std::unique_ptr M = GenModule()) - PTU->TheModule = std::move(M); - - return PTU; -} - -std::unique_ptr IncrementalParser::GenModule() { - static unsigned ID = 0; if (CodeGenerator *CG = getCodeGen(Act.get())) { std::unique_ptr M(CG->ReleaseModule()); - CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext()); - return M; + CG->StartModule("incr_module_" + std::to_string(PTUs.size()), + M->getContext()); + + PTU->TheModule = std::move(M); } - return nullptr; + + return PTU; } void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h index 99e37588df9db..8e45d6b5931bc 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -16,6 +16,7 @@ #include "clang/Interpreter/PartialTranslationUnit.h" #include "clang/AST/GlobalDecl.h" + #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -30,8 +31,8 @@ namespace clang { class ASTConsumer; class CompilerInstance; class IncrementalAction; -class Interpreter; class Parser; + /// Provides support for incremental compilation. Keeps track of the state /// changes between the subsequent incremental input. /// @@ -56,8 +57,7 @@ class IncrementalParser { std::list PTUs; public: - IncrementalParser(Interpreter &Interp, - std::unique_ptr Instance, + IncrementalParser(std::unique_ptr Instance, llvm::LLVMContext &LLVMCtx, llvm::Error &Err); ~IncrementalParser(); @@ -76,8 +76,6 @@ class IncrementalParser { std::list &getPTUs() { return PTUs; } - std::unique_ptr GenModule(); - private: llvm::Expected ParseOrWrapTopLevelDecl(); }; diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 82eaa8539c140..24fb9da69a8bc 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 CI, llvm::ErrorAsOutParameter EAO(&Err); auto LLVMCtx = std::make_unique(); TSCtx = std::make_unique(std::move(LLVMCtx)); - IncrParser = std::make_unique(*this, std::move(CI), + IncrParser = std::make_unique(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 - 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 - void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) { - __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size); - } -)"; - llvm::Expected> Interpreter::create(std::unique_ptr CI) { llvm::Error Err = llvm::Error::success(); @@ -226,14 +197,6 @@ Interpreter::create(std::unique_ptr CI) { std::unique_ptr(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 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 &PTUs = IncrParser->getPTUs(); - assert(PTUs.size() >= InitPTUSize && "empty PTU list?"); - return PTUs.size() - InitPTUSize; -} - llvm::Expected 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 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 &PTUs = IncrParser->getPTUs(); - if (N > getEffectivePTUSize()) + if (N > PTUs.size()) return llvm::make_error("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 -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 { - clang::Interpreter &Interp; - ASTContext &Ctx; - Sema &S; - Expr *E; - llvm::SmallVector Args; - -public: - RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef, - Expr *VE, ArrayRef 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(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(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(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(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(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(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(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(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(This), OpaqueType); - VRef.setLongDouble(Val); -} diff --git a/clang/lib/Interpreter/InterpreterUtils.cpp b/clang/lib/Interpreter/InterpreterUtils.cpp deleted file mode 100644 index c19cf6aa3156c..0000000000000 --- a/clang/lib/Interpreter/InterpreterUtils.cpp +++ /dev/null @@ -1,111 +0,0 @@ -//===--- InterpreterUtils.cpp - Incremental Utils --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements some common utils used in the incremental library. -// -//===----------------------------------------------------------------------===// - -#include "InterpreterUtils.h" - -namespace clang { - -IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val) { - return IntegerLiteral::Create(C, llvm::APSInt::getUnsigned(Val), - C.UnsignedLongLongTy, SourceLocation()); -} - -Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E) { - ASTContext &Ctx = S.getASTContext(); - if (!Ty->isPointerType()) - Ty = Ctx.getPointerType(Ty); - - TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation()); - Expr *Result = - S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E).get(); - assert(Result && "Cannot create CStyleCastPtrExpr"); - return Result; -} - -Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, uintptr_t Ptr) { - ASTContext &Ctx = S.getASTContext(); - return CStyleCastPtrExpr(S, Ty, IntegerLiteralExpr(Ctx, (uint64_t)Ptr)); -} - -Sema::DeclGroupPtrTy CreateDGPtrFrom(Sema &S, Decl *D) { - SmallVector DeclsInGroup; - DeclsInGroup.push_back(D); - Sema::DeclGroupPtrTy DeclGroupPtr = S.BuildDeclaratorGroup(DeclsInGroup); - return DeclGroupPtr; -} - -NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name, - const DeclContext *Within) { - DeclarationName DName = &S.Context.Idents.get(Name); - LookupResult R(S, DName, SourceLocation(), - Sema::LookupNestedNameSpecifierName); - R.suppressDiagnostics(); - if (!Within) - S.LookupName(R, S.TUScope); - else { - if (const auto *TD = dyn_cast(Within); - TD && !TD->getDefinition()) - // No definition, no lookup result. - return nullptr; - - S.LookupQualifiedName(R, const_cast(Within)); - } - - if (R.empty()) - return nullptr; - - R.resolveKind(); - - return dyn_cast(R.getFoundDecl()); -} - -NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name, - const DeclContext *Within) { - DeclarationName DName = &S.Context.Idents.get(Name); - LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, - Sema::ForVisibleRedeclaration); - - R.suppressDiagnostics(); - - if (!Within) - S.LookupName(R, S.TUScope); - else { - const DeclContext *PrimaryWithin = nullptr; - if (const auto *TD = dyn_cast(Within)) - PrimaryWithin = llvm::dyn_cast_or_null(TD->getDefinition()); - else - PrimaryWithin = Within->getPrimaryContext(); - - // No definition, no lookup result. - if (!PrimaryWithin) - return nullptr; - - S.LookupQualifiedName(R, const_cast(PrimaryWithin)); - } - - if (R.empty()) - return nullptr; - R.resolveKind(); - - if (R.isSingleResult()) - return llvm::dyn_cast(R.getFoundDecl()); - - return nullptr; -} - -std::string GetFullTypeName(ASTContext &Ctx, QualType QT) { - PrintingPolicy Policy(Ctx.getPrintingPolicy()); - Policy.SuppressScope = false; - Policy.AnonymousTagLocations = false; - return QT.getAsString(Policy); -} -} // namespace clang diff --git a/clang/lib/Interpreter/InterpreterUtils.h b/clang/lib/Interpreter/InterpreterUtils.h deleted file mode 100644 index 8df158c17d491..0000000000000 --- a/clang/lib/Interpreter/InterpreterUtils.h +++ /dev/null @@ -1,54 +0,0 @@ -//===--- InterpreterUtils.h - Incremental Utils --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements some common utils used in the incremental library. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INTERPRETER_UTILS_H -#define LLVM_CLANG_INTERPRETER_UTILS_H - -#include "clang/AST/ASTContext.h" -#include "clang/AST/Mangle.h" -#include "clang/AST/TypeVisitor.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Job.h" -#include "clang/Driver/Options.h" -#include "clang/Driver/Tool.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Lex/PreprocessorOptions.h" - -#include "clang/Sema/Lookup.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Errc.h" -#include "llvm/TargetParser/Host.h" - -namespace clang { -IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val); - -Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E); - -Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, uintptr_t Ptr); - -Sema::DeclGroupPtrTy CreateDGPtrFrom(Sema &S, Decl *D); - -NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name, - const DeclContext *Within = nullptr); - -NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name, - const DeclContext *Within); - -std::string GetFullTypeName(ASTContext &Ctx, QualType QT); -} // namespace clang - -#endif diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp deleted file mode 100644 index fe37eebac5257..0000000000000 --- a/clang/lib/Interpreter/Value.cpp +++ /dev/null @@ -1,266 +0,0 @@ -//===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the class that used to represent a value in incremental -// C++. -// -//===----------------------------------------------------------------------===// - -#include "clang/Interpreter/Value.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" -#include "clang/Interpreter/Interpreter.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_os_ostream.h" -#include -#include -#include - -using namespace clang; - -namespace { - -// This is internal buffer maintained by Value, used to hold temporaries. -class ValueStorage { -public: - using DtorFunc = void (*)(void *); - - static unsigned char *CreatePayload(void *DtorF, size_t AllocSize, - size_t ElementsSize) { - if (AllocSize < sizeof(Canary)) - AllocSize = sizeof(Canary); - unsigned char *Buf = - new unsigned char[ValueStorage::getPayloadOffset() + AllocSize]; - ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize); - std::memcpy(VS->getPayload(), Canary, sizeof(Canary)); - return VS->getPayload(); - } - - unsigned char *getPayload() { return Storage; } - const unsigned char *getPayload() const { return Storage; } - - static unsigned getPayloadOffset() { - static ValueStorage Dummy(nullptr, 0, 0); - return Dummy.getPayload() - reinterpret_cast(&Dummy); - } - - static ValueStorage *getFromPayload(void *Payload) { - ValueStorage *R = reinterpret_cast( - (unsigned char *)Payload - getPayloadOffset()); - return R; - } - - void Retain() { ++RefCnt; } - - void Release() { - assert(RefCnt > 0 && "Can't release if reference count is already zero"); - if (--RefCnt == 0) { - // We hace a non-trivial dtor. - if (Dtor && IsAlive()) { - assert(Elements && "We at least should have 1 element in Value"); - size_t Stride = AllocSize / Elements; - for (size_t Idx = 0; Idx < Elements; ++Idx) - (*Dtor)(getPayload() + Idx * Stride); - } - delete[] reinterpret_cast(this); - } - } - - // Check whether the storage is valid by validating the canary bits. - // If someone accidentally write some invalid bits in the storage, the canary - // will be changed first, and `IsAlive` will return false then. - bool IsAlive() const { - return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0; - } - -private: - ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum) - : RefCnt(1), Dtor(reinterpret_cast(DtorF)), - AllocSize(AllocSize), Elements(ElementsNum) {} - - mutable unsigned RefCnt; - DtorFunc Dtor = nullptr; - size_t AllocSize = 0; - size_t Elements = 0; - unsigned char Storage[1]; - - // These are some canary bits that are used for protecting the storage been - // damaged. - static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f, - 0x2d, 0x23, 0x95, 0x91}; -}; -} // namespace - -static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { - if (Ctx.hasSameType(QT, Ctx.VoidTy)) - return Value::K_Void; - - if (const auto *ET = QT->getAs()) - QT = ET->getDecl()->getIntegerType(); - - const auto *BT = QT->getAs(); - if (!BT || BT->isNullPtrType()) - return Value::K_PtrOrObj; - - switch (QT->getAs()->getKind()) { - default: - assert(false && "Type not supported"); - return Value::K_Unspecified; -#define X(type, name) \ - case BuiltinType::name: \ - return Value::K_##name; - REPL_BUILTIN_TYPES -#undef X - } -} - -Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) { - setKind(ConvertQualTypeToKind(getASTContext(), getType())); - if (ValueKind == K_PtrOrObj) { - QualType Canon = getType().getCanonicalType(); - if ((Canon->isPointerType() || Canon->isObjectType() || - Canon->isReferenceType()) && - (Canon->isRecordType() || Canon->isConstantArrayType() || - Canon->isMemberPointerType())) { - IsManuallyAlloc = true; - // Compile dtor function. - Interpreter &Interp = getInterpreter(); - void *DtorF = nullptr; - size_t ElementsSize = 1; - QualType DtorTy = getType(); - - if (const auto *ArrTy = - llvm::dyn_cast(DtorTy.getTypePtr())) { - DtorTy = ArrTy->getElementType(); - llvm::APInt ArrSize(sizeof(size_t) * 8, 1); - do { - ArrSize *= ArrTy->getSize(); - ArrTy = llvm::dyn_cast( - ArrTy->getElementType().getTypePtr()); - } while (ArrTy); - ElementsSize = static_cast(ArrSize.getZExtValue()); - } - if (const auto *RT = DtorTy->getAs()) { - if (CXXRecordDecl *CXXRD = - llvm::dyn_cast(RT->getDecl())) { - if (llvm::Expected Addr = - Interp.CompileDtorCall(CXXRD)) - DtorF = reinterpret_cast(Addr->getValue()); - else - llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs()); - } - } - - size_t AllocSize = - getASTContext().getTypeSizeInChars(getType()).getQuantity(); - unsigned char *Payload = - ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize); - setPtr((void *)Payload); - } - } -} - -Value::Value(const Value &RHS) - : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data), - ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) { - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Retain(); -} - -Value::Value(Value &&RHS) noexcept { - Interp = std::exchange(RHS.Interp, nullptr); - OpaqueType = std::exchange(RHS.OpaqueType, nullptr); - Data = RHS.Data; - ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); - IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); - - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Release(); -} - -Value &Value::operator=(const Value &RHS) { - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Release(); - - Interp = RHS.Interp; - OpaqueType = RHS.OpaqueType; - Data = RHS.Data; - ValueKind = RHS.ValueKind; - IsManuallyAlloc = RHS.IsManuallyAlloc; - - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Retain(); - - return *this; -} - -Value &Value::operator=(Value &&RHS) noexcept { - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Release(); - - Interp = std::exchange(RHS.Interp, nullptr); - OpaqueType = std::exchange(RHS.OpaqueType, nullptr); - ValueKind = std::exchange(RHS.ValueKind, K_Unspecified); - IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false); - - Data = RHS.Data; - - return *this; -} - -void Value::clear() { - if (IsManuallyAlloc) - ValueStorage::getFromPayload(getPtr())->Release(); - ValueKind = K_Unspecified; - OpaqueType = nullptr; - Interp = nullptr; - IsManuallyAlloc = false; -} - -Value::~Value() { clear(); } - -void *Value::getPtr() const { - assert(ValueKind == K_PtrOrObj); - return Data.m_Ptr; -} - -QualType Value::getType() const { - return QualType::getFromOpaquePtr(OpaqueType); -} - -Interpreter &Value::getInterpreter() { - assert(Interp != nullptr && - "Can't get interpreter from a default constructed value"); - return *Interp; -} - -const Interpreter &Value::getInterpreter() const { - assert(Interp != nullptr && - "Can't get interpreter from a default constructed value"); - return *Interp; -} - -ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); } - -const ASTContext &Value::getASTContext() const { - return getInterpreter().getASTContext(); -} - -void Value::dump() const { print(llvm::outs()); } - -void Value::printType(llvm::raw_ostream &Out) const { - Out << "Not implement yet.\n"; -} -void Value::printData(llvm::raw_ostream &Out) const { - Out << "Not implement yet.\n"; -} -void Value::print(llvm::raw_ostream &Out) const { - assert(OpaqueType != nullptr && "Can't print default Value"); - Out << "Not implement yet.\n"; -} diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt index 2ccbe292fd49e..2ea0122a7b795 100644 --- a/clang/tools/clang-repl/CMakeLists.txt +++ b/clang/tools/clang-repl/CMakeLists.txt @@ -12,7 +12,6 @@ add_clang_tool(clang-repl ) clang_target_link_libraries(clang-repl PRIVATE - clangAST clangBasic clangFrontend clangInterpreter diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt index 698494b9897f5..1a099dbbfe59a 100644 --- a/clang/unittests/Interpreter/CMakeLists.txt +++ b/clang/unittests/Interpreter/CMakeLists.txt @@ -22,5 +22,3 @@ target_link_libraries(ClangReplInterpreterTests PUBLIC if(NOT WIN32) add_subdirectory(ExceptionTests) endif() - -export_executable_symbols(ClangReplInterpreterTests) diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index 1662de406e40f..d555911a89451 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -17,7 +17,6 @@ #include "clang/AST/Mangle.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Interpreter/Value.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" @@ -34,11 +33,6 @@ using namespace clang; #define CLANG_INTERPRETER_NO_SUPPORT_EXEC #endif -int Global = 42; -// JIT reports symbol not found on Windows without the visibility attribute. -REPL_EXTERNAL_VISIBILITY int getGlobal() { return Global; } -REPL_EXTERNAL_VISIBILITY void setGlobal(int val) { Global = val; } - namespace { using Args = std::vector; static std::unique_ptr @@ -282,7 +276,8 @@ TEST(IncrementalProcessing, InstantiateTemplate) { std::vector Args = {"-fno-delayed-template-parsing"}; std::unique_ptr Interp = createInterpreter(Args); - llvm::cantFail(Interp->Parse("extern \"C\" int printf(const char*,...);" + llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);" + "extern \"C\" int printf(const char*,...);" "class A {};" "struct B {" " template" @@ -320,95 +315,4 @@ TEST(IncrementalProcessing, InstantiateTemplate) { free(NewA); } -TEST(InterpreterTest, Value) { - std::unique_ptr Interp = createInterpreter(); - - Value V1; - llvm::cantFail(Interp->ParseAndExecute("int x = 42;")); - llvm::cantFail(Interp->ParseAndExecute("x", &V1)); - EXPECT_TRUE(V1.isValid()); - EXPECT_TRUE(V1.hasValue()); - EXPECT_EQ(V1.getInt(), 42); - EXPECT_EQ(V1.convertTo(), 42); - EXPECT_TRUE(V1.getType()->isIntegerType()); - EXPECT_EQ(V1.getKind(), Value::K_Int); - EXPECT_FALSE(V1.isManuallyAlloc()); - - Value V2; - llvm::cantFail(Interp->ParseAndExecute("double y = 3.14;")); - llvm::cantFail(Interp->ParseAndExecute("y", &V2)); - EXPECT_TRUE(V2.isValid()); - EXPECT_TRUE(V2.hasValue()); - EXPECT_EQ(V2.getDouble(), 3.14); - EXPECT_EQ(V2.convertTo(), 3.14); - EXPECT_TRUE(V2.getType()->isFloatingType()); - EXPECT_EQ(V2.getKind(), Value::K_Double); - EXPECT_FALSE(V2.isManuallyAlloc()); - - Value V3; - llvm::cantFail(Interp->ParseAndExecute( - "struct S { int* p; S() { p = new int(42); } ~S() { delete p; }};")); - llvm::cantFail(Interp->ParseAndExecute("S{}", &V3)); - EXPECT_TRUE(V3.isValid()); - EXPECT_TRUE(V3.hasValue()); - EXPECT_TRUE(V3.getType()->isRecordType()); - EXPECT_EQ(V3.getKind(), Value::K_PtrOrObj); - EXPECT_TRUE(V3.isManuallyAlloc()); - - Value V4; - llvm::cantFail(Interp->ParseAndExecute("int getGlobal();")); - llvm::cantFail(Interp->ParseAndExecute("void setGlobal(int);")); - llvm::cantFail(Interp->ParseAndExecute("getGlobal()", &V4)); - EXPECT_EQ(V4.getInt(), 42); - EXPECT_TRUE(V4.getType()->isIntegerType()); - - Value V5; - // Change the global from the compiled code. - setGlobal(43); - llvm::cantFail(Interp->ParseAndExecute("getGlobal()", &V5)); - EXPECT_EQ(V5.getInt(), 43); - EXPECT_TRUE(V5.getType()->isIntegerType()); - - // Change the global from the interpreted code. - llvm::cantFail(Interp->ParseAndExecute("setGlobal(44);")); - EXPECT_EQ(getGlobal(), 44); - - Value V6; - llvm::cantFail(Interp->ParseAndExecute("void foo() {}")); - llvm::cantFail(Interp->ParseAndExecute("foo()", &V6)); - EXPECT_TRUE(V6.isValid()); - EXPECT_FALSE(V6.hasValue()); - EXPECT_TRUE(V6.getType()->isVoidType()); - EXPECT_EQ(V6.getKind(), Value::K_Void); - EXPECT_FALSE(V2.isManuallyAlloc()); - - Value V7; - llvm::cantFail(Interp->ParseAndExecute("foo", &V7)); - EXPECT_TRUE(V7.isValid()); - EXPECT_TRUE(V7.hasValue()); - EXPECT_TRUE(V7.getType()->isFunctionProtoType()); - EXPECT_EQ(V7.getKind(), Value::K_PtrOrObj); - EXPECT_FALSE(V7.isManuallyAlloc()); - - Value V8; - llvm::cantFail(Interp->ParseAndExecute("struct SS{ void f() {} };")); - llvm::cantFail(Interp->ParseAndExecute("&SS::f", &V8)); - EXPECT_TRUE(V8.isValid()); - EXPECT_TRUE(V8.hasValue()); - EXPECT_TRUE(V8.getType()->isMemberFunctionPointerType()); - EXPECT_EQ(V8.getKind(), Value::K_PtrOrObj); - EXPECT_TRUE(V8.isManuallyAlloc()); - - Value V9; - llvm::cantFail(Interp->ParseAndExecute("struct A { virtual int f(); };")); - llvm::cantFail( - Interp->ParseAndExecute("struct B : A { int f() { return 42; }};")); - llvm::cantFail(Interp->ParseAndExecute("int (B::*ptr)() = &B::f;")); - llvm::cantFail(Interp->ParseAndExecute("ptr", &V9)); - EXPECT_TRUE(V9.isValid()); - EXPECT_TRUE(V9.hasValue()); - EXPECT_TRUE(V9.getType()->isMemberFunctionPointerType()); - EXPECT_EQ(V9.getKind(), Value::K_PtrOrObj); - EXPECT_TRUE(V9.isManuallyAlloc()); -} } // end anonymous namespace