Home | History | Annotate | Line # | Download | only in clang-repl
      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