Index: clang/test/Interpreter/simple-exception.cpp =================================================================== --- /dev/null +++ clang/test/Interpreter/simple-exception.cpp @@ -0,0 +1,14 @@ +// clang-format off +// REQUIRES: host-supports-jit, host-supports-exception +// UNSUPPORTED: system-aix +// XFAIL: arm, arm64-apple, windows-msvc, windows-gnu +// RUN: cat %s | clang-repl | FileCheck %s +extern "C" int printf(const char *, ...); + +int f() { throw "Simple exception"; return 0; } +int checkException() { try { printf("Running f()\n"); f(); } catch (const char *e) { printf("%s\n", e); } return 0; } +auto r1 = checkException(); +// CHECK: Running f() +// CHECK-NEXT: Simple exception + +%quit \ No newline at end of file Index: clang/test/lit.cfg.py =================================================================== --- clang/test/lit.cfg.py +++ clang/test/lit.cfg.py @@ -89,8 +89,27 @@ return 'true' in clang_repl_out -if have_host_jit_support(): - config.available_features.add('host-supports-jit') +def have_host_exception_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-exception'], 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_exception_support(): + config.available_features.add('host-supports-exception') if config.clang_staticanalyzer: config.available_features.add('staticanalyzer') Index: clang/tools/clang-repl/ClangRepl.cpp =================================================================== --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -28,6 +28,8 @@ llvm::cl::CommaSeparated); static llvm::cl::opt OptHostSupportsJit("host-supports-jit", llvm::cl::Hidden); +static llvm::cl::opt OptHostSupportsException("host-supports-exception", + llvm::cl::Hidden); static llvm::cl::list OptInputs(llvm::cl::Positional, llvm::cl::desc("[code to run]")); @@ -65,6 +67,35 @@ return Errs ? EXIT_FAILURE : EXIT_SUCCESS; } +// Check if the host environment supports c++ exception handling +// by querying the existence of symbol __cxa_throw. +static bool checkExceptionSupport() { + auto J = llvm::orc::LLJITBuilder().create(); + if (!J) { + llvm::consumeError(J.takeError()); + return false; + } + + auto Interp = clang::Interpreter::create(std::move(CI)); + if (!Interp) { + llvm::consumeError(Interp.takeError()); + return false; + } + + if (auto Err = Interp->ParseAndExecute("")) { + llvm::consumeError(std::move(Err)); + return false; + } + + auto Sym = Interp->getSymbolAddress("__cxa_throw"); + if (!Sym) { + llvm::consumeError(Sym.takeError()); + return false; + } + + return true; +} + llvm::ExitOnError ExitOnErr; int main(int argc, const char **argv) { ExitOnErr.setBanner("clang-repl: "); @@ -87,6 +118,14 @@ return 0; } + if (OptHostSupportsException) { + if (checkExceptionSupport()) + llvm::outs() << "true\n"; + else + 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));