diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 07c170a63ce82..c7b63d64e453a 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -143,6 +143,41 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { return std::move(Clang); } +static llvm::Error HandleFrontendOptions(const CompilerInstance &CI) { + const auto &FrontendOpts = CI.getFrontendOpts(); + + // FIXME: Temporary duplication to honor -mllvm in clang-repl. + // clang/flang handle -mllvm in their tool-side ExecuteCompilerInvocation + // paths. clang-repl currently lacks that step, so we minimally parse + // FrontendOpts.LLVMArgs here to ensure -mllvm options take effect. + // Follow-up work: + // Move this -mllvm handling into a shared, driver/tool-level facility + // used by clang, clang-repl, flang, etc., and remove this library-side + // duplication. + + if (!FrontendOpts.LLVMArgs.empty()) { + unsigned NumArgs = FrontendOpts.LLVMArgs.size(); + auto Args = std::make_unique(NumArgs + 2); + Args[0] = "clang-repl (LLVM option parsing)"; + for (unsigned i = 0; i != NumArgs; ++i) { + Args[i + 1] = FrontendOpts.LLVMArgs[i].c_str(); + if (Args[i + 1][0] == '-') { + auto *option = static_cast *>( + llvm::cl::getRegisteredOptions()[Args[i + 1] + 1]); + if (option) { + option->setInitialValue(true); + } else { + llvm::errs() << "Unknown LLVM option: " << Args[i + 1] << "\n"; + } + } + } + Args[NumArgs + 1] = nullptr; + llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); + } + + return llvm::Error::success(); +} + } // anonymous namespace namespace clang { @@ -418,8 +453,6 @@ Interpreter::getOrcRuntimePath(const driver::ToolChain &TC) { llvm::Expected> Interpreter::create(std::unique_ptr CI, JITConfig Config) { - llvm::Error Err = llvm::Error::success(); - std::unique_ptr JB; if (Config.IsOutOfProcess) { @@ -450,6 +483,11 @@ Interpreter::create(std::unique_ptr CI, JITConfig Config) { } } + llvm::Error Err = HandleFrontendOptions(*CI); + if (Err) { + return std::move(Err); + } + auto Interp = std::unique_ptr(new Interpreter( std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config)); if (auto E = std::move(Err)) diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt index 7b8dcfc9b0546..0c04f7283b53c 100644 --- a/clang/unittests/Interpreter/CMakeLists.txt +++ b/clang/unittests/Interpreter/CMakeLists.txt @@ -80,6 +80,7 @@ target_link_options(ClangReplInterpreterTests PUBLIC "SHELL: -s ALLOW_MEMORY_GROWTH=1" PUBLIC "SHELL: -s STACK_SIZE=32mb" PUBLIC "SHELL: -s INITIAL_MEMORY=128mb" + PUBLIC "SHELL: -s NO_DISABLE_EXCEPTION_CATCHING" PUBLIC "SHELL: --emrun" PUBLIC "SHELL: -Wl,--export=__clang_Interpreter_SetValueWithAlloc" PUBLIC "SHELL: -Wl,--export=__clang_Interpreter_SetValueNoAlloc" diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index 9ff9092524d21..67756c42f1880 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -443,4 +443,21 @@ TEST_F(InterpreterTest, TranslationUnit_CanonicalDecl) { sema.getASTContext().getTranslationUnitDecl()->getCanonicalDecl()); } +TEST_F(InterpreterTest, EmscriptenExceptionHandling) { +#ifndef __EMSCRIPTEN__ + GTEST_SKIP() << "This test only applies to Emscripten builds."; +#endif + + using Args = std::vector; + Args ExtraArgs = {"-std=c++20", "-v", + "-fexceptions", "-fcxx-exceptions", + "-mllvm", "-enable-emscripten-cxx-exceptions", + "-mllvm", "-enable-emscripten-sjlj"}; + + std::unique_ptr Interp = createInterpreter(ExtraArgs); + + llvm::cantFail( + Interp->ParseAndExecute("try { throw 1; } catch (...) { 0; }")); +} + } // end anonymous namespace