1 //===--- tools/clang-repl/ClangRepl.cpp - clang-repl - the Clang REPL -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a REPL tool on top of clang. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Basic/Diagnostic.h" 14 #include "clang/Frontend/CompilerInstance.h" 15 #include "clang/Frontend/FrontendDiagnostic.h" 16 #include "clang/Interpreter/Interpreter.h" 17 18 #include "llvm/ExecutionEngine/Orc/LLJIT.h" 19 #include "llvm/LineEditor/LineEditor.h" 20 #include "llvm/Support/CommandLine.h" 21 #include "llvm/Support/ManagedStatic.h" // llvm_shutdown 22 #include "llvm/Support/Signals.h" 23 #include "llvm/Support/TargetSelect.h" // llvm::Initialize* 24 25 static llvm::cl::list<std::string> 26 ClangArgs("Xcc", llvm::cl::ZeroOrMore, 27 llvm::cl::desc("Argument to pass to the CompilerInvocation"), 28 llvm::cl::CommaSeparated); 29 static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit", 30 llvm::cl::Hidden); 31 32 static void LLVMErrorHandler(void *UserData, const std::string &Message, 33 bool GenCrashDiag) { 34 auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData); 35 36 Diags.Report(clang::diag::err_fe_error_backend) << Message; 37 38 // Run the interrupt handlers to make sure any special cleanups get done, in 39 // particular that we remove files registered with RemoveFileOnSignal. 40 llvm::sys::RunInterruptHandlers(); 41 42 // We cannot recover from llvm errors. When reporting a fatal error, exit 43 // with status 70 to generate crash diagnostics. For BSD systems this is 44 // defined as an internal software error. Otherwise, exit with status 1. 45 46 exit(GenCrashDiag ? 70 : 1); 47 } 48 49 llvm::ExitOnError ExitOnErr; 50 int main(int argc, const char **argv) { 51 ExitOnErr.setBanner("clang-repl: "); 52 llvm::cl::ParseCommandLineOptions(argc, argv); 53 54 std::vector<const char *> ClangArgv(ClangArgs.size()); 55 std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), 56 [](const std::string &s) -> const char * { return s.data(); }); 57 llvm::InitializeNativeTarget(); 58 llvm::InitializeNativeTargetAsmPrinter(); 59 60 if (OptHostSupportsJit) { 61 auto J = llvm::orc::LLJITBuilder().create(); 62 if (J) 63 llvm::outs() << "true\n"; 64 else { 65 llvm::consumeError(J.takeError()); 66 llvm::outs() << "false\n"; 67 } 68 return 0; 69 } 70 71 // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It 72 // can replace the boilerplate code for creation of the compiler instance. 73 auto CI = ExitOnErr(clang::IncrementalCompilerBuilder::create(ClangArgv)); 74 75 // Set an error handler, so that any LLVM backend diagnostics go through our 76 // error handler. 77 llvm::install_fatal_error_handler(LLVMErrorHandler, 78 static_cast<void *>(&CI->getDiagnostics())); 79 80 auto Interp = ExitOnErr(clang::Interpreter::create(std::move(CI))); 81 llvm::LineEditor LE("clang-repl"); 82 // FIXME: Add LE.setListCompleter 83 while (llvm::Optional<std::string> Line = LE.readLine()) { 84 if (*Line == "quit") 85 break; 86 if (auto Err = Interp->ParseAndExecute(*Line)) 87 llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); 88 } 89 90 // Our error handler depends on the Diagnostics object, which we're 91 // potentially about to delete. Uninstall the handler now so that any 92 // later errors use the default handling behavior instead. 93 llvm::remove_fatal_error_handler(); 94 95 llvm::llvm_shutdown(); 96 97 return 0; 98 } 99