Change:
Related to . If a fatal error occurs in LLVM, the compiler exits with status 1. This is problematic, because if a test is expecting a compilation failure, the test could still pass. It also makes it difficult to test for the presence of ICEs in general. A simple fix would be to patch our copy of LLVM to exit with 101 (like ICEs) in , but any other ideas would be appreciated.
Those error functions all call , which sounds like it could be a great hook for us, but then that only calls . :/
There is  though, and that handler gets called first.
That sounds nice, but if we exit with 101 (or simply panic) in the handler won't we be skipping any other cleanup (, plus any future cleanup that gets there)? Or could we just call it in our handler? I'm interested in putting a patch together, but I'm unfamiliar with how we link Rust to C++. The error handler needs to be able to consume a .
We shouldn't do anything that looks like exception unwinding. See : I think we can call it -- it's publicly declared in . We might want to keep a note to make sure we check for new cleanup needed when we update LLVM though. We bridge C++ code in . You could just write our handler in C++ there, and add some C-FFI function for to call and hook that up.

Discussion:
main_thread_worker_state = MainThreadWorkerState::Idle; } Message::Done { result: Err(()), worker_id: _ } => { <del> shared_emitter.fatal("aborting due to worker thread failure"); // Exit the coordinator thread return Err(()) </del> <ins> bug!("worker thread panicked"); </ins> } Message::CodegenItem => { bug!("the coordinator should not receive codegen requests")

panic!("expected abort due to worker thread errors") }, Err(_) => { <del> sess.fatal("Error during codegen/LLVM phase."); </del> <ins> bug!("panic during codegen/LLVM phase"); </ins> } };

extern { pub type ModuleBuffer; } extern "C" { <ins> pub fn LLVMRustInstallFatalErrorHandler(); </ins> // Create and destroy contexts. pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context; pub fn LLVMContextDispose(C: &'static mut Context);

let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); <ins> llvm::LLVMRustInstallFatalErrorHandler(); </ins> { let mut add = |arg: &str| { let s = CString::new(arg).unwrap();

#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Bitcode/BitcodeWriterPass.h" <ins> #include "llvm/Support/Signals.h" </ins> #include "llvm/IR/CallSite.h"

#include <cstdlib> #endif <ins> #include <iostream> </ins> //===----------------------------------------------------------------------=== // // This file defines alternate interfaces to core functions that are more

static LLVM_THREAD_LOCAL char *LastError; <ins> // Custom error handler for fatal LLVM errors. // // Notably it exits the process with code 101, unlike LLVM's default of 1. static void FatalErrorHandler(void *UserData, const std::string& Reason, bool GenCrashDiag) { // Do the same thing that the default error handler does. std::cerr << "LLVM ERROR: " << Reason << std::endl; // Since this error handler exits the process, we have to run any cleanup that // LLVM would run after handling the error. This might change with an LLVM // upgrade. sys::RunInterruptHandlers(); exit(101); } extern "C" void LLVMRustInstallFatalErrorHandler() { install_fatal_error_handler(FatalErrorHandler); } </ins> extern "C" LLVMMemoryBufferRef LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =