diff --git a/clang/test/Interpreter/simple-exception.cpp b/clang/test/Interpreter/simple-exception.cpp new file mode 100644 --- /dev/null +++ b/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 diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -70,7 +70,7 @@ if config.clang_examples: config.available_features.add('examples') -def have_host_jit_support(): +def have_host_jit_feature_support(feature_name): clang_repl_exe = lit.util.which('clang-repl', config.clang_tools_dir) if not clang_repl_exe: @@ -79,7 +79,7 @@ try: clang_repl_cmd = subprocess.Popen( - [clang_repl_exe, '--host-supports-jit'], stdout=subprocess.PIPE) + [clang_repl_exe, '--host-supports-' + feature_name], stdout=subprocess.PIPE) except OSError: print('could not exec clang-repl') return False @@ -89,9 +89,12 @@ return 'true' in clang_repl_out -if have_host_jit_support(): +if have_host_jit_feature_support('jit'): config.available_features.add('host-supports-jit') +if have_host_jit_feature_support('exception'): + config.available_features.add('host-supports-exception') + if config.clang_staticanalyzer: config.available_features.add('staticanalyzer') tools.append('clang-check') diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/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,42 @@ 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; + } + + std::vector Dummy; + auto CI = clang::IncrementalCompilerBuilder::create(Dummy); + if (!CI) { + llvm::consumeError(CI.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 +125,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));