Author: Vassil Vassilev Date: 2021-05-13T04:44:19Z New Revision: f6907152db3d70606817ffe28274c6a90b331bbc
URL: https://github.com/llvm/llvm-project/commit/f6907152db3d70606817ffe28274c6a90b331bbc DIFF: https://github.com/llvm/llvm-project/commit/f6907152db3d70606817ffe28274c6a90b331bbc.diff LOG: Revert "[clang-repl] Land initial infrastructure for incremental parsing" This reverts commit 44a4000181e1a25027e87f2ae4e71cb876a7a275. We are seeing build failures due to missing dependency to libSupport and CMake Error at tools/clang/tools/clang-repl/cmake_install.cmake file INSTALL cannot find Added: clang/unittests/CodeGen/IncrementalProcessingTest.cpp Modified: clang/include/clang/CodeGen/CodeGenAction.h clang/include/clang/Frontend/FrontendAction.h clang/lib/CMakeLists.txt clang/lib/CodeGen/CodeGenAction.cpp clang/lib/Frontend/FrontendAction.cpp clang/test/CMakeLists.txt clang/test/lit.cfg.py clang/tools/CMakeLists.txt clang/unittests/CMakeLists.txt clang/unittests/CodeGen/CMakeLists.txt Removed: clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Interpreter/Transaction.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/IncrementalExecutor.cpp clang/lib/Interpreter/IncrementalExecutor.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/test/Interpreter/execute.cpp clang/test/Interpreter/sanity.c clang/tools/clang-repl/CMakeLists.txt clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/IncrementalProcessingTest.cpp clang/unittests/Interpreter/InterpreterTest.cpp ################################################################################ diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index b5721344046d..1db904ea974c 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -19,7 +19,6 @@ namespace llvm { namespace clang { class BackendConsumer; -class CodeGenerator; class CodeGenAction : public ASTFrontendAction { private: @@ -78,8 +77,6 @@ class CodeGenAction : public ASTFrontendAction { /// Take the LLVM context used by this action. llvm::LLVMContext *takeLLVMContext(); - CodeGenerator *getCodeGenerator() const; - BackendConsumer *BEConsumer; }; diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h index dfefddfb4527..319b3bc62cc4 100644 --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -234,7 +234,7 @@ class FrontendAction { /// Perform any per-file post processing, deallocate per-file /// objects, and run statistics and output file cleanup code. - virtual void EndSourceFile(); + void EndSourceFile(); /// @} }; @@ -302,16 +302,15 @@ class PreprocessorFrontendAction : public FrontendAction { /// some existing action's behavior. It implements every virtual method in /// the FrontendAction interface by forwarding to the wrapped action. class WrapperFrontendAction : public FrontendAction { -protected: std::unique_ptr<FrontendAction> WrappedAction; +protected: bool PrepareToExecuteAction(CompilerInstance &CI) override; std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; bool BeginInvocation(CompilerInstance &CI) override; bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; - void EndSourceFile() override; void EndSourceFileAction() override; bool shouldEraseOutputFiles() override; diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h deleted file mode 100644 index d4dd8731da18..000000000000 --- a/clang/include/clang/Interpreter/Interpreter.h +++ /dev/null @@ -1,71 +0,0 @@ -//===--- Interpreter.h - Incremental Compilation and Execution---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the component which performs incremental code -// compilation and execution. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H -#define LLVM_CLANG_INTERPRETER_INTERPRETER_H - -#include "clang/Interpreter/Transaction.h" - -#include "llvm/Support/Error.h" - -#include <memory> -#include <vector> - -namespace llvm { -namespace orc { -class ThreadSafeContext; -} -class Module; -} // namespace llvm - -namespace clang { - -class CompilerInstance; -class DeclGroupRef; -class IncrementalExecutor; -class IncrementalParser; - -/// Create a pre-configured \c CompilerInstance for incremental processing. -class IncrementalCompilerBuilder { -public: - static llvm::Expected<std::unique_ptr<CompilerInstance>> - create(std::vector<const char *> &ClangArgv); -}; - -/// Provides top-level interfaces for incremental compilation and execution. -class Interpreter { - std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx; - std::unique_ptr<IncrementalParser> IncrParser; - std::unique_ptr<IncrementalExecutor> IncrExecutor; - - Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err); - -public: - ~Interpreter(); - static llvm::Expected<std::unique_ptr<Interpreter>> - create(std::unique_ptr<CompilerInstance> CI); - const CompilerInstance *getCompilerInstance() const; - llvm::Expected<Transaction &> Parse(llvm::StringRef Code); - llvm::Error Execute(Transaction &T); - llvm::Error ParseAndExecute(llvm::StringRef Code) { - auto ErrOrTransaction = Parse(Code); - if (auto Err = ErrOrTransaction.takeError()) - return Err; - if (ErrOrTransaction->TheModule) - return Execute(*ErrOrTransaction); - return llvm::Error::success(); - } -}; -} // namespace clang - -#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H diff --git a/clang/include/clang/Interpreter/Transaction.h b/clang/include/clang/Interpreter/Transaction.h deleted file mode 100644 index 15639d4af0f9..000000000000 --- a/clang/include/clang/Interpreter/Transaction.h +++ /dev/null @@ -1,39 +0,0 @@ -//===--- Transaction.h - Incremental Compilation and Execution---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines utilities tracking the incrementally processed pieces of -// code. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_INTERPRETER_TRANSACTION_H -#define LLVM_CLANG_INTERPRETER_TRANSACTION_H - -#include <memory> -#include <vector> - -namespace llvm { -class Module; -} - -namespace clang { - -class DeclGroupRef; - -/// The class keeps track of various objects created as part of processing -/// incremental inputs. -struct Transaction { - /// The decls created for the input. - std::vector<clang::DeclGroupRef> Decls; - - /// The llvm IR produced for the input. - std::unique_ptr<llvm::Module> TheModule; -}; -} // namespace clang - -#endif // LLVM_CLANG_INTERPRETER_TRANSACTION_H diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt index 2b49fb9e96f0..be09c0c351f3 100644 --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -25,4 +25,3 @@ add_subdirectory(IndexSerialization) add_subdirectory(StaticAnalyzer) add_subdirectory(Format) add_subdirectory(Testing) -add_subdirectory(Interpreter) diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 02dcea286505..d33a4797430b 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -885,10 +885,6 @@ llvm::LLVMContext *CodeGenAction::takeLLVMContext() { return VMContext; } -CodeGenerator *CodeGenAction::getCodeGenerator() const { - return BEConsumer->getCodeGenerator(); -} - static std::unique_ptr<raw_pwrite_stream> GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) { switch (Action) { diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 7ff4812c6800..11b25b106627 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -1087,7 +1087,6 @@ bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) { void WrapperFrontendAction::ExecuteAction() { WrappedAction->ExecuteAction(); } -void WrapperFrontendAction::EndSourceFile() { WrappedAction->EndSourceFile(); } void WrapperFrontendAction::EndSourceFileAction() { WrappedAction->EndSourceFileAction(); } diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt deleted file mode 100644 index e7dadba1affb..000000000000 --- a/clang/lib/Interpreter/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -set(LLVM_LINK_COMPONENTS - core - native - OrcJit - Target - ) - -add_clang_library(clangInterpreter - IncrementalExecutor.cpp - IncrementalParser.cpp - Interpreter.cpp - - LINK_LIBS - clangAST - clangAnalysis - clangBasic - clangEdit - clangLex - clangSema - clangCodeGen - clangFrontendTool - ) diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp deleted file mode 100644 index f999e5eceaed..000000000000 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//===--- IncrementalExecutor.cpp - Incremental Execution --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the class which performs incremental code execution. -// -//===----------------------------------------------------------------------===// - -#include "IncrementalExecutor.h" - -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LLJIT.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/TargetSelect.h" - -namespace clang { - -IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, - llvm::Error &Err) - : TSCtx(TSC) { - using namespace llvm::orc; - llvm::ErrorAsOutParameter EAO(&Err); - - if (auto JitOrErr = LLJITBuilder().create()) - Jit = std::move(*JitOrErr); - else { - Err = JitOrErr.takeError(); - return; - } - - const char Pref = Jit->getDataLayout().getGlobalPrefix(); - // Discover symbols from the process as a fallback. - if (auto PSGOrErr = DynamicLibrarySearchGenerator::GetForCurrentProcess(Pref)) - Jit->getMainJITDylib().addGenerator(std::move(*PSGOrErr)); - else { - Err = PSGOrErr.takeError(); - return; - } -} - -IncrementalExecutor::~IncrementalExecutor() {} - -llvm::Error IncrementalExecutor::addModule(std::unique_ptr<llvm::Module> M) { - return Jit->addIRModule(llvm::orc::ThreadSafeModule(std::move(M), TSCtx)); -} - -llvm::Error IncrementalExecutor::runCtors() const { - return Jit->initialize(Jit->getMainJITDylib()); -} - -} // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h deleted file mode 100644 index c4e33a390942..000000000000 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ /dev/null @@ -1,46 +0,0 @@ -//===--- IncrementalExecutor.h - Incremental Execution ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the class which performs incremental code execution. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H -#define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" - -#include <memory> - -namespace llvm { -class Error; -class Module; -namespace orc { -class LLJIT; -class ThreadSafeContext; -} // namespace orc -} // namespace llvm - -namespace clang { -class IncrementalExecutor { - using CtorDtorIterator = llvm::orc::CtorDtorIterator; - std::unique_ptr<llvm::orc::LLJIT> Jit; - llvm::orc::ThreadSafeContext &TSCtx; - -public: - IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err); - ~IncrementalExecutor(); - - llvm::Error addModule(std::unique_ptr<llvm::Module> M); - llvm::Error runCtors() const; -}; - -} // end namespace clang - -#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp deleted file mode 100644 index 70baabfeb8fb..000000000000 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ /dev/null @@ -1,254 +0,0 @@ -//===--------- IncrementalParser.cpp - Incremental Compilation -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the class which performs incremental code compilation. -// -//===----------------------------------------------------------------------===// - -#include "IncrementalParser.h" - -#include "clang/CodeGen/BackendUtil.h" -#include "clang/CodeGen/CodeGenAction.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendAction.h" -#include "clang/FrontendTool/Utils.h" -#include "clang/Parse/Parser.h" -#include "clang/Sema/Sema.h" - -#include "llvm/Option/ArgList.h" -#include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Timer.h" - -#include <sstream> - -namespace clang { - -/// A custom action enabling the incremental processing functionality. -/// -/// The usual \p FrontendAction expects one call to ExecuteAction and once it -/// sees a call to \p EndSourceFile it deletes some of the important objects -/// such as \p Preprocessor and \p Sema assuming no further input will come. -/// -/// \p IncrementalAction ensures it keep its underlying action's objects alive -/// as long as the \p IncrementalParser needs them. -/// -class IncrementalAction : public WrapperFrontendAction { -private: - bool IsTerminating = false; - -public: - IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, - llvm::Error &Err) - : WrapperFrontendAction([&]() { - llvm::ErrorAsOutParameter EAO(&Err); - std::unique_ptr<FrontendAction> Act; - switch (CI.getFrontendOpts().ProgramAction) { - default: - Err = llvm::createStringError( - std::errc::state_not_recoverable, - "Driver initialization failed. " - "Incremental mode for action is not supported"); - return Act; - case frontend::ASTDump: - LLVM_FALLTHROUGH; - case frontend::ASTPrint: - LLVM_FALLTHROUGH; - case frontend::ParseSyntaxOnly: - Act = CreateFrontendAction(CI); - break; - case frontend::EmitObj: - LLVM_FALLTHROUGH; - case frontend::EmitLLVMOnly: - Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); - break; - } - return Act; - }()) {} - FrontendAction *getWrapped() const { return WrappedAction.get(); } - void ExecuteAction() override { - CompilerInstance &CI = getCompilerInstance(); - assert(CI.hasPreprocessor() && "No PP!"); - - // FIXME: Move the truncation aspect of this into Sema, we delayed this till - // here so the source manager would be initialized. - if (hasCodeCompletionSupport() && - !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) - CI.createCodeCompletionConsumer(); - - // Use a code completion consumer? - CodeCompleteConsumer *CompletionConsumer = nullptr; - if (CI.hasCodeCompletionConsumer()) - CompletionConsumer = &CI.getCodeCompletionConsumer(); - - Preprocessor &PP = CI.getPreprocessor(); - PP.enableIncrementalProcessing(); - PP.EnterMainSourceFile(); - - if (!CI.hasSema()) - CI.createSema(getTranslationUnitKind(), CompletionConsumer); - } - - // Do not terminate after processing the input. This allows us to keep various - // clang objects alive and to incrementally grow the current TU. - void EndSourceFile() override { - // The WrappedAction can be nullptr if we issued an error in the ctor. - if (IsTerminating && getWrapped()) - WrapperFrontendAction::EndSourceFile(); - } - - void FinalizeAction() { - assert(!IsTerminating && "Already finalized!"); - IsTerminating = true; - EndSourceFile(); - } -}; - -IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance, - llvm::LLVMContext &LLVMCtx, - llvm::Error &Err) - : CI(std::move(Instance)) { - llvm::ErrorAsOutParameter EAO(&Err); - Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err); - if (Err) - return; - CI->ExecuteAction(*Act); - Consumer = &CI->getASTConsumer(); - P.reset( - new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); - P->Initialize(); -} - -IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); } - -llvm::Expected<Transaction &> IncrementalParser::ParseOrWrapTopLevelDecl() { - DiagnosticsEngine &Diags = getCI()->getDiagnostics(); - - if (Diags.hasErrorOccurred()) - llvm::report_fatal_error("Previous input had errors, " - "recovery not yet supported", - /*GenCrashDiag=*/false); - - // Recover resources if we crash before exiting this method. - Sema &S = CI->getSema(); - llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); - Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); - Sema::LocalEagerInstantiationScope LocalInstantiations(S); - - // Skip previous eof due to last incremental input. - if (P->getCurToken().is(tok::eof)) - P->ConsumeToken(); - - Transactions.emplace_back(Transaction()); - Transaction &LastTransaction = Transactions.back(); - - Parser::DeclGroupPtrTy ADecl; - for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF; - AtEOF = P->ParseTopLevelDecl(ADecl)) { - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) - return llvm::make_error<llvm::StringError>("Parsing failed. " - "The consumer rejected a decl", - std::error_code()); - LastTransaction.Decls.push_back(ADecl.get()); - } - - // Process any TopLevelDecls generated by #pragma weak. - for (Decl *D : S.WeakTopLevelDecls()) { - DeclGroupRef DGR(D); - LastTransaction.Decls.push_back(DGR); - Consumer->HandleTopLevelDecl(DGR); - } - - LocalInstantiations.perform(); - GlobalInstantiations.perform(); - - Consumer->HandleTranslationUnit(S.getASTContext()); - - if (Diags.hasErrorOccurred()) - return llvm::make_error<llvm::StringError>("Parsing failed.", - std::error_code()); - - return LastTransaction; -} - -static CodeGenerator *getCodeGen(FrontendAction *Act) { - IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act); - FrontendAction *WrappedAct = IncrAct->getWrapped(); - if (!WrappedAct->hasIRSupport()) - return nullptr; - return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); -} - -llvm::Expected<Transaction &> IncrementalParser::Parse(llvm::StringRef input) { - Preprocessor &PP = CI->getPreprocessor(); - assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); - - std::ostringstream SourceName; - SourceName << "input_line_" << InputCount++; - - // Create an uninitialized memory buffer, copy code in and append "\n" - size_t InputSize = input.size(); // don't include trailing 0 - // MemBuffer size should *not* include terminating zero - std::unique_ptr<llvm::MemoryBuffer> MB( - llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, - SourceName.str())); - char *MBStart = const_cast<char *>(MB->getBufferStart()); - memcpy(MBStart, input.data(), InputSize); - MBStart[InputSize] = '\n'; - - SourceManager &SM = CI->getSourceManager(); - - // FIXME: Create SourceLocation, which will allow clang to order the overload - // candidates for example - SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); - - // Create FileID for the current buffer. - FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, - /*LoadedOffset=*/0, NewLoc); - - // NewLoc only used for diags. - if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc)) - return llvm::make_error<llvm::StringError>("Parsing failed. " - "Cannot enter source file.", - std::error_code()); - - auto ErrOrTransaction = ParseOrWrapTopLevelDecl(); - if (auto Err = ErrOrTransaction.takeError()) - return std::move(Err); - - if (PP.getLangOpts().DelayedTemplateParsing) { - // Microsoft-specific: - // Late parsed templates can leave unswallowed "macro"-like tokens. - // They will seriously confuse the Parser when entering the next - // source file. So lex until we are EOF. - Token Tok; - do { - PP.Lex(Tok); - } while (Tok.isNot(tok::eof)); - } - - Token AssertTok; - PP.Lex(AssertTok); - assert(AssertTok.is(tok::eof) && - "Lexer must be EOF when starting incremental parse!"); - - if (CodeGenerator *CG = getCodeGen(Act.get())) { - std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); - CG->StartModule("incr_module_" + std::to_string(Transactions.size()), - M->getContext()); - - ErrOrTransaction->TheModule = std::move(M); - } - - return ErrOrTransaction; -} -} // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h deleted file mode 100644 index 2ebc64e5930e..000000000000 --- a/clang/lib/Interpreter/IncrementalParser.h +++ /dev/null @@ -1,77 +0,0 @@ -//===--- IncrementalParser.h - Incremental Compilation ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the class which performs incremental code compilation. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H -#define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H - -#include "clang/Interpreter/Transaction.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" - -#include <list> -#include <memory> -namespace llvm { -class LLVMContext; -} - -namespace clang { -class ASTConsumer; -class CompilerInstance; -class CodeGenerator; -class DeclGroupRef; -class FrontendAction; -class IncrementalAction; -class Parser; - -/// Provides support for incremental compilation. Keeps track of the state -/// changes between the subsequent incremental input. -/// -class IncrementalParser { - /// Long-lived, incremental parsing action. - std::unique_ptr<IncrementalAction> Act; - - /// Compiler instance performing the incremental compilation. - std::unique_ptr<CompilerInstance> CI; - - /// Parser. - std::unique_ptr<Parser> P; - - /// Consumer to process the produced top level decls. Owned by Act. - ASTConsumer *Consumer = nullptr; - - /// Counts the number of direct user input lines that have been parsed. - unsigned InputCount = 0; - - /// List containing every information about every incrementally parsed piece - /// of code. - std::list<Transaction> Transactions; - -public: - IncrementalParser(std::unique_ptr<CompilerInstance> Instance, - llvm::LLVMContext &LLVMCtx, llvm::Error &Err); - ~IncrementalParser(); - - const CompilerInstance *getCI() const { return CI.get(); } - - /// Parses incremental input by creating an in-memory file. - ///\returns a \c Transaction which holds information about the \c Decls and - /// \c llvm::Module corresponding to the input. - llvm::Expected<Transaction &> Parse(llvm::StringRef Input); - -private: - llvm::Expected<Transaction &> ParseOrWrapTopLevelDecl(); -}; -} // end namespace clang - -#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp deleted file mode 100644 index 8de38c0afcd9..000000000000 --- a/clang/lib/Interpreter/Interpreter.cpp +++ /dev/null @@ -1,220 +0,0 @@ -//===------ Interpreter.cpp - Incremental Compilation and Execution -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the component which performs incremental code -// compilation and execution. -// -//===----------------------------------------------------------------------===// - -#include "clang/Interpreter/Interpreter.h" - -#include "IncrementalExecutor.h" -#include "IncrementalParser.h" - -#include "clang/Basic/TargetInfo.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Job.h" -#include "clang/Driver/Options.h" -#include "clang/Driver/Tool.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Lex/PreprocessorOptions.h" - -#include "llvm/IR/Module.h" -#include "llvm/Support/Host.h" - -using namespace clang; - -// FIXME: Figure out how to unify with namespace init_convenience from -// tools/clang-import-test/clang-import-test.cpp and -// examples/clang-interpreter/main.cpp -namespace { -/// Retrieves the clang CC1 specific flags out of the compilation's jobs. -/// \returns NULL on error. -static llvm::Expected<const llvm::opt::ArgStringList *> -GetCC1Arguments(DiagnosticsEngine *Diagnostics, - driver::Compilation *Compilation) { - // We expect to get back exactly one Command job, if we didn't something - // failed. Extract that job from the Compilation. - const driver::JobList &Jobs = Compilation->getJobs(); - if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin())) - return llvm::createStringError(std::errc::state_not_recoverable, - "Driver initialization failed. " - "Unable to create a driver job"); - - // The one job we find should be to invoke clang again. - const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin())); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") - return llvm::createStringError(std::errc::state_not_recoverable, - "Driver initialization failed"); - - return &Cmd->getArguments(); -} - -static llvm::Expected<std::unique_ptr<CompilerInstance>> -CreateCI(const llvm::opt::ArgStringList &Argv) { - std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - - // Register the support for object-file-wrapped Clang modules. - // FIXME: Clang should register these container operations automatically. - auto PCHOps = Clang->getPCHContainerOperations(); - PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>()); - PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>()); - - // Buffer diagnostics from argument parsing so that we can output them using - // a well formed diagnostic object. - IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); - TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; - DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); - bool Success = CompilerInvocation::CreateFromArgs( - Clang->getInvocation(), llvm::makeArrayRef(Argv.begin(), Argv.size()), - Diags); - - // Infer the builtin include path if unspecified. - if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && - Clang->getHeaderSearchOpts().ResourceDir.empty()) - Clang->getHeaderSearchOpts().ResourceDir = - CompilerInvocation::GetResourcesPath(Argv[0], nullptr); - - // Create the actual diagnostics engine. - Clang->createDiagnostics(); - if (!Clang->hasDiagnostics()) - return llvm::createStringError(std::errc::state_not_recoverable, - "Initialization failed. " - "Unable to create diagnostics engine"); - - DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); - if (!Success) - return llvm::createStringError(std::errc::state_not_recoverable, - "Initialization failed. " - "Unable to flush diagnostics"); - - // FIXME: Merge with CompilerInstance::ExecuteAction. - llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release(); - Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB); - - Clang->setTarget(TargetInfo::CreateTargetInfo( - Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); - if (!Clang->hasTarget()) - return llvm::createStringError(std::errc::state_not_recoverable, - "Initialization failed. " - "Target is missing"); - - Clang->getTarget().adjust(Clang->getLangOpts()); - - return std::move(Clang); -} - -} // anonymous namespace - -llvm::Expected<std::unique_ptr<CompilerInstance>> -IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) { - - // If we don't know ClangArgv0 or the address of main() at this point, try - // to guess it anyway (it's possible on some platforms). - std::string MainExecutableName = - llvm::sys::fs::getMainExecutable(nullptr, nullptr); - - ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str()); - - // Prepending -c to force the driver to do something if no action was - // specified. By prepending we allow users to override the default - // action and use other actions in incremental mode. - // FIXME: Print proper driver diagnostics if the driver flags are wrong. - ClangArgv.insert(ClangArgv.begin() + 1, "-c"); - - if (!llvm::is_contained(ClangArgv, " -x")) { - // We do C++ by default; append right after argv[0] if no "-x" given - ClangArgv.push_back("-x"); - ClangArgv.push_back("c++"); - } - - // Put a dummy C++ file on to ensure there's at least one compile job for the - // driver to construct. - ClangArgv.push_back("<<< inputs >>>"); - - CompilerInvocation Invocation; - // Buffer diagnostics from argument parsing so that we can output them using a - // well formed diagnostic object. - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); - TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; - DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); - unsigned MissingArgIndex, MissingArgCount; - const llvm::opt::OptTable &Opts = driver::getDriverOptTable(); - llvm::opt::InputArgList ParsedArgs = - Opts.ParseArgs(ArrayRef<const char *>(ClangArgv).slice(1), - MissingArgIndex, MissingArgCount); - ParseDiagnosticArgs(*DiagOpts, ParsedArgs, &Diags); - - driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], - llvm::sys::getDefaultTargetTriple(), Diags); - Driver.setCheckInputsExist(false); // the input comes from mem buffers - llvm::ArrayRef<const char *> RF = llvm::makeArrayRef(ClangArgv); - std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF)); - - if (Compilation->getArgs().hasArg(driver::options::OPT_v)) - Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false); - - auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get()); - if (auto Err = ErrOrCC1Args.takeError()) - return std::move(Err); - - return CreateCI(**ErrOrCC1Args); -} - -Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI, - llvm::Error &Err) { - llvm::ErrorAsOutParameter EAO(&Err); - auto LLVMCtx = std::make_unique<llvm::LLVMContext>(); - TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx)); - IncrParser = std::make_unique<IncrementalParser>(std::move(CI), - *TSCtx->getContext(), Err); -} - -Interpreter::~Interpreter() {} - -llvm::Expected<std::unique_ptr<Interpreter>> -Interpreter::create(std::unique_ptr<CompilerInstance> CI) { - llvm::Error Err = llvm::Error::success(); - auto Interp = - std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err)); - if (Err) - return std::move(Err); - return std::move(Interp); -} - -const CompilerInstance *Interpreter::getCompilerInstance() const { - return IncrParser->getCI(); -} - -llvm::Expected<Transaction &> Interpreter::Parse(llvm::StringRef Code) { - return IncrParser->Parse(Code); -} - -llvm::Error Interpreter::Execute(Transaction &T) { - assert(T.TheModule); - if (!IncrExecutor) { - llvm::Error Err = llvm::Error::success(); - IncrExecutor = std::make_unique<IncrementalExecutor>(*TSCtx, Err); - if (Err) - return Err; - } - // FIXME: Add a callback to retain the llvm::Module once the JIT is done. - if (auto Err = IncrExecutor->addModule(std::move(T.TheModule))) - return Err; - - if (auto Err = IncrExecutor->runCtors()) - return Err; - - return llvm::Error::success(); -} diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index 8e3460f75c37..f87b32a97fa6 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -68,7 +68,6 @@ list(APPEND CLANG_TEST_DEPS clang-import-test clang-rename clang-refactor - clang-repl clang- diff clang-scan-deps diagtool diff --git a/clang/test/Interpreter/execute.cpp b/clang/test/Interpreter/execute.cpp deleted file mode 100644 index 81ab57e955cf..000000000000 --- a/clang/test/Interpreter/execute.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: cat %s | clang-repl | FileCheck %s -// REQUIRES: host-supports-jit - -extern "C" int printf(const char *, ...); -int i = 42; -auto r1 = printf("i = %d\n", i); -// CHECK: i = 42 - -struct S { float f = 1.0; S *m = nullptr;} s; - -auto r2 = printf("S[f=%f, m=0x%llx]\n", s.f, reinterpret_cast<unsigned long long>(s.m)); -// CHECK-NEXT: S[f=1.000000, m=0x0] - -quit diff --git a/clang/test/Interpreter/sanity.c b/clang/test/Interpreter/sanity.c deleted file mode 100644 index f77faaf6748b..000000000000 --- a/clang/test/Interpreter/sanity.c +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: cat %s | \ -// RUN: clang-repl -Xcc -fno-color-diagnostics -Xcc -Xclang -Xcc -ast-dump \ -// RUN: -Xcc -Xclang -Xcc -ast-dump-filter -Xcc -Xclang -Xcc Test 2>&1| \ -// RUN: FileCheck %s - -int TestVar = 12; -// CHECK: Dumping TestVar: -// CHECK-NEXT: VarDecl [[var_ptr:0x[0-9a-f]+]] <{{.*}} TestVar 'int' cinit -// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 12 - -void TestFunc() { ++TestVar; } -// CHECK: Dumping TestFunc: -// CHECK-NEXT: FunctionDecl {{.*}} TestFunc 'void ()' -// CHECK-NEXT: CompoundStmt{{.*}} -// CHECK-NEXT: UnaryOperator{{.*}} 'int' lvalue prefix '++' -// CHECK-NEXT: DeclRefExpr{{.*}} 'int' lvalue Var [[var_ptr]] 'TestVar' 'int' - -quit diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index c872b6aab847..7411e8716943 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -63,7 +63,7 @@ tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] tools = [ - 'apinotes-test', 'c-index-test', 'clang- diff ', 'clang-format', 'clang-repl', + 'apinotes-test', 'c-index-test', 'clang- diff ', 'clang-format', 'clang-tblgen', 'opt', 'llvm-ifs', 'yaml2obj', ToolSubst('%clang_extdef_map', command=FindTool( 'clang-extdef-mapping'), unresolved='ignore'), @@ -73,28 +73,6 @@ config.available_features.add('examples') tools.append('clang-interpreter') -def have_host_jit_support(): - clang_repl_exe = lit.util.which('clang-repl', config.clang_tools_dir) - - if not clang_repl_exe: - print('clang-repl not found') - return False - - try: - clang_repl_cmd = subprocess.Popen( - [clang_repl_exe, '--host-supports-jit'], stdout=subprocess.PIPE) - except OSError: - print('could not exec clang-repl') - return False - - clang_repl_out = clang_repl_cmd.stdout.read().decode('ascii') - clang_repl_cmd.wait() - - return 'true' in clang_repl_out - -if have_host_jit_support(): - config.available_features.add('host-supports-jit') - if config.clang_staticanalyzer: config.available_features.add('staticanalyzer') tools.append('clang-check') diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt index 63fe79eccf73..32359178066c 100644 --- a/clang/tools/CMakeLists.txt +++ b/clang/tools/CMakeLists.txt @@ -11,7 +11,6 @@ add_clang_subdirectory(clang-import-test) add_clang_subdirectory(clang-offload-bundler) add_clang_subdirectory(clang-offload-wrapper) add_clang_subdirectory(clang-scan-deps) -add_clang_subdirectory(clang-repl) add_clang_subdirectory(c-index-test) diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt deleted file mode 100644 index 558ac4837f9a..000000000000 --- a/clang/tools/clang-repl/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set( LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} - Option - Support - ) - -add_clang_executable(clang-repl - EXCLUDE_FROM_ALL - ClangRepl.cpp - ) - -target_link_libraries(clang-repl PUBLIC - clangInterpreter - clangTooling - LLVMLineEditor - ) - -install(TARGETS clang-repl - RUNTIME DESTINATION bin) diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp deleted file mode 100644 index b5b5bf6e0c6b..000000000000 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===--- tools/clang-repl/ClangRepl.cpp - clang-repl - the Clang REPL -----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements a REPL tool on top of clang. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/Diagnostic.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Interpreter/Interpreter.h" - -#include "llvm/ExecutionEngine/Orc/LLJIT.h" -#include "llvm/LineEditor/LineEditor.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ManagedStatic.h" // llvm_shutdown -#include "llvm/Support/Signals.h" -#include "llvm/Support/TargetSelect.h" // llvm::Initialize* - -static llvm::cl::list<std::string> - ClangArgs("Xcc", llvm::cl::ZeroOrMore, - llvm::cl::desc("Argument to pass to the CompilerInvocation"), - llvm::cl::CommaSeparated); -static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit", - llvm::cl::Hidden); - -static void LLVMErrorHandler(void *UserData, const std::string &Message, - bool GenCrashDiag) { - auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData); - - Diags.Report(clang::diag::err_fe_error_backend) << Message; - - // Run the interrupt handlers to make sure any special cleanups get done, in - // particular that we remove files registered with RemoveFileOnSignal. - llvm::sys::RunInterruptHandlers(); - - // We cannot recover from llvm errors. When reporting a fatal error, exit - // with status 70 to generate crash diagnostics. For BSD systems this is - // defined as an internal software error. Otherwise, exit with status 1. - - exit(GenCrashDiag ? 70 : 1); -} - -llvm::ExitOnError ExitOnErr; -int main(int argc, const char **argv) { - ExitOnErr.setBanner("clang-repl: "); - llvm::cl::ParseCommandLineOptions(argc, argv); - - std::vector<const char *> ClangArgv(ClangArgs.size()); - std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), - [](const std::string &s) -> const char * { return s.data(); }); - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - if (OptHostSupportsJit) { - auto J = llvm::orc::LLJITBuilder().create(); - if (J) - llvm::outs() << "true\n"; - else { - llvm::consumeError(J.takeError()); - llvm::outs() << "false\n"; - } - return 0; - } - - // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It - // can replace the boilerplate code for creation of the compiler instance. - auto CI = ExitOnErr(clang::IncrementalCompilerBuilder::create(ClangArgv)); - - // Set an error handler, so that any LLVM backend diagnostics go through our - // error handler. - llvm::install_fatal_error_handler(LLVMErrorHandler, - static_cast<void *>(&CI->getDiagnostics())); - - auto Interp = ExitOnErr(clang::Interpreter::create(std::move(CI))); - llvm::LineEditor LE("clang-repl"); - // FIXME: Add LE.setListCompleter - while (llvm::Optional<std::string> Line = LE.readLine()) { - if (*Line == "quit") - break; - if (auto Err = Interp->ParseAndExecute(*Line)) - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); - } - - // Our error handler depends on the Diagnostics object, which we're - // potentially about to delete. Uninstall the handler now so that any - // later errors use the default handling behavior instead. - llvm::remove_fatal_error_handler(); - - llvm::llvm_shutdown(); - - return 0; -} diff --git a/clang/unittests/CMakeLists.txt b/clang/unittests/CMakeLists.txt index 51fe5de9ce64..4e0873955700 100644 --- a/clang/unittests/CMakeLists.txt +++ b/clang/unittests/CMakeLists.txt @@ -35,7 +35,6 @@ add_subdirectory(Frontend) add_subdirectory(Rewrite) add_subdirectory(Sema) add_subdirectory(CodeGen) -add_subdirectory(Interpreter) # FIXME: libclang unit tests are disabled on Windows due # to failures, mostly in libclang.VirtualFileOverlay_*. if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD) diff --git a/clang/unittests/CodeGen/CMakeLists.txt b/clang/unittests/CodeGen/CMakeLists.txt index a9a7b7a1cbaa..3fe547a65086 100644 --- a/clang/unittests/CodeGen/CMakeLists.txt +++ b/clang/unittests/CodeGen/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(ClangCodeGenTests BufferSourceTest.cpp CodeGenExternalTest.cpp + IncrementalProcessingTest.cpp TBAAMetadataTest.cpp CheckTargetFeaturesTest.cpp ) @@ -16,7 +17,6 @@ clang_target_link_libraries(ClangCodeGenTests clangBasic clangCodeGen clangFrontend - clangInterpreter clangLex clangParse clangSerialization diff --git a/clang/unittests/CodeGen/IncrementalProcessingTest.cpp b/clang/unittests/CodeGen/IncrementalProcessingTest.cpp new file mode 100644 index 000000000000..fed8ecd59f35 --- /dev/null +++ b/clang/unittests/CodeGen/IncrementalProcessingTest.cpp @@ -0,0 +1,155 @@ +//=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TestCompiler.h" + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include "gtest/gtest.h" + +#include <memory> + +using namespace llvm; +using namespace clang; + +namespace { + +// Incremental processing produces several modules, all using the same "main +// file". Make sure CodeGen can cope with that, e.g. for static initializers. +const char TestProgram1[] = + "extern \"C\" int funcForProg1() { return 17; }\n" + "struct EmitCXXGlobalInitFunc1 {\n" + " EmitCXXGlobalInitFunc1() {}\n" + "} test1;"; + +const char TestProgram2[] = + "extern \"C\" int funcForProg2() { return 42; }\n" + "struct EmitCXXGlobalInitFunc2 {\n" + " EmitCXXGlobalInitFunc2() {}\n" + "} test2;"; + + +/// An incremental version of ParseAST(). +static std::unique_ptr<llvm::Module> +IncrementalParseAST(CompilerInstance& CI, Parser& P, + CodeGenerator& CG, const char* code) { + static int counter = 0; + struct IncreaseCounterOnRet { + ~IncreaseCounterOnRet() { + ++counter; + } + } ICOR; + + Sema& S = CI.getSema(); + clang::SourceManager &SM = S.getSourceManager(); + if (!code) { + // Main file + SM.setMainFileID(SM.createFileID( + llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User)); + + S.getPreprocessor().EnterMainSourceFile(); + P.Initialize(); + } else { + FileID FID = SM.createFileID( + llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User); + SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter); + S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc); + } + + ExternalASTSource *External = S.getASTContext().getExternalSource(); + if (External) + External->StartTranslationUnit(&CG); + + Parser::DeclGroupPtrTy ADecl; + for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; + AtEOF = P.ParseTopLevelDecl(ADecl)) { + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl && !CG.HandleTopLevelDecl(ADecl.get())) + return nullptr; + } + + // Process any TopLevelDecls generated by #pragma weak. + for (Decl *D : S.WeakTopLevelDecls()) + CG.HandleTopLevelDecl(DeclGroupRef(D)); + + CG.HandleTranslationUnit(S.getASTContext()); + + std::unique_ptr<llvm::Module> M(CG.ReleaseModule()); + // Switch to next module. + CG.StartModule("incremental-module-" + std::to_string(counter), + M->getContext()); + return M; +} + +const Function* getGlobalInit(llvm::Module& M) { + for (const auto& Func: M) + if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_")) + return &Func; + + return nullptr; +} + +TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) { + clang::LangOptions LO; + LO.CPlusPlus = 1; + LO.CPlusPlus11 = 1; + TestCompiler Compiler(LO); + clang::CompilerInstance &CI = Compiler.compiler; + CI.getPreprocessor().enableIncrementalProcessing(); + CI.setASTConsumer(std::move(Compiler.CG)); + clang::CodeGenerator& CG = + static_cast<clang::CodeGenerator&>(CI.getASTConsumer()); + CI.createSema(clang::TU_Prefix, nullptr); + + Sema& S = CI.getSema(); + + std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S, + /*SkipFunctionBodies*/ false)); + Parser &P = *ParseOP.get(); + + std::array<std::unique_ptr<llvm::Module>, 3> M; + M[0] = IncrementalParseAST(CI, P, CG, nullptr); + ASSERT_TRUE(M[0]); + + M[1] = IncrementalParseAST(CI, P, CG, TestProgram1); + ASSERT_TRUE(M[1]); + ASSERT_TRUE(M[1]->getFunction("funcForProg1")); + + M[2] = IncrementalParseAST(CI, P, CG, TestProgram2); + ASSERT_TRUE(M[2]); + ASSERT_TRUE(M[2]->getFunction("funcForProg2")); + // First code should not end up in second module: + ASSERT_FALSE(M[2]->getFunction("funcForProg1")); + + // Make sure global inits exist and are unique: + const Function* GlobalInit1 = getGlobalInit(*M[1]); + ASSERT_TRUE(GlobalInit1); + + const Function* GlobalInit2 = getGlobalInit(*M[2]); + ASSERT_TRUE(GlobalInit2); + + ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName()); + +} + +} // end anonymous namespace diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt deleted file mode 100644 index b0def94382a6..000000000000 --- a/clang/unittests/Interpreter/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(LLVM_LINK_COMPONENTS - ) - -add_clang_unittest(ClangReplInterpreterTests - IncrementalProcessingTest.cpp - InterpreterTest.cpp - ) -target_link_libraries(ClangReplInterpreterTests PUBLIC - clangInterpreter - clangFrontend - ) diff --git a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp deleted file mode 100644 index 7d58d9837b8f..000000000000 --- a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp +++ /dev/null @@ -1,80 +0,0 @@ -//=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Interpreter/Interpreter.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Parser.h" -#include "clang/Sema/Sema.h" -#include "llvm/ADT/Triple.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" -#include "gtest/gtest.h" - -#include <memory> - -using namespace llvm; -using namespace clang; - -namespace { - -// Incremental processing produces several modules, all using the same "main -// file". Make sure CodeGen can cope with that, e.g. for static initializers. -const char TestProgram1[] = "extern \"C\" int funcForProg1() { return 17; }\n" - "struct EmitCXXGlobalInitFunc1 {\n" - " EmitCXXGlobalInitFunc1() {}\n" - "} test1;"; - -const char TestProgram2[] = "extern \"C\" int funcForProg2() { return 42; }\n" - "struct EmitCXXGlobalInitFunc2 {\n" - " EmitCXXGlobalInitFunc2() {}\n" - "} test2;"; - -const Function *getGlobalInit(llvm::Module *M) { - for (const auto &Func : *M) - if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_")) - return &Func; - - return nullptr; -} - -TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) { - std::vector<const char *> ClangArgv = {"-Xclang", "-emit-llvm-only"}; - auto CI = llvm::cantFail(IncrementalCompilerBuilder::create(ClangArgv)); - auto Interp = llvm::cantFail(Interpreter::create(std::move(CI))); - - std::array<clang::Transaction *, 2> Transactions; - - Transactions[0] = &llvm::cantFail(Interp->Parse(TestProgram1)); - ASSERT_TRUE(Transactions[0]->TheModule); - ASSERT_TRUE(Transactions[0]->TheModule->getFunction("funcForProg1")); - - Transactions[1] = &llvm::cantFail(Interp->Parse(TestProgram2)); - ASSERT_TRUE(Transactions[1]->TheModule); - ASSERT_TRUE(Transactions[1]->TheModule->getFunction("funcForProg2")); - // First code should not end up in second module: - ASSERT_FALSE(Transactions[1]->TheModule->getFunction("funcForProg1")); - - // Make sure global inits exist and are unique: - const Function *GlobalInit1 = getGlobalInit(Transactions[0]->TheModule.get()); - ASSERT_TRUE(GlobalInit1); - - const Function *GlobalInit2 = getGlobalInit(Transactions[1]->TheModule.get()); - ASSERT_TRUE(GlobalInit2); - - ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName()); -} - -} // end anonymous namespace diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp deleted file mode 100644 index 984255c0a229..000000000000 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ /dev/null @@ -1,122 +0,0 @@ -//===- unittests/Interpreter/InterpreterTest.cpp --- Interpreter tests ----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Unit tests for Clang's Interpreter library. -// -//===----------------------------------------------------------------------===// - -#include "clang/Interpreter/Interpreter.h" - -#include "clang/AST/Decl.h" -#include "clang/AST/DeclGroup.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" - -#include "llvm/ADT/ArrayRef.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using namespace clang; - -namespace { -using Args = std::vector<const char *>; -static std::unique_ptr<Interpreter> -createInterpreter(const Args &ExtraArgs = {}, - DiagnosticConsumer *Client = nullptr) { - Args ClangArgs = {"-Xclang", "-emit-llvm-only"}; - ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end()); - auto CI = cantFail(clang::IncrementalCompilerBuilder::create(ClangArgs)); - if (Client) - CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false); - return cantFail(clang::Interpreter::create(std::move(CI))); -} - -TEST(InterpreterTest, Sanity) { - std::unique_ptr<Interpreter> Interp = createInterpreter(); - Transaction &R1(cantFail(Interp->Parse("void g(); void g() {}"))); - EXPECT_EQ(2U, R1.Decls.size()); - - Transaction &R2(cantFail(Interp->Parse("int i;"))); - EXPECT_EQ(1U, R2.Decls.size()); -} - -static std::string DeclToString(DeclGroupRef DGR) { - return llvm::cast<NamedDecl>(DGR.getSingleDecl())->getQualifiedNameAsString(); -} - -TEST(InterpreterTest, IncrementalInputTopLevelDecls) { - std::unique_ptr<Interpreter> Interp = createInterpreter(); - auto R1OrErr = Interp->Parse("int var1 = 42; int f() { return var1; }"); - // gtest doesn't expand into explicit bool conversions. - EXPECT_TRUE(!!R1OrErr); - auto R1 = R1OrErr->Decls; - EXPECT_EQ(2U, R1.size()); - EXPECT_EQ("var1", DeclToString(R1[0])); - EXPECT_EQ("f", DeclToString(R1[1])); - - auto R2OrErr = Interp->Parse("int var2 = f();"); - EXPECT_TRUE(!!R2OrErr); - auto R2 = R2OrErr->Decls; - EXPECT_EQ(1U, R2.size()); - EXPECT_EQ("var2", DeclToString(R2[0])); -} - -TEST(InterpreterTest, Errors) { - Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; - - // Create the diagnostic engine with unowned consumer. - std::string DiagnosticOutput; - llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); - auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( - DiagnosticsOS, new DiagnosticOptions()); - - auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); - auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError(); - using ::testing::HasSubstr; - EXPECT_THAT(DiagnosticsOS.str(), - HasSubstr("error: unknown type name 'intentional_error'")); - EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); - -#ifdef GTEST_HAS_DEATH_TEST - EXPECT_DEATH((void)Interp->Parse("int var1 = 42;"), ""); -#endif -} - -// Here we test whether the user can mix declarations and statements. The -// interpreter should be smart enough to recognize the declarations from the -// statements and wrap the latter into a declaration, producing valid code. -TEST(InterpreterTest, DeclsAndStatements) { - Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; - - // Create the diagnostic engine with unowned consumer. - std::string DiagnosticOutput; - llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); - auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( - DiagnosticsOS, new DiagnosticOptions()); - - auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); - auto R1OrErr = Interp->Parse( - "int var1 = 42; extern \"C\" int printf(const char*, ...);"); - // gtest doesn't expand into explicit bool conversions. - EXPECT_TRUE(!!R1OrErr); - - auto R1 = R1OrErr->Decls; - EXPECT_EQ(2U, R1.size()); - - // FIXME: Add support for wrapping and running statements. - auto R2OrErr = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);"); - EXPECT_FALSE(!!R2OrErr); - using ::testing::HasSubstr; - EXPECT_THAT(DiagnosticsOS.str(), - HasSubstr("error: unknown type name 'var1'")); - auto Err = R2OrErr.takeError(); - EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); -} - -} // end anonymous namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits