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