diff --git a/patches/llvm/clang16-D141215-Value.patch b/patches/llvm/clang16-1-Value.patch similarity index 79% rename from patches/llvm/clang16-D141215-Value.patch rename to patches/llvm/clang16-1-Value.patch index 76762368..9d702ee8 100644 --- a/patches/llvm/clang16-D141215-Value.patch +++ b/patches/llvm/clang16-1-Value.patch @@ -1,13 +1,13 @@ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h -index 863f6ac57f2a..2e343405cfbe 100644 +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: @@ -18,19 +18,19 @@ index 863f6ac57f2a..2e343405cfbe 100644 + assert(IsSemiMissing && "Operation supported for printing values only!"); + Statement = S; + } -+ bool isValuePrinting() const { return IsSemiMissing; } -+ void setValuePrinting(bool Missing = true) { IsSemiMissing = Missing; } - ++ 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 96feae991ccb..7526298557a8 100644 +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) + @@ -38,20 +38,20 @@ index 96feae991ccb..7526298557a8 100644 #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 @@ #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" @@ -59,14 +59,26 @@ 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: @@ -91,29 +103,33 @@ index fd22af976613..020c2a88c185 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); -@@ -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 +139,8 @@ index fd22af976613..020c2a88c185 100644 + Expr *SynthesizeExpr(Expr *E); + +private: ++ size_t getEffectivePTUSize() const; ++ + bool FindRuntimeInterface(); + + llvm::DenseMap Dtors; @@ -130,14 +148,14 @@ index fd22af976613..020c2a88c185 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 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 +163,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 +254,7 @@ index 000000000000..f70eb214b3d5 + REPL_BUILTIN_TYPES +#undef X + -+ K_Void, ++ K_Void, + K_PtrOrObj, + K_Unspecified + }; @@ -238,6 +281,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 +290,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 +322,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,16 +349,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 +index 6f9581b9e..6b73f43a1 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -18,6 +18,7 @@ @@ -331,31 +377,10 @@ index 6f9581b9ea1f..6b73f43a1fb7 100644 + 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 +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, @@ -366,7 +391,7 @@ index ffa85e523c03..1b262d9e6f7c 100644 + !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. @@ -379,7 +404,7 @@ index ffa85e523c03..1b262d9e6f7c 100644 // 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 @@ -388,36 +413,44 @@ index c49f22fddd8e..565e824bf0c9 100644 Interpreter.cpp + InterpreterUtils.cpp + Value.cpp - + 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()); } - + -llvm::Expected +llvm::Expected 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,17 +458,18 @@ 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..e43189071 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// - + #include "IncrementalParser.h" - #include "clang/AST/DeclContextInternals.h" @@ -453,9 +487,9 @@ index 373e2844b4e4..259b9875e6be 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; @@ -472,7 +506,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); @@ -535,7 +569,7 @@ index 373e2844b4e4..259b9875e6be 100644 @@ -122,7 +194,8 @@ public: } }; - + -IncrementalParser::IncrementalParser(std::unique_ptr Instance, +IncrementalParser::IncrementalParser(Interpreter &Interp, + std::unique_ptr Instance, @@ -554,7 +588,7 @@ index 373e2844b4e4..259b9875e6be 100644 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(); @@ -563,52 +597,53 @@ index 373e2844b4e4..259b9875e6be 100644 // 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) { +@@ -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!"); } - - Token AssertTok; - PP.Lex(AssertTok); + +- Token AssertTok; +- PP.Lex(AssertTok); - assert(AssertTok.is(tok::eof) && -+ assert(AssertTok.is(tok::annot_repl_input_end) && - "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()), -- M->getContext()); -- +- "Lexer must be EOF when starting incremental parse!"); + if (std::unique_ptr M = GenModule()) - PTU->TheModule = std::move(M); -- } - - return PTU; - } - ++ 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 8e45d6b5931b..99e37588df9d 100644 +index 8e45d6b59..99e37588d 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ 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" @@ -626,31 +661,31 @@ index 8e45d6b5931b..99e37588df9d 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: 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 @@ #include "IncrementalExecutor.h" #include "IncrementalParser.h" - + +#include "InterpreterUtils.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Mangle.h" @@ -659,7 +694,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 +706,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)); @@ -686,17 +721,18 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + IncrParser = std::make_unique(*this, std::move(CI), *TSCtx->getContext(), Err); } - -@@ -189,6 +196,28 @@ Interpreter::~Interpreter() { + +@@ -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. +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 +752,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 @@ -730,11 +767,11 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + Interp->InitPTUSize = Interp->IncrParser->getPTUs().size(); 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(); } - + -const llvm::orc::LLJIT *Interpreter::getExecutionEngine() const { - if (IncrExecutor) - return IncrExecutor->getExecutionEngine(); @@ -761,7 +798,7 @@ index a6f5fdc6eefc..e8a07eceb678 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 @@ -770,7 +807,7 @@ index a6f5fdc6eefc..e8a07eceb678 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(); @@ -783,14 +820,21 @@ 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(); } - + -llvm::Expected +llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) { + @@ -818,7 +862,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 @@ -245,7 +332,7 @@ Interpreter::getSymbolAddress(GlobalDecl GD) const { return getSymbolAddress(MangledName); } - + -llvm::Expected +llvm::Expected Interpreter::getSymbolAddress(llvm::StringRef IRName) const { @@ -827,7 +871,7 @@ index a6f5fdc6eefc..e8a07eceb678 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 { @@ -835,18 +879,34 @@ index a6f5fdc6eefc..e8a07eceb678 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()) 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 +988,7 @@ index a6f5fdc6eefc..e8a07eceb678 100644 + E = EWC->getSubExpr(); + } + -+ExprResult getCall() { ++ ExprResult getCall() { + QualType Ty = E->getType(); + QualType DesugaredTy = Ty.getDesugaredType(Ctx); + @@ -1000,8 +1060,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 +1070,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 +1101,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 +1125,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 +1167,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 +1192,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 +1248,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 +1268,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 +1287,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 +1306,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 +1365,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 +1404,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 +1425,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 +1503,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 +1521,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 +1532,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()) { @@ -1593,7 +1696,7 @@ index 000000000000..34a77344bc86 + Out << "Not implement yet.\n"; +} diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp -index 66168467ecf5..0822f83b58df 100644 +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) { @@ -1615,11 +1718,11 @@ index 66168467ecf5..0822f83b58df 100644 + } 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 +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, @@ -1629,7 +1732,7 @@ index 3a7f5426d4a7..57a3dfba4f1d 100644 + 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: @@ -1637,9 +1740,9 @@ index 3a7f5426d4a7..57a3dfba4f1d 100644 + 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 +index e6812ac72..2f193a3b4 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2030,6 +2030,7 @@ void Parser::SkipMalformedDecl() { @@ -1648,54 +1751,54 @@ index e6812ac72c88..3e64e6f074fc 100644 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())->setValuePrinting(); ++ 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 1c8441fafc48..446fc7ea6385 100644 +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 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)) ++ // 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 (!R.isInvalid() && CurTok) ++ 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 6db3dc3156fd..9682f12ed211 100644 +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) { @@ -1706,39 +1809,95 @@ index 6db3dc3156fd..9682f12ed211 100644 // 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 +@@ -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(); -+ 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, + 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 +--- /dev/null ++++ b/clang/test/Interpreter/Inputs/dynamic-library-test.cpp +@@ -0,0 +1,6 @@ ++int ultimate_answer = 0; ++ ++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 ++ ++// 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 ++ ++#include ++ ++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 ) - + clang_target_link_libraries(clang-repl PRIVATE + clangAST 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 +1906,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 @@ @@ -1758,64 +1939,91 @@ index d4900a0e4de8..4e737a0b313a 100644 +#include "clang/Interpreter/Value.h" #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); - + - 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*,...);" "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 +2042,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 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