[clang-repl] Handle mllvm args for clang-repl before calling executeAction (#197133) Fixes #178139 This work is built on top of discussions done in https://github.com/llvm/llvm-project/pull/132670 Making a fresh PR cause the branch is a a year old and a bit outdated. ### Problem Statement : This is a 3 part problem statement. Imagine our compiler builder args look like this ``` CB.SetCompilerArgs({ "-v", "-xc++", "-std=c++23", "-Xclang", "-iwithsysroot/include/compat", "-fwasm-exceptions", "-mllvm", "-wasm-enable-sjlj" }); ``` **Problem 1** : clang-repl won't respect mllvm args just yet But the interpreter should be responsible for this. Hence i) We move relevant code into a function called `parseLLVMArgs` in `CompilerInstance.cpp` ii) And we need to add `CI->parseLLVMArgs();` while interpreter creation in `Interpreter.cpp` **Result** : We are now at a stage where clang-repl would repsect the mllvm args passed from the top **Problem 2** : clang-repl would respect the mllvm but only for the first `ParseAndExecute` call. So the block parsing the `Runtimes` is formed correctly. Any cell after that would fail with ``` LLVM ERROR: -exception-model=wasm only allowed with at least one of -wasm-enable-eh or -wasm-enable-sjlj Aborted() ``` And this is because of this line here. https://github.com/llvm/llvm-project/blob/3bab75245a2bbbec36206f7e0c569c17a1a487e6/lld/wasm/Driver.cpp#L1315 We call `lldMain` in `Wasm.cpp` which leads us to `linkerMain` in `lld/wasm/Driver.cpp`. Now I thought this is a case where wasm-ld is not respecting "incremental" compilation and resetting options set by the clang globally. But as Sam's comment conveys [here](https://github.com/llvm/llvm-project/issues/178139#issuecomment-3806525095) I think wasm-ld/lld's design **is not wrong**. My understanding goes like this 1. lld's reset is correct within lld's model. lld was never designed to coexist with a live incremental compiler in the same process. Its cleanup code exists for test isolation and is doing exactly what it was designed to do. Asking lld to skip the reset would break test isolation 2. lld cannot know which options it "owns" vs. which were set by the caller. LLVM's `cl::` system is a global flat namespace. There is no ownership or scoping concept. When lld calls `ResetAllOptionOccurrences()`, it resets *everything* — it literally cannot distinguish. 3. The options being reset are conceptually the CALLER's responsibility. `-wasm-enable-eh` and `-wasm-enable-sjlj` are codegen flags set by the frontend (via `-fwasm-exceptions` / `-mllvm`). The fact that they happen to live in the same global cl registry that lld resets is an artifact of LLVM's global option design, not a meaningful coupling between lld and clang. The Right Fix: **Restore in WasmIncrementalExecutor::addModule()** **Result** : clang-repl would respect mllvm across all cells. <img width="703" height="454" alt="image" src="https://github.com/user-attachments/assets/862d5459-6e78-41e3-bc03-1bbd8c081edd" /> **Problem 3** : Once we've solved the above 2 problems. I added a test in InterpreterTest.cpp but that woudl fail with ``` [----------] 1 test from InterpreterTest [ RUN ] InterpreterTest.EmscriptenExceptionHandling [DBG CreateCpp] wasm-enable-eh registered: NO [DBG CreateCpp] wasm-enable-sjlj registered: NO clang version 23.0.0git (git@github.com:anutosh491/llvm-project.git d1b0c854354cb9bc0033b126fa1f71b2a6c721b2) Target: wasm32-unknown-emscripten Thread model: posix InstalledDir: "" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name "<<< inputs >>>" -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +exception-handling -target-feature +multivalue -target-feature +reference-types -exception-model=wasm -mllvm -wasm-enable-eh -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/ -v -fcoverage-compilation-dir=/ -resource-dir lib/clang/23 -internal-isystem lib/clang/23/include -internal-isystem /include/wasm32-emscripten -internal-isystem /include -std=c++23 -fdeprecated-macro -ferror-limit 19 -fmessage-length=80 -fvisibility=default -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -exception-model=wasm -emit-llvm-only -fincremental-extensions -mllvm -wasm-enable-sjlj -o "<<< inputs >>>.o" -x c++ "<<< inputs >>>" [DBG parseLLVMArgs] wasm-enable-eh registered: NO [DBG parseLLVMArgs] wasm-enable-sjlj registered: NO [DBG parseLLVMArgs] args to parse: -wasm-enable-eh -wasm-enable-sjlj clang (LLVM option parsing): Unknown command line argument '-wasm-enable-eh'. Try: 'clang (LLVM option parsing) --help' clang (LLVM option parsing): Did you mean '--rng-seed'? clang (LLVM option parsing): Unknown command line argument '-wasm-enable-sjlj'. Try: 'clang (LLVM option parsing) --help' clang (LLVM option parsing): Did you mean '--sort-timers'? ``` **Root cause** : llvm_shutdown() Destroys the Option Registry `InterpreterTestBase::TearDownTestSuite()` (in `InterpreterTestFixture.h`) calls `llvm::llvm_shutdown()` after each test suite completes. This function destroys all `ManagedStatic<>` objects, including `ManagedStatic<CommandLineParser>` — the singleton that holds the entire `cl::opt` registry. When the next test suite starts and accesses the `CommandLineParser` again, a fresh empty instance is created. The `cl::opt` global objects (like`WasmEnableEH`) still exist in memory — their constructors ran at program startup — but they have `FullyInitialized = true` and will **not** call `addArgument()` again. So they remain permanently unregistered in the new parser. Fix : Guard llvm_shutdown() on Emscripten. Have added a comment in `TearDownTestSuite()` for the same. Now we have ``` [ RUN ] InterpreterTest.EmscriptenExceptionHandling clang version 23.0.0git (git@github.com:anutosh491/llvm-project.git d1b0c854354cb9bc0033b126fa1f71b2a6c721b2) Target: wasm32-unknown-emscripten Thread model: posix InstalledDir: "" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name "<<< inputs >>>" -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +exception-handling -target-feature +multivalue -target-feature +reference-types -exception-model=wasm -mllvm -wasm-enable-eh -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/ -v -fcoverage-compilation-dir=/ -resource-dir lib/clang/23 -internal-isystem lib/clang/23/include -internal-isystem /include/wasm32-emscripten -internal-isystem /include -std=c++23 -fdeprecated-macro -ferror-limit 19 -fmessage-length=80 -fvisibility=default -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -exception-model=wasm -emit-llvm-only -fincremental-extensions -mllvm -wasm-enable-sjlj -o "<<< inputs >>>.o" -x c++ "<<< inputs >>>" clang -cc1 version 23.0.0git based upon LLVM 23.0.0git default target wasm32-unknown-emscripten ignoring nonexistent directory "lib/clang/23/include" ignoring nonexistent directory "/include/wasm32-emscripten" ignoring nonexistent directory "/include" #include "..." search starts here: End of search list. [ OK ] InterpreterTest.EmscriptenExceptionHandling (37 ms) [----------] 10 tests from InterpreterTest (674 ms total) ```
Welcome to the LLVM project!
This repository contains the source code for LLVM, a toolkit for the construction of highly optimized compilers, optimizers, and run-time environments.
The LLVM project has multiple components. The core of the project is itself called “LLVM”. This contains all of the tools, libraries, and header files needed to process intermediate representations and convert them into object files. Tools include an assembler, disassembler, bitcode analyzer, and bitcode optimizer.
C-like languages use the Clang frontend. This component compiles C, C++, Objective-C, and Objective-C++ code into LLVM bitcode -- and from there into object files, using LLVM.
Other components include: the libc++ C++ standard library, the LLD linker, and more.
Consult the Getting Started with LLVM page for information on building and running LLVM.
For information on how to contribute to the LLVM project, please take a look at the Contributing to LLVM guide.
Join the LLVM Discourse forums, Discord chat, LLVM Office Hours or Regular sync-ups.
The LLVM project has adopted a code of conduct for participants to all modes of communication within the project.