From 2c1cd207838866cbc85fd80b19f72c59575fe5fb Mon Sep 17 00:00:00 2001 From: Alexander Penev Date: Sun, 27 Aug 2023 21:20:01 +0000 Subject: [PATCH 1/8] Fix Value patch --- .../llvm/{clang16-D141215-Value.patch => clang16-1-Value.patch} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename patches/llvm/{clang16-D141215-Value.patch => clang16-1-Value.patch} (100%) diff --git a/patches/llvm/clang16-D141215-Value.patch b/patches/llvm/clang16-1-Value.patch similarity index 100% rename from patches/llvm/clang16-D141215-Value.patch rename to patches/llvm/clang16-1-Value.patch From 7a35edbe9c5a608aa86f6621fb2e954a06df4d38 Mon Sep 17 00:00:00 2001 From: Alexander Penev Date: Sun, 27 Aug 2023 21:21:33 +0000 Subject: [PATCH 2/8] Fix Value patch 2 --- patches/llvm/clang16-1-Value.patch | 739 +++++++++++++++-------------- 1 file changed, 372 insertions(+), 367 deletions(-) diff --git a/patches/llvm/clang16-1-Value.patch b/patches/llvm/clang16-1-Value.patch index 76762368..9f411410 100644 --- a/patches/llvm/clang16-1-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -1,44 +1,5 @@ -diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h -index 863f6ac57f2a..2e343405cfbe 100644 ---- a/clang/include/clang/AST/Decl.h -+++ b/clang/include/clang/AST/Decl.h -@@ -4308,6 +4308,7 @@ class TopLevelStmtDecl : public Decl { - friend class ASTDeclWriter; - - Stmt *Statement = nullptr; -+ bool IsSemiMissing = false; - - TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S) - : Decl(TopLevelStmt, DC, L), Statement(S) {} -@@ -4321,6 +4322,12 @@ public: - SourceRange getSourceRange() const override LLVM_READONLY; - Stmt *getStmt() { return Statement; } - const Stmt *getStmt() const { return Statement; } -+ void setStmt(Stmt *S) { -+ assert(IsSemiMissing && "Operation supported for printing values only!"); -+ Statement = S; -+ } -+ bool isValuePrinting() const { return IsSemiMissing; } -+ void setValuePrinting(bool Missing = true) { IsSemiMissing = Missing; } - - static bool classof(const Decl *D) { return classofKind(D->getKind()); } - static bool classofKind(Kind K) { return K == TopLevelStmt; } -diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def -index 96feae991ccb..7526298557a8 100644 ---- a/clang/include/clang/Basic/TokenKinds.def -+++ b/clang/include/clang/Basic/TokenKinds.def -@@ -936,6 +936,9 @@ ANNOTATION(module_end) - // into the name of a header unit. - ANNOTATION(header_unit) - -+// Annotation for end of input in clang-repl. -+ANNOTATION(repl_input_end) -+ - #undef PRAGMA_ANNOTATION - #undef ANNOTATION - #undef TESTING_KEYWORD diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h -index fd22af976613..020c2a88c185 100644 +index fd22af976..e68021845 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -14,13 +14,15 @@ @@ -60,13 +21,25 @@ index fd22af976613..020c2a88c185 100644 #include #include -@@ -52,22 +54,24 @@ class Interpreter { +@@ -28,7 +30,7 @@ namespace llvm { + namespace orc { + class LLJIT; + class ThreadSafeContext; +-} ++} // namespace orc + } // namespace llvm + + namespace clang { +@@ -52,39 +54,64 @@ 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: @@ -94,26 +67,30 @@ index fd22af976613..020c2a88c185 100644 /// Undo N previous incremental inputs. llvm::Error Undo(unsigned N = 1); -@@ -75,16 +79,33 @@ public: - /// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses + +- /// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses ++ /// Link a dynamic library ++ llvm::Error LoadDynamicLibrary(const char *name); ++ ++ /// \returns the \c ExecutorAddr of a \c GlobalDecl. This interface uses /// the CodeGenModule's internal mangling cache to avoid recomputing the /// mangled name. - llvm::Expected getSymbolAddress(GlobalDecl GD) const; + llvm::Expected getSymbolAddress(GlobalDecl GD) const; - /// \returns the \c JITTargetAddress of a given name as written in the IR. +- /// \returns the \c JITTargetAddress of a given name as written in the IR. - llvm::Expected ++ /// \returns the \c ExecutorAddr of a given name as written in the IR. + llvm::Expected getSymbolAddress(llvm::StringRef IRName) const; - /// \returns the \c JITTargetAddress of a given name as written in the object +- /// \returns the \c JITTargetAddress of a given name as written in the object ++ /// \returns the \c ExecutorAddr of a given name as written in the object /// file. - llvm::Expected + llvm::Expected getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; + -+ size_t getEffectivePTUSize() const; -+ + enum InterfaceKind { NoAlloc, WithAlloc, CopyArray }; + + const llvm::SmallVectorImpl &getValuePrintingInfo() const { @@ -123,6 +100,8 @@ index fd22af976613..020c2a88c185 100644 + Expr *SynthesizeExpr(Expr *E); + +private: ++ size_t getEffectivePTUSize() const; ++ + bool FindRuntimeInterface(); + + llvm::DenseMap Dtors; @@ -133,11 +112,11 @@ index fd22af976613..020c2a88c185 100644 diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h new file mode 100644 -index 000000000000..f70eb214b3d5 +index 000000000..4df436703 --- /dev/null +++ b/clang/include/clang/Interpreter/Value.h -@@ -0,0 +1,174 @@ -+//===--- Value.h - Incremental Compiation and Execution---*- C++ -*-===// +@@ -0,0 +1,202 @@ ++//===--- 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. @@ -145,16 +124,41 @@ index 000000000000..f70eb214b3d5 +// +//===----------------------------------------------------------------------===// +// -+// This file defines the class that used to represent a value in incremental -+// C++. ++// 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 "llvm/Support/Compiler.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; + @@ -211,7 +215,7 @@ index 000000000000..f70eb214b3d5 + REPL_BUILTIN_TYPES +#undef X + -+ K_Void, ++ K_Void, + K_PtrOrObj, + K_Unspecified + }; @@ -238,6 +242,7 @@ index 000000000000..f70eb214b3d5 + + 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; } @@ -246,44 +251,27 @@ index 000000000000..f70eb214b3d5 + void *getPtr() const; + void setPtr(void *Ptr) { Data.m_Ptr = Ptr; } + -+ bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; } -+ +#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 + -+ // Allow castAs to be partially specialized. -+ template struct CastFwd { -+ static T cast(const Value &V) { -+ if (V.isPointerOrObjectType()) -+ return (T)(uintptr_t)V.getAs(); -+ if (!V.isValid() || V.isVoid()) { -+ return T(); -+ } -+ return V.getAs(); -+ } -+ }; -+ -+ template struct CastFwd { -+ static T *cast(const Value &V) { -+ if (V.isPointerOrObjectType()) -+ return (T *)(uintptr_t)V.getAs(); -+ return nullptr; -+ } -+ }; -+ + /// \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 castAs() const { return CastFwd::cast(*this); } ++ 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 getAs() const { ++ template T as() const { + switch (ValueKind) { + default: + return T(); @@ -295,7 +283,26 @@ index 000000000000..f70eb214b3d5 + } + } + -+private: ++ // 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; @@ -303,83 +310,16 @@ index 000000000000..f70eb214b3d5 + bool IsManuallyAlloc = false; +}; + -+template <> inline void *Value::getAs() const { ++template <> inline void *Value::as() const { + if (isPointerOrObjectType()) + return Data.m_Ptr; -+ return (void *)getAs(); ++ return (void *)as(); +} + +} // namespace clang +#endif -diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h -index 6f9581b9ea1f..6b73f43a1fb7 100644 ---- a/clang/include/clang/Parse/Parser.h -+++ b/clang/include/clang/Parse/Parser.h -@@ -18,6 +18,7 @@ - #include "clang/Basic/OpenMPKinds.h" - #include "clang/Basic/OperatorPrecedence.h" - #include "clang/Basic/Specifiers.h" -+#include "clang/Basic/TokenKinds.h" - #include "clang/Lex/CodeCompletionHandler.h" - #include "clang/Lex/Preprocessor.h" - #include "clang/Sema/DeclSpec.h" -@@ -692,7 +693,8 @@ private: - bool isEofOrEom() { - tok::TokenKind Kind = Tok.getKind(); - return Kind == tok::eof || Kind == tok::annot_module_begin || -- Kind == tok::annot_module_end || Kind == tok::annot_module_include; -+ Kind == tok::annot_module_end || Kind == tok::annot_module_include || -+ Kind == tok::annot_repl_input_end; - } - - /// Checks if the \p Level is valid for use in a fold expression. -diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp -index 12d602fed693..8952920a09ad 100644 ---- a/clang/lib/CodeGen/CodeGenModule.cpp -+++ b/clang/lib/CodeGen/CodeGenModule.cpp -@@ -7186,8 +7186,14 @@ void CodeGenModule::printPostfixForExternalizedDecl(llvm::raw_ostream &OS, - } - - void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) { -- assert(DeferredDeclsToEmit.empty() && -- "Should have emitted all decls deferred to emit."); -+ // FIXME: Re-enable the assertions once we fix regular codegen to not leave -+ // weak references behind. -+ // The code example also leaves entries in WeakRefReferences in regular clang. -+ // #include -+ // auto p = std::make_shared(42); -+ // -+ // assert(DeferredDeclsToEmit.empty() && -+ // "Should have emitted all decls deferred to emit."); - assert(NewBuilder->DeferredDecls.empty() && - "Newly created module should not have deferred decls"); - NewBuilder->DeferredDecls = std::move(DeferredDecls); -diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp -index ffa85e523c03..1b262d9e6f7c 100644 ---- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp -+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp -@@ -663,7 +663,8 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, - // them. - if (Tok.is(tok::eof) || - (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) && -- !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end))) -+ !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) && -+ !Tok.is(tok::annot_repl_input_end))) - return; - - // EmittedDirectiveOnThisLine takes priority over RequireSameLine. -@@ -819,6 +820,9 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, - // -traditional-cpp the lexer keeps /all/ whitespace, including comments. - PP.Lex(Tok); - continue; -+ } else if (Tok.is(tok::annot_repl_input_end)) { -+ PP.Lex(Tok); -+ continue; - } else if (Tok.is(tok::eod)) { - // Don't print end of directive tokens, since they are typically newlines - // that mess up our line tracking. These come from unknown pre-processor diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt -index c49f22fddd8e..565e824bf0c9 100644 +index c49f22fdd..565e824bf 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -12,6 +12,8 @@ add_clang_library(clangInterpreter @@ -392,10 +332,10 @@ index c49f22fddd8e..565e824bf0c9 100644 DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp -index 37d230b61f76..b4b6bc8b40fe 100644 +index 37d230b61..489ea48e0 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp -@@ -86,15 +86,12 @@ llvm::Error IncrementalExecutor::runCtors() const { +@@ -86,7 +86,7 @@ llvm::Error IncrementalExecutor::runCtors() const { return Jit->initialize(Jit->getMainJITDylib()); } @@ -404,20 +344,28 @@ index 37d230b61f76..b4b6bc8b40fe 100644 IncrementalExecutor::getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const { auto Sym = (NameKind == LinkerName) ? Jit->lookupLinkerMangled(Name) - : Jit->lookup(Name); -- -- if (!Sym) -- return Sym.takeError(); +@@ -94,7 +94,7 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name, + + if (!Sym) + return Sym.takeError(); - return Sym->getValue(); -+ return std::move(Sym); ++ return Sym; } } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h -index 54d37c76326b..8bead233d448 100644 +index 54d37c763..dd0a210a0 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h -@@ -51,9 +51,9 @@ public: +@@ -16,6 +16,7 @@ + #include "llvm/ADT/DenseMap.h" + #include "llvm/ADT/StringRef.h" + #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" ++#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" + + #include + +@@ -51,9 +52,10 @@ public: llvm::Error removeModule(PartialTranslationUnit &PTU); llvm::Error runCtors() const; llvm::Error cleanUp(); @@ -425,12 +373,13 @@ index 54d37c76326b..8bead233d448 100644 + llvm::Expected getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; - llvm::orc::LLJIT *getExecutionEngine() const { return Jit.get(); } ++ + llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; } }; } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp -index 373e2844b4e4..259b9875e6be 100644 +index 373e2844b..f892eeb81 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -11,7 +11,6 @@ @@ -472,7 +421,7 @@ index 373e2844b4e4..259b9875e6be 100644 + + for (Decl *D : DGR) + if (auto *TSD = llvm::dyn_cast(D); -+ TSD && TSD->isValuePrinting()) ++ TSD && TSD->isSemiMissing()) + TSD->setStmt(Interp.SynthesizeExpr(cast(TSD->getStmt()))); + + return Consumer->HandleTopLevelDecl(DGR); @@ -552,29 +501,8 @@ index 373e2844b4e4..259b9875e6be 100644 Consumer = &CI->getASTConsumer(); P.reset( new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); -@@ -158,8 +234,8 @@ IncrementalParser::ParseOrWrapTopLevelDecl() { - LastPTU.TUPart = C.getTranslationUnitDecl(); - - // Skip previous eof due to last incremental input. -- if (P->getCurToken().is(tok::eof)) { -- P->ConsumeToken(); -+ if (P->getCurToken().is(tok::annot_repl_input_end)) { -+ P->ConsumeAnyToken(); - // FIXME: Clang does not call ExitScope on finalizing the regular TU, we - // might want to do that around HandleEndOfTranslationUnit. - P->ExitScope(); -@@ -259,25 +335,30 @@ IncrementalParser::Parse(llvm::StringRef input) { - Token Tok; - do { - PP.Lex(Tok); -- } while (Tok.isNot(tok::eof)); -+ } while (Tok.isNot(tok::annot_repl_input_end)); - } - - Token AssertTok; - PP.Lex(AssertTok); -- assert(AssertTok.is(tok::eof) && -+ assert(AssertTok.is(tok::annot_repl_input_end) && +@@ -267,17 +343,22 @@ IncrementalParser::Parse(llvm::StringRef input) { + assert(AssertTok.is(tok::eof) && "Lexer must be EOF when starting incremental parse!"); - if (CodeGenerator *CG = getCodeGen(Act.get())) { @@ -603,7 +531,7 @@ index 373e2844b4e4..259b9875e6be 100644 TranslationUnitDecl *MostRecentTU = PTU.TUPart; TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h -index 8e45d6b5931b..99e37588df9d 100644 +index 8e45d6b59..99e37588d 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -16,7 +16,6 @@ @@ -644,7 +572,7 @@ index 8e45d6b5931b..99e37588df9d 100644 llvm::Expected ParseOrWrapTopLevelDecl(); }; diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp -index a6f5fdc6eefc..e8a07eceb678 100644 +index a6f5fdc6e..4391bd008 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -16,7 +16,11 @@ @@ -659,7 +587,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" -@@ -27,12 +31,15 @@ +@@ -27,12 +31,16 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" @@ -671,14 +599,14 @@ index a6f5fdc6eefc..e8a07eceb678 100644 +#include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/Module.h" #include "llvm/Support/Errc.h" --#include "llvm/Support/Host.h" -- ++#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" -+#include "llvm/TargetParser/Host.h" + #include "llvm/Support/Host.h" +- using namespace clang; // FIXME: Figure out how to unify with namespace init_convenience from -@@ -176,7 +183,7 @@ Interpreter::Interpreter(std::unique_ptr CI, +@@ -176,7 +184,7 @@ Interpreter::Interpreter(std::unique_ptr CI, llvm::ErrorAsOutParameter EAO(&Err); auto LLVMCtx = std::make_unique(); TSCtx = std::make_unique(std::move(LLVMCtx)); @@ -687,7 +615,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 *TSCtx->getContext(), Err); } -@@ -189,6 +196,28 @@ Interpreter::~Interpreter() { +@@ -189,6 +197,29 @@ Interpreter::~Interpreter() { } } @@ -697,6 +625,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 +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); @@ -716,12 +645,13 @@ index a6f5fdc6eefc..e8a07eceb678 100644 llvm::Expected> Interpreter::create(std::unique_ptr CI) { llvm::Error Err = llvm::Error::success(); -@@ -196,6 +225,14 @@ Interpreter::create(std::unique_ptr CI) { +@@ -196,6 +227,15 @@ 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); ++ auto PTU = Interp->Parse(Runtimes); ++ if (!PTU) ++ return PTU.takeError(); + + Interp->ValuePrintingInfo.resize(3); + // FIXME: This is a ugly hack. Undo command checks its availability by looking @@ -731,7 +661,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 return std::move(Interp); } -@@ -203,19 +240,50 @@ const CompilerInstance *Interpreter::getCompilerInstance() const { +@@ -203,25 +243,53 @@ const CompilerInstance *Interpreter::getCompilerInstance() const { return IncrParser->getCI(); } @@ -783,10 +713,17 @@ index a6f5fdc6eefc..e8a07eceb678 100644 +} + llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { -- assert(T.TheModule); + assert(T.TheModule); if (!IncrExecutor) { - const clang::TargetInfo &TI = - getCompilerInstance()->getASTContext().getTargetInfo(); +- const clang::TargetInfo &TI = +- getCompilerInstance()->getASTContext().getTargetInfo(); +- llvm::Error Err = llvm::Error::success(); +- IncrExecutor = std::make_unique(*TSCtx, Err, TI); +- ++ auto Err = CreateExecutor(); + if (Err) + return Err; + } @@ -235,7 +303,26 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { return llvm::Error::success(); } @@ -842,11 +779,27 @@ index a6f5fdc6eefc..e8a07eceb678 100644 return llvm::make_error("Operation failed. " "Too many undos", std::error_code()); -@@ -283,3 +370,305 @@ llvm::Error Interpreter::Undo(unsigned N) { +@@ -283,3 +370,359 @@ llvm::Error Interpreter::Undo(unsigned N) { } return llvm::Error::success(); } + ++llvm::Error Interpreter::LoadDynamicLibrary(const char *name) { ++ auto EE = getExecutionEngine(); ++ if (!EE) ++ return EE.takeError(); ++ ++ auto &DL = EE->getDataLayout(); ++ ++ if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load( ++ name, DL.getGlobalPrefix())) ++ EE->getMainJITDylib().addGenerator(std::move(*DLSG)); ++ else ++ return DLSG.takeError(); ++ ++ return llvm::Error::success(); ++} ++ +llvm::Expected +Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) { + assert(CXXRD && "Cannot compile a destructor for a nullptr"); @@ -928,7 +881,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + E = EWC->getSubExpr(); + } + -+ExprResult getCall() { ++ ExprResult getCall() { + QualType Ty = E->getType(); + QualType DesugaredTy = Ty.getDesugaredType(Ctx); + @@ -1000,8 +953,8 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc], + E->getBeginLoc(), Args, E->getEndLoc()); + } -+ default: llvm_unreachable("Unknown InterfaceKind."); + } ++ llvm_unreachable("Unhandled Interpreter::InterfaceKind"); + } + + Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) { @@ -1010,19 +963,22 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + + Interpreter::InterfaceKind + VisitMemberPointerType(const MemberPointerType *Ty) { -+ llvm_unreachable("Not implemented yet"); ++ 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) { -+ 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()); ++ HandlePtrType(Ty); + return Interpreter::InterfaceKind::NoAlloc; + } + @@ -1038,10 +994,11 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + Args.push_back(E); + else if (Ty->isFloatingType()) + Args.push_back(E); -+ else if (Ty->isVoidType()) -+ 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; + } @@ -1061,6 +1018,14 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + 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 + @@ -1095,7 +1060,9 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue}); + + ExprResult Result = Builder.getCall(); -+ assert(!Result.isInvalid() && "Failed to generate the CallExpr!"); ++ // It could fail, like printing an array type in C. (not supported) ++ if (Result.isInvalid()) ++ return E; + return Result.get(); +} + @@ -1118,11 +1085,35 @@ index a6f5fdc6eefc..e8a07eceb678 100644 +} + +REPL_EXTERNAL_VISIBILITY void ++__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, ++ void *OpaqueType) { ++ Value &VRef = *(Value *)OutVal; ++ VRef = Value(static_cast(This), OpaqueType); ++} ++ ++static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) { ++ QualType QT = V.getType(); ++ if (const auto *ET = QT->getAs()) ++ QT = ET->getDecl()->getIntegerType(); ++ ++ switch (QT->getAs()->getKind()) { ++ default: ++ llvm_unreachable("unknown type kind!"); ++#define X(type, name) \ ++ case BuiltinType::name: \ ++ V.set##name(Data); \ ++ break; ++ REPL_BUILTIN_TYPES ++#undef X ++ } ++} ++ ++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); ++ SetValueDataBasedOnQualType(VRef, Val); +} + +REPL_EXTERNAL_VISIBILITY void @@ -1150,7 +1141,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 +} diff --git a/clang/lib/Interpreter/InterpreterUtils.cpp b/clang/lib/Interpreter/InterpreterUtils.cpp new file mode 100644 -index 000000000000..1ec2bf54987b +index 000000000..c19cf6aa3 --- /dev/null +++ b/clang/lib/Interpreter/InterpreterUtils.cpp @@ -0,0 +1,111 @@ @@ -1170,9 +1161,9 @@ index 000000000000..1ec2bf54987b + +namespace clang { + -+IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uintptr_t Ptr) { -+ const llvm::APInt Addr(8 * sizeof(void *), Ptr); -+ return IntegerLiteral::Create(C, Addr, C.getUIntPtrType(), SourceLocation()); ++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) { @@ -1189,7 +1180,7 @@ index 000000000000..1ec2bf54987b + +Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, uintptr_t Ptr) { + ASTContext &Ctx = S.getASTContext(); -+ return CStyleCastPtrExpr(S, Ty, IntegerLiteralExpr(Ctx, Ptr)); ++ return CStyleCastPtrExpr(S, Ty, IntegerLiteralExpr(Ctx, (uint64_t)Ptr)); +} + +Sema::DeclGroupPtrTy CreateDGPtrFrom(Sema &S, Decl *D) { @@ -1208,10 +1199,10 @@ index 000000000000..1ec2bf54987b + if (!Within) + S.LookupName(R, S.TUScope); + else { -+ if (const clang::TagDecl *TD = dyn_cast(Within)) -+ if (!TD->getDefinition()) -+ // No definition, no lookup result. -+ return nullptr; ++ if (const auto *TD = dyn_cast(Within); ++ TD && !TD->getDefinition()) ++ // No definition, no lookup result. ++ return nullptr; + + S.LookupQualifiedName(R, const_cast(Within)); + } @@ -1267,10 +1258,10 @@ index 000000000000..1ec2bf54987b +} // namespace clang diff --git a/clang/lib/Interpreter/InterpreterUtils.h b/clang/lib/Interpreter/InterpreterUtils.h new file mode 100644 -index 000000000000..61f4cf7e1239 +index 000000000..8df158c17 --- /dev/null +++ b/clang/lib/Interpreter/InterpreterUtils.h -@@ -0,0 +1,55 @@ +@@ -0,0 +1,54 @@ +//===--- InterpreterUtils.h - Incremental Utils --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -1306,9 +1297,8 @@ index 000000000000..61f4cf7e1239 +#include "llvm/Support/Errc.h" +#include "llvm/TargetParser/Host.h" + -+// TODO: create a sub namespace `repl`. +namespace clang { -+IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uintptr_t Ptr); ++IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val); + +Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E); + @@ -1328,10 +1318,10 @@ index 000000000000..61f4cf7e1239 +#endif diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp new file mode 100644 -index 000000000000..34a77344bc86 +index 000000000..fe37eebac --- /dev/null +++ b/clang/lib/Interpreter/Value.cpp -@@ -0,0 +1,260 @@ +@@ -0,0 +1,266 @@ +//===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -1406,6 +1396,9 @@ index 000000000000..34a77344bc86 + } + } + ++ // 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; + } @@ -1421,6 +1414,8 @@ index 000000000000..34a77344bc86 + 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}; +}; @@ -1430,10 +1425,11 @@ index 000000000000..34a77344bc86 + if (Ctx.hasSameType(QT, Ctx.VoidTy)) + return Value::K_Void; + -+ if (const auto *ET = dyn_cast(QT.getTypePtr())) ++ if (const auto *ET = QT->getAs()) + QT = ET->getDecl()->getIntegerType(); + -+ if (!QT->isBuiltinType() || QT->castAs()->isNullPtrType()) ++ const auto *BT = QT->getAs(); ++ if (!BT || BT->isNullPtrType()) + return Value::K_PtrOrObj; + + switch (QT->getAs()->getKind()) { @@ -1592,141 +1588,45 @@ index 000000000000..34a77344bc86 + assert(OpaqueType != nullptr && "Can't print default Value"); + Out << "Not implement yet.\n"; +} -diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp -index 66168467ecf5..0822f83b58df 100644 ---- a/clang/lib/Lex/PPLexerChange.cpp -+++ b/clang/lib/Lex/PPLexerChange.cpp -@@ -526,13 +526,19 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { - return LeavingSubmodule; - } - } -- - // If this is the end of the main file, form an EOF token. - assert(CurLexer && "Got EOF but no current lexer set!"); - const char *EndPos = getCurLexerEndPos(); - Result.startToken(); - CurLexer->BufferPtr = EndPos; -- CurLexer->FormTokenWithChars(Result, EndPos, tok::eof); -+ -+ if (isIncrementalProcessingEnabled()) { -+ CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_repl_input_end); -+ Result.setAnnotationEndLoc(Result.getLocation()); -+ Result.setAnnotationValue(nullptr); -+ } else { -+ CurLexer->FormTokenWithChars(Result, EndPos, tok::eof); -+ } - - if (isCodeCompletionEnabled()) { - // Inserting the code-completion point increases the source buffer by 1, -diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp -index 3a7f5426d4a7..57a3dfba4f1d 100644 ---- a/clang/lib/Parse/ParseCXXInlineMethods.cpp -+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp -@@ -836,6 +836,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, - case tok::annot_module_begin: - case tok::annot_module_end: - case tok::annot_module_include: -+ case tok::annot_repl_input_end: - // Ran out of tokens. - return false; - -@@ -1242,6 +1243,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, - case tok::annot_module_begin: - case tok::annot_module_end: - case tok::annot_module_include: -+ case tok::annot_repl_input_end: - // Ran out of tokens. - return false; - -diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp -index e6812ac72c88..3e64e6f074fc 100644 ---- a/clang/lib/Parse/ParseDecl.cpp -+++ b/clang/lib/Parse/ParseDecl.cpp -@@ -2030,6 +2030,7 @@ void Parser::SkipMalformedDecl() { - case tok::annot_module_begin: - case tok::annot_module_end: - case tok::annot_module_include: -+ case tok::annot_repl_input_end: - return; - - default: -@@ -5394,6 +5395,13 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { - - SmallVector DeclsInGroup; - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get())); +diff --git a/clang/test/Interpreter/Inputs/dynamic-library-test.cpp b/clang/test/Interpreter/Inputs/dynamic-library-test.cpp +new file mode 100644 +index 000000000..1f143ba04 +--- /dev/null ++++ b/clang/test/Interpreter/Inputs/dynamic-library-test.cpp +@@ -0,0 +1,6 @@ ++int ultimate_answer = 0; + -+ if (Tok.is(tok::annot_repl_input_end) && -+ Tok.getAnnotationValue() != nullptr) { -+ ConsumeAnnotationToken(); -+ cast(DeclsInGroup.back())->setValuePrinting(); -+ } ++int calculate_answer() { ++ ultimate_answer = 42; ++ return 5; ++} +diff --git a/clang/test/Interpreter/dynamic-library.cpp b/clang/test/Interpreter/dynamic-library.cpp +new file mode 100644 +index 000000000..794ccccf7 +--- /dev/null ++++ b/clang/test/Interpreter/dynamic-library.cpp +@@ -0,0 +1,19 @@ ++// REQUIRES: host-supports-jit, system-linux + - // Currently happens for things like -fms-extensions and use `__if_exists`. - for (Stmt *S : Stmts) - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S)); -diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp -index 1c8441fafc48..446fc7ea6385 100644 ---- a/clang/lib/Parse/ParseStmt.cpp -+++ b/clang/lib/Parse/ParseStmt.cpp -@@ -543,9 +543,22 @@ StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { - return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr); - } - -- // Otherwise, eat the semicolon. -- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); -- return handleExprStmt(Expr, StmtCtx); -+ Token *CurTok = nullptr; -+ // If we're parsing an ExprStmt and the last semicolon is missing and the -+ // incremental externsion is enabled and we're reaching the end, consider we -+ // want to do value printing. Note we shouldn't eat the token since the -+ // callback need it. -+ if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::annot_repl_input_end)) -+ CurTok = &Tok; -+ else -+ // Otherwise, eat the semicolon. -+ ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); ++// RUN: %clang -xc++ -o %T/libdynamic-library-test.so -fPIC -shared -DLIBRARY %S/Inputs/dynamic-library-test.cpp ++// RUN: cat %s | env LD_LIBRARY_PATH=%T:$LD_LIBRARY_PATH clang-repl | FileCheck %s + -+ StmtResult R = handleExprStmt(Expr, StmtCtx); -+ if (!R.isInvalid() && CurTok) -+ CurTok->setAnnotationValue(R.get()); ++#include + -+ return R; - } - - /// ParseSEHTryBlockCommon -diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp -index 6db3dc3156fd..9682f12ed211 100644 ---- a/clang/lib/Parse/Parser.cpp -+++ b/clang/lib/Parse/Parser.cpp -@@ -319,6 +319,7 @@ bool Parser::SkipUntil(ArrayRef Toks, SkipUntilFlags Flags) { - case tok::annot_module_begin: - case tok::annot_module_end: - case tok::annot_module_include: -+ case tok::annot_repl_input_end: - // Stop before we change submodules. They generally indicate a "good" - // place to pick up parsing again (except in the special case where - // we're trying to skip to EOF). -@@ -614,8 +615,8 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, - - // Skip over the EOF token, flagging end of previous input for incremental - // processing -- if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) -- ConsumeToken(); -+ if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::annot_repl_input_end)) -+ ConsumeAnnotationToken(); - - Result = nullptr; - switch (Tok.getKind()) { -@@ -695,6 +696,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, - return false; - - case tok::eof: -+ case tok::annot_repl_input_end: - // Check whether -fmax-tokens= was reached. - if (PP.getMaxTokens() != 0 && PP.getTokenCount() > PP.getMaxTokens()) { - PP.Diag(Tok.getLocation(), diag::warn_max_tokens_total) ++extern int ultimate_answer; ++int calculate_answer(); ++ ++%lib libdynamic-library-test.so ++ ++printf("Return value: %d\n", calculate_answer()); ++// CHECK: Return value: 5 ++ ++printf("Variable: %d\n", ultimate_answer); ++// CHECK-NEXT: Variable: 42 ++ ++%quit diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt -index b51a18c10cdc..15d7f9439ff5 100644 +index b51a18c10..15d7f9439 100644 --- a/clang/tools/clang-repl/CMakeLists.txt +++ b/clang/tools/clang-repl/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_tool(clang-repl @@ -1737,8 +1637,26 @@ index b51a18c10cdc..15d7f9439ff5 100644 clangBasic clangFrontend clangInterpreter +diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp +index 401a31d34..33faf3fab 100644 +--- a/clang/tools/clang-repl/ClangRepl.cpp ++++ b/clang/tools/clang-repl/ClangRepl.cpp +@@ -123,6 +123,13 @@ int main(int argc, const char **argv) { + } + continue; + } ++ if (Line->rfind("%lib ", 0) == 0) { ++ if (auto Err = Interp->LoadDynamicLibrary(Line->data() + 5)) { ++ llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); ++ HasError = true; ++ } ++ continue; ++ } + + if (auto Err = Interp->ParseAndExecute(*Line)) { + llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt -index 1a099dbbfe59..698494b9897f 100644 +index 1a099dbbf..698494b98 100644 --- a/clang/unittests/Interpreter/CMakeLists.txt +++ b/clang/unittests/Interpreter/CMakeLists.txt @@ -22,3 +22,5 @@ target_link_libraries(ClangReplInterpreterTests PUBLIC @@ -1747,8 +1665,30 @@ index 1a099dbbfe59..698494b9897f 100644 endif() + +export_executable_symbols(ClangReplInterpreterTests) +diff --git a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp +index f54c65568..6d0433a98 100644 +--- a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp ++++ b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp +@@ -25,7 +25,6 @@ + #include "llvm/ExecutionEngine/Orc/LLJIT.h" + #include "llvm/Support/ManagedStatic.h" + #include "llvm/Support/TargetSelect.h" +-#include "llvm-c/Error.h" + + #include "gmock/gmock.h" + #include "gtest/gtest.h" +@@ -116,7 +115,8 @@ extern "C" int throw_exception() { + llvm::cantFail(Interp->ParseAndExecute(ExceptionCode)); + testing::internal::CaptureStdout(); + auto ThrowException = +- (int (*)())llvm::cantFail(Interp->getSymbolAddress("throw_exception")); ++ llvm::cantFail(Interp->getSymbolAddress("throw_exception")) ++ .toPtr(); + EXPECT_ANY_THROW(ThrowException()); + std::string CapturedStdOut = testing::internal::GetCapturedStdout(); + EXPECT_EQ(CapturedStdOut, "Caught: 'To be caught in JIT'\n"); diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp -index d4900a0e4de8..4e737a0b313a 100644 +index d4900a0e4..330fd18ab 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -17,6 +17,7 @@ @@ -1759,18 +1699,28 @@ index d4900a0e4de8..4e737a0b313a 100644 #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" -@@ -33,6 +34,10 @@ using namespace clang; +@@ -33,6 +34,11 @@ using namespace clang; #define CLANG_INTERPRETER_NO_SUPPORT_EXEC #endif +int Global = 42; -+int getGlobal() { return Global; } -+void setGlobal(int val) { Global = val; } ++// 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 -@@ -276,8 +281,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { +@@ -225,7 +231,7 @@ TEST(IncrementalProcessing, FindMangledNameSymbol) { + + std::string MangledName = MangleName(FD); + auto Addr = cantFail(Interp->getSymbolAddress(MangledName)); +- EXPECT_NE(0U, Addr); ++ EXPECT_NE(0U, Addr.getValue()); + GlobalDecl GD(FD); + EXPECT_EQ(Addr, cantFail(Interp->getSymbolAddress(GD))); + } +@@ -276,8 +282,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { std::vector Args = {"-fno-delayed-template-parsing"}; std::unique_ptr Interp = createInterpreter(Args); @@ -1780,42 +1730,59 @@ index d4900a0e4de8..4e737a0b313a 100644 "class A {};" "struct B {" " template" -@@ -314,4 +318,55 @@ TEST(IncrementalProcessing, InstantiateTemplate) { +@@ -309,9 +314,109 @@ TEST(IncrementalProcessing, InstantiateTemplate) { + + std::string MangledName = MangleName(TmpltSpec); + typedef int (*TemplateSpecFn)(void *); +- auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName)); ++ auto fn = ++ cantFail(Interp->getSymbolAddress(MangledName)).toPtr(); + EXPECT_EQ(42, fn(NewA)); free(NewA); } ++#ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC ++TEST(InterpreterTest, DISABLED_Value) { ++#else +TEST(InterpreterTest, Value) { ++#endif ++ // We cannot execute on the platform. ++ if (!HostSupportsJit()) ++ return; ++ + 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()); -+ EXPECT_FALSE(V1.isPointerOrObjectType()); + + 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()); -+ EXPECT_FALSE(V2.isPointerOrObjectType()); + + 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()); -+ EXPECT_TRUE(V3.isPointerOrObjectType()); + + Value V4; + llvm::cantFail(Interp->ParseAndExecute("int getGlobal();")); @@ -1834,5 +1801,43 @@ index d4900a0e4de8..4e737a0b313a 100644 + // 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 From 058412d6322af8ff6707ff571d3ca837bea63d0e Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:46:45 +0300 Subject: [PATCH 3/8] Delete clang16-D148435-WeakRefs.patch --- patches/llvm/clang16-D148435-WeakRefs.patch | 33 --------------------- 1 file changed, 33 deletions(-) delete mode 100644 patches/llvm/clang16-D148435-WeakRefs.patch diff --git a/patches/llvm/clang16-D148435-WeakRefs.patch b/patches/llvm/clang16-D148435-WeakRefs.patch deleted file mode 100644 index e04f43c2..00000000 --- a/patches/llvm/clang16-D148435-WeakRefs.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp -index 12d602fed693..e73102544361 100644 ---- a/clang/lib/CodeGen/CodeGenModule.cpp -+++ b/clang/lib/CodeGen/CodeGenModule.cpp -@@ -7202,7 +7202,6 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) { - "Newly created module should not have manglings"); - NewBuilder->Manglings = std::move(Manglings); - -- assert(WeakRefReferences.empty() && "Not all WeakRefRefs have been applied"); - NewBuilder->WeakRefReferences = std::move(WeakRefReferences); - - NewBuilder->TBAA = std::move(TBAA); -diff --git a/clang/test/Interpreter/execute-weak.cpp b/clang/test/Interpreter/execute-weak.cpp -index 5b343512c545..66f2214ab03c 100644 ---- a/clang/test/Interpreter/execute-weak.cpp -+++ b/clang/test/Interpreter/execute-weak.cpp -@@ -2,11 +2,16 @@ - // RUN: clang-repl "int i = 10;" 'extern "C" int printf(const char*,...);' \ - // RUN: 'auto r1 = printf("i = %d\n", i);' | FileCheck --check-prefix=CHECK-DRIVER %s - // CHECK-DRIVER: i = 10 -+// - // UNSUPPORTED: system-aix, system-windows - // RUN: cat %s | clang-repl | FileCheck %s -+ - extern "C" int printf(const char *, ...); - int __attribute__((weak)) bar() { return 42; } - auto r4 = printf("bar() = %d\n", bar()); - // CHECK: bar() = 42 - -+int a = 12; -+static __typeof(a) b __attribute__((__weakref__("a"))); -+int c = b; - %quit From f03061acd50262e90d30704ad76cb2137177ce71 Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:48:42 +0300 Subject: [PATCH 4/8] Update clang16-1-Value.patch --- patches/llvm/clang16-1-Value.patch | 102 ++++++++++++++--------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/patches/llvm/clang16-1-Value.patch b/patches/llvm/clang16-1-Value.patch index 9f411410..5ed88832 100644 --- a/patches/llvm/clang16-1-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -5,14 +5,14 @@ index fd22af976..e68021845 100644 @@ -14,13 +14,15 @@ #ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H #define LLVM_CLANG_INTERPRETER_INTERPRETER_H - + -#include "clang/Interpreter/PartialTranslationUnit.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 "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" @@ -20,7 +20,7 @@ index fd22af976..e68021845 100644 - #include #include - + @@ -28,7 +30,7 @@ namespace llvm { namespace orc { class LLJIT; @@ -28,12 +28,12 @@ index fd22af976..e68021845 100644 -} +} // namespace orc } // namespace llvm - + namespace clang { @@ -52,39 +54,64 @@ class Interpreter { - + Interpreter(std::unique_ptr CI, llvm::Error &Err); - + + llvm::Error CreateExecutor(); + unsigned InitPTUSize = 0; + @@ -64,10 +64,10 @@ index fd22af976..e68021845 100644 - } + llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr); + llvm::Expected CompileDtorCall(CXXRecordDecl *CXXRD); - + /// Undo N previous incremental inputs. llvm::Error Undo(unsigned N = 1); - + - /// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses + /// Link a dynamic library + llvm::Error LoadDynamicLibrary(const char *name); @@ -77,13 +77,13 @@ index fd22af976..e68021845 100644 /// mangled name. - llvm::Expected getSymbolAddress(GlobalDecl GD) const; + llvm::Expected getSymbolAddress(GlobalDecl GD) const; - + - /// \returns the \c JITTargetAddress of a given name as written in the IR. - llvm::Expected + /// \returns the \c ExecutorAddr of a given name as written in the IR. + llvm::Expected getSymbolAddress(llvm::StringRef IRName) const; - + - /// \returns the \c JITTargetAddress of a given name as written in the object + /// \returns the \c ExecutorAddr of a given name as written in the object /// file. @@ -109,7 +109,7 @@ index fd22af976..e68021845 100644 + llvm::SmallVector ValuePrintingInfo; }; } // namespace clang - + diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h new file mode 100644 index 000000000..4df436703 @@ -328,7 +328,7 @@ index c49f22fdd..565e824bf 100644 Interpreter.cpp + InterpreterUtils.cpp + Value.cpp - + DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -338,20 +338,20 @@ index 37d230b61..489ea48e0 100644 @@ -86,7 +86,7 @@ llvm::Error IncrementalExecutor::runCtors() const { return Jit->initialize(Jit->getMainJITDylib()); } - + -llvm::Expected +llvm::Expected IncrementalExecutor::getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const { auto Sym = (NameKind == LinkerName) ? Jit->lookupLinkerMangled(Name) @@ -94,7 +94,7 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name, - + if (!Sym) return Sym.takeError(); - return Sym->getValue(); + return Sym; } - + } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index 54d37c763..dd0a210a0 100644 @@ -362,9 +362,9 @@ index 54d37c763..dd0a210a0 100644 #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" - + #include - + @@ -51,9 +52,10 @@ public: llvm::Error removeModule(PartialTranslationUnit &PTU); llvm::Error runCtors() const; @@ -376,7 +376,7 @@ index 54d37c763..dd0a210a0 100644 + + llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; } }; - + } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 373e2844b..f892eeb81 100644 @@ -384,7 +384,7 @@ index 373e2844b..f892eeb81 100644 +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// - + #include "IncrementalParser.h" - #include "clang/AST/DeclContextInternals.h" @@ -402,9 +402,9 @@ index 373e2844b..f892eeb81 100644 #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Error.h" @@ -31,6 +30,79 @@ - + namespace clang { - + +class IncrementalASTConsumer final : public ASTConsumer { + Interpreter &Interp; + std::unique_ptr Consumer; @@ -484,7 +484,7 @@ index 373e2844b..f892eeb81 100644 @@ -122,7 +194,8 @@ public: } }; - + -IncrementalParser::IncrementalParser(std::unique_ptr Instance, +IncrementalParser::IncrementalParser(Interpreter &Interp, + std::unique_ptr Instance, @@ -504,7 +504,7 @@ index 373e2844b..f892eeb81 100644 @@ -267,17 +343,22 @@ IncrementalParser::Parse(llvm::StringRef input) { assert(AssertTok.is(tok::eof) && "Lexer must be EOF when starting incremental parse!"); - + - if (CodeGenerator *CG = getCodeGen(Act.get())) { - std::unique_ptr M(CG->ReleaseModule()); - CG->StartModule("incr_module_" + std::to_string(PTUs.size()), @@ -513,10 +513,10 @@ index 373e2844b..f892eeb81 100644 + 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())) { @@ -536,7 +536,7 @@ index 8e45d6b59..99e37588d 100644 +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -16,7 +16,6 @@ #include "clang/Interpreter/PartialTranslationUnit.h" - + #include "clang/AST/GlobalDecl.h" - #include "llvm/ADT/ArrayRef.h" @@ -554,18 +554,18 @@ index 8e45d6b59..99e37588d 100644 /// @@ -57,7 +56,8 @@ class IncrementalParser { std::list PTUs; - + public: - IncrementalParser(std::unique_ptr Instance, + IncrementalParser(Interpreter &Interp, + std::unique_ptr Instance, llvm::LLVMContext &LLVMCtx, llvm::Error &Err); ~IncrementalParser(); - + @@ -76,6 +76,8 @@ public: - + std::list &getPTUs() { return PTUs; } - + + std::unique_ptr GenModule(); + private: @@ -578,7 +578,7 @@ index a6f5fdc6e..4391bd008 100644 @@ -16,7 +16,11 @@ #include "IncrementalExecutor.h" #include "IncrementalParser.h" - + +#include "InterpreterUtils.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Mangle.h" @@ -604,7 +604,7 @@ index a6f5fdc6e..4391bd008 100644 #include "llvm/Support/Host.h" - using namespace clang; - + // FIXME: Figure out how to unify with namespace init_convenience from @@ -176,7 +184,7 @@ Interpreter::Interpreter(std::unique_ptr CI, llvm::ErrorAsOutParameter EAO(&Err); @@ -614,11 +614,11 @@ index a6f5fdc6e..4391bd008 100644 + IncrParser = std::make_unique(*this, std::move(CI), *TSCtx->getContext(), Err); } - + @@ -189,6 +197,29 @@ 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. @@ -660,11 +660,11 @@ index a6f5fdc6e..4391bd008 100644 + Interp->InitPTUSize = Interp->IncrParser->getPTUs().size(); return std::move(Interp); } - + @@ -203,25 +243,53 @@ const CompilerInstance *Interpreter::getCompilerInstance() const { return IncrParser->getCI(); } - + -const llvm::orc::LLJIT *Interpreter::getExecutionEngine() const { - if (IncrExecutor) - return IncrExecutor->getExecutionEngine(); @@ -691,7 +691,7 @@ index a6f5fdc6e..4391bd008 100644 + 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 @@ -700,7 +700,7 @@ index a6f5fdc6e..4391bd008 100644 + clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation()); return IncrParser->Parse(Code); } - + +llvm::Error Interpreter::CreateExecutor() { + const clang::TargetInfo &TI = + getCompilerInstance()->getASTContext().getTargetInfo(); @@ -727,7 +727,7 @@ index a6f5fdc6e..4391bd008 100644 @@ -235,7 +303,26 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { return llvm::Error::success(); } - + -llvm::Expected +llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) { + @@ -755,7 +755,7 @@ index a6f5fdc6e..4391bd008 100644 @@ -245,7 +332,7 @@ Interpreter::getSymbolAddress(GlobalDecl GD) const { return getSymbolAddress(MangledName); } - + -llvm::Expected +llvm::Expected Interpreter::getSymbolAddress(llvm::StringRef IRName) const { @@ -764,7 +764,7 @@ index a6f5fdc6e..4391bd008 100644 @@ -255,7 +342,7 @@ Interpreter::getSymbolAddress(llvm::StringRef IRName) const { return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName); } - + -llvm::Expected +llvm::Expected Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const { @@ -772,7 +772,7 @@ index a6f5fdc6e..4391bd008 100644 return llvm::make_error("Operation failed. " @@ -268,7 +355,7 @@ Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const { llvm::Error Interpreter::Undo(unsigned N) { - + std::list &PTUs = IncrParser->getPTUs(); - if (N > PTUs.size()) + if (N > getEffectivePTUSize()) @@ -1631,7 +1631,7 @@ index b51a18c10..15d7f9439 100644 +++ b/clang/tools/clang-repl/CMakeLists.txt @@ -12,6 +12,7 @@ add_clang_tool(clang-repl ) - + clang_target_link_libraries(clang-repl PRIVATE + clangAST clangBasic @@ -1652,7 +1652,7 @@ index 401a31d34..33faf3fab 100644 + } + continue; + } - + if (auto Err = Interp->ParseAndExecute(*Line)) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt @@ -1674,7 +1674,7 @@ index f54c65568..6d0433a98 100644 #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/TargetSelect.h" -#include "llvm-c/Error.h" - + #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -116,7 +115,8 @@ extern "C" int throw_exception() { @@ -1698,11 +1698,11 @@ index d4900a0e4..330fd18ab 100644 +#include "clang/Interpreter/Value.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" - + @@ -33,6 +34,11 @@ 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; } @@ -1712,7 +1712,7 @@ index d4900a0e4..330fd18ab 100644 using Args = std::vector; static std::unique_ptr @@ -225,7 +231,7 @@ TEST(IncrementalProcessing, FindMangledNameSymbol) { - + std::string MangledName = MangleName(FD); auto Addr = cantFail(Interp->getSymbolAddress(MangledName)); - EXPECT_NE(0U, Addr); @@ -1723,7 +1723,7 @@ index d4900a0e4..330fd18ab 100644 @@ -276,8 +282,7 @@ TEST(IncrementalProcessing, InstantiateTemplate) { std::vector Args = {"-fno-delayed-template-parsing"}; std::unique_ptr Interp = createInterpreter(Args); - + - llvm::cantFail(Interp->Parse("void* operator new(__SIZE_TYPE__, void* __p);" - "extern \"C\" int printf(const char*,...);" + llvm::cantFail(Interp->Parse("extern \"C\" int printf(const char*,...);" @@ -1731,7 +1731,7 @@ index d4900a0e4..330fd18ab 100644 "struct B {" " template" @@ -309,9 +314,109 @@ TEST(IncrementalProcessing, InstantiateTemplate) { - + std::string MangledName = MangleName(TmpltSpec); typedef int (*TemplateSpecFn)(void *); - auto fn = (TemplateSpecFn)cantFail(Interp->getSymbolAddress(MangledName)); @@ -1740,7 +1740,7 @@ index d4900a0e4..330fd18ab 100644 EXPECT_EQ(42, fn(NewA)); free(NewA); } - + +#ifdef CLANG_INTERPRETER_NO_SUPPORT_EXEC +TEST(InterpreterTest, DISABLED_Value) { +#else From 19d532f62db2a05af238e2f5c99d1c0c028c1d1e Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Tue, 29 Aug 2023 09:16:30 +0300 Subject: [PATCH 5/8] Update clang16-1-Value.patch --- patches/llvm/clang16-1-Value.patch | 283 ++++++++++++++++++++++++++--- 1 file changed, 262 insertions(+), 21 deletions(-) diff --git a/patches/llvm/clang16-1-Value.patch b/patches/llvm/clang16-1-Value.patch index 5ed88832..9d702ee8 100644 --- a/patches/llvm/clang16-1-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -1,3 +1,42 @@ +diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h +index 863f6ac57..feb6db113 100644 +--- a/clang/include/clang/AST/Decl.h ++++ b/clang/include/clang/AST/Decl.h +@@ -4308,6 +4308,7 @@ class TopLevelStmtDecl : public Decl { + friend class ASTDeclWriter; + + Stmt *Statement = nullptr; ++ bool IsSemiMissing = false; + + TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S) + : Decl(TopLevelStmt, DC, L), Statement(S) {} +@@ -4321,6 +4322,12 @@ public: + SourceRange getSourceRange() const override LLVM_READONLY; + Stmt *getStmt() { return Statement; } + const Stmt *getStmt() const { return Statement; } ++ void setStmt(Stmt *S) { ++ assert(IsSemiMissing && "Operation supported for printing values only!"); ++ Statement = S; ++ } ++ bool isSemiMissing() const { return IsSemiMissing; } ++ void setSemiMissing(bool Missing = true) { IsSemiMissing = Missing; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TopLevelStmt; } +diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def +index 96feae991..752629855 100644 +--- a/clang/include/clang/Basic/TokenKinds.def ++++ b/clang/include/clang/Basic/TokenKinds.def +@@ -936,6 +936,9 @@ ANNOTATION(module_end) + // into the name of a header unit. + ANNOTATION(header_unit) + ++// Annotation for end of input in clang-repl. ++ANNOTATION(repl_input_end) ++ + #undef PRAGMA_ANNOTATION + #undef ANNOTATION + #undef TESTING_KEYWORD diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index fd22af976..e68021845 100644 --- a/clang/include/clang/Interpreter/Interpreter.h @@ -318,6 +357,52 @@ index 000000000..4df436703 + +} // namespace clang +#endif +diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h +index 6f9581b9e..6b73f43a1 100644 +--- a/clang/include/clang/Parse/Parser.h ++++ b/clang/include/clang/Parse/Parser.h +@@ -18,6 +18,7 @@ + #include "clang/Basic/OpenMPKinds.h" + #include "clang/Basic/OperatorPrecedence.h" + #include "clang/Basic/Specifiers.h" ++#include "clang/Basic/TokenKinds.h" + #include "clang/Lex/CodeCompletionHandler.h" + #include "clang/Lex/Preprocessor.h" + #include "clang/Sema/DeclSpec.h" +@@ -692,7 +693,8 @@ private: + bool isEofOrEom() { + tok::TokenKind Kind = Tok.getKind(); + return Kind == tok::eof || Kind == tok::annot_module_begin || +- Kind == tok::annot_module_end || Kind == tok::annot_module_include; ++ Kind == tok::annot_module_end || Kind == tok::annot_module_include || ++ Kind == tok::annot_repl_input_end; + } + + /// Checks if the \p Level is valid for use in a fold expression. +diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp +index ffa85e523..1b262d9e6 100644 +--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp ++++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp +@@ -663,7 +663,8 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, + // them. + if (Tok.is(tok::eof) || + (Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) && +- !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end))) ++ !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end) && ++ !Tok.is(tok::annot_repl_input_end))) + return; + + // EmittedDirectiveOnThisLine takes priority over RequireSameLine. +@@ -819,6 +820,9 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, + // -traditional-cpp the lexer keeps /all/ whitespace, including comments. + PP.Lex(Tok); + continue; ++ } else if (Tok.is(tok::annot_repl_input_end)) { ++ PP.Lex(Tok); ++ continue; + } else if (Tok.is(tok::eod)) { + // Don't print end of directive tokens, since they are typically newlines + // that mess up our line tracking. These come from unknown pre-processor diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index c49f22fdd..565e824bf 100644 --- a/clang/lib/Interpreter/CMakeLists.txt @@ -379,7 +464,7 @@ index 54d37c763..dd0a210a0 100644 } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp -index 373e2844b..f892eeb81 100644 +index 373e2844b..e43189071 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -11,7 +11,6 @@ @@ -501,35 +586,57 @@ index 373e2844b..f892eeb81 100644 Consumer = &CI->getASTConsumer(); P.reset( new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); -@@ -267,17 +343,22 @@ IncrementalParser::Parse(llvm::StringRef input) { - assert(AssertTok.is(tok::eof) && - "Lexer must be EOF when starting incremental parse!"); +@@ -158,8 +234,8 @@ IncrementalParser::ParseOrWrapTopLevelDecl() { + LastPTU.TUPart = C.getTranslationUnitDecl(); -- if (CodeGenerator *CG = getCodeGen(Act.get())) { -- std::unique_ptr M(CG->ReleaseModule()); -- CG->StartModule("incr_module_" + std::to_string(PTUs.size()), -- M->getContext()); -- -+ if (std::unique_ptr M = GenModule()) - PTU->TheModule = std::move(M); -- } + // Skip previous eof due to last incremental input. +- if (P->getCurToken().is(tok::eof)) { +- P->ConsumeToken(); ++ if (P->getCurToken().is(tok::annot_repl_input_end)) { ++ P->ConsumeAnyToken(); + // FIXME: Clang does not call ExitScope on finalizing the regular TU, we + // might want to do that around HandleEndOfTranslationUnit. + P->ExitScope(); +@@ -259,23 +335,28 @@ IncrementalParser::Parse(llvm::StringRef input) { + Token Tok; + do { + PP.Lex(Tok); +- } while (Tok.isNot(tok::eof)); ++ } while (Tok.isNot(tok::annot_repl_input_end)); ++ } else { ++ Token AssertTok; ++ PP.Lex(AssertTok); ++ assert(AssertTok.is(tok::annot_repl_input_end) && ++ "Lexer must be EOF when starting incremental parse!"); + } - return PTU; - } +- Token AssertTok; +- PP.Lex(AssertTok); +- assert(AssertTok.is(tok::eof) && +- "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()); + if (CodeGenerator *CG = getCodeGen(Act.get())) { + std::unique_ptr M(CG->ReleaseModule()); +- CG->StartModule("incr_module_" + std::to_string(PTUs.size()), +- M->getContext()); +- +- PTU->TheModule = std::move(M); + CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext()); + return M; -+ } + } +- +- return PTU; + return nullptr; -+} -+ + } + void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { - TranslationUnitDecl *MostRecentTU = PTU.TUPart; - TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h index 8e45d6b59..99e37588d 100644 --- a/clang/lib/Interpreter/IncrementalParser.h @@ -1588,6 +1695,140 @@ index 000000000..fe37eebac + assert(OpaqueType != nullptr && "Can't print default Value"); + Out << "Not implement yet.\n"; +} +diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp +index 66168467e..0822f83b5 100644 +--- a/clang/lib/Lex/PPLexerChange.cpp ++++ b/clang/lib/Lex/PPLexerChange.cpp +@@ -526,13 +526,19 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { + return LeavingSubmodule; + } + } +- + // If this is the end of the main file, form an EOF token. + assert(CurLexer && "Got EOF but no current lexer set!"); + const char *EndPos = getCurLexerEndPos(); + Result.startToken(); + CurLexer->BufferPtr = EndPos; +- CurLexer->FormTokenWithChars(Result, EndPos, tok::eof); ++ ++ if (isIncrementalProcessingEnabled()) { ++ CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_repl_input_end); ++ Result.setAnnotationEndLoc(Result.getLocation()); ++ Result.setAnnotationValue(nullptr); ++ } else { ++ CurLexer->FormTokenWithChars(Result, EndPos, tok::eof); ++ } + + if (isCodeCompletionEnabled()) { + // Inserting the code-completion point increases the source buffer by 1, +diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp +index 3a7f5426d..57a3dfba4 100644 +--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp ++++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp +@@ -836,6 +836,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: ++ case tok::annot_repl_input_end: + // Ran out of tokens. + return false; + +@@ -1242,6 +1243,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: ++ case tok::annot_repl_input_end: + // Ran out of tokens. + return false; + +diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp +index e6812ac72..2f193a3b4 100644 +--- a/clang/lib/Parse/ParseDecl.cpp ++++ b/clang/lib/Parse/ParseDecl.cpp +@@ -2030,6 +2030,7 @@ void Parser::SkipMalformedDecl() { + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: ++ case tok::annot_repl_input_end: + return; + + default: +@@ -5394,6 +5395,13 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { + + SmallVector DeclsInGroup; + DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get())); ++ ++ if (Tok.is(tok::annot_repl_input_end) && ++ Tok.getAnnotationValue() != nullptr) { ++ ConsumeAnnotationToken(); ++ cast(DeclsInGroup.back())->setSemiMissing(); ++ } ++ + // Currently happens for things like -fms-extensions and use `__if_exists`. + for (Stmt *S : Stmts) + DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S)); +diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp +index 1c8441faf..d22e1d440 100644 +--- a/clang/lib/Parse/ParseStmt.cpp ++++ b/clang/lib/Parse/ParseStmt.cpp +@@ -543,9 +543,22 @@ StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) { + return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr); + } + +- // Otherwise, eat the semicolon. +- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); +- return handleExprStmt(Expr, StmtCtx); ++ Token *CurTok = nullptr; ++ // If the semicolon is missing at the end of REPL input, consider if ++ // we want to do value printing. Note this is only enabled in C++ mode ++ // since part of the implementation requires C++ language features. ++ // Note we shouldn't eat the token since the callback needs it. ++ if (Tok.is(tok::annot_repl_input_end) && Actions.getLangOpts().CPlusPlus) ++ CurTok = &Tok; ++ else ++ // Otherwise, eat the semicolon. ++ ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); ++ ++ StmtResult R = handleExprStmt(Expr, StmtCtx); ++ if (CurTok && !R.isInvalid()) ++ CurTok->setAnnotationValue(R.get()); ++ ++ return R; + } + + /// ParseSEHTryBlockCommon +diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp +index 6db3dc315..7fbb27057 100644 +--- a/clang/lib/Parse/Parser.cpp ++++ b/clang/lib/Parse/Parser.cpp +@@ -319,6 +319,7 @@ bool Parser::SkipUntil(ArrayRef Toks, SkipUntilFlags Flags) { + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: ++ case tok::annot_repl_input_end: + // Stop before we change submodules. They generally indicate a "good" + // place to pick up parsing again (except in the special case where + // we're trying to skip to EOF). +@@ -612,11 +613,6 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, + Sema::ModuleImportState &ImportState) { + DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); + +- // Skip over the EOF token, flagging end of previous input for incremental +- // processing +- if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) +- ConsumeToken(); +- + Result = nullptr; + switch (Tok.getKind()) { + case tok::annot_pragma_unused: +@@ -695,6 +691,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, + return false; + + case tok::eof: ++ case tok::annot_repl_input_end: + // Check whether -fmax-tokens= was reached. + if (PP.getMaxTokens() != 0 && PP.getTokenCount() > PP.getMaxTokens()) { + PP.Diag(Tok.getLocation(), diag::warn_max_tokens_total) diff --git a/clang/test/Interpreter/Inputs/dynamic-library-test.cpp b/clang/test/Interpreter/Inputs/dynamic-library-test.cpp new file mode 100644 index 000000000..1f143ba04 From 7fa64cdd6795686cc34d89b6ee1f8579fbcd0978 Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Wed, 30 Aug 2023 02:03:50 +0300 Subject: [PATCH 6/8] Update clang16-1-Value.patch --- patches/llvm/clang16-1-Value.patch | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/llvm/clang16-1-Value.patch b/patches/llvm/clang16-1-Value.patch index 9d702ee8..ec74c35a 100644 --- a/patches/llvm/clang16-1-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -2082,3 +2082,4 @@ index d4900a0e4..330fd18ab 100644 + EXPECT_TRUE(V9.isManuallyAlloc()); +} } // end anonymous namespace + From 3217d08a0dd6de39a7fa72ebaaa0146473e6a0b7 Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Wed, 30 Aug 2023 07:18:21 +0300 Subject: [PATCH 7/8] Update clang16-1-Value.patch From 02ee00dcd79fead4c3c7abda451e0f00957cef03 Mon Sep 17 00:00:00 2001 From: Alexander Penev <7923188+alexander-penev@users.noreply.github.com> Date: Wed, 30 Aug 2023 07:57:31 +0300 Subject: [PATCH 8/8] Update clang16-1-Value.patch --- patches/llvm/clang16-1-Value.patch | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/llvm/clang16-1-Value.patch b/patches/llvm/clang16-1-Value.patch index ec74c35a..9d702ee8 100644 --- a/patches/llvm/clang16-1-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -2082,4 +2082,3 @@ index d4900a0e4..330fd18ab 100644 + EXPECT_TRUE(V9.isManuallyAlloc()); +} } // end anonymous namespace -