The daemon caught Loc.Error at each op and nothing else. That was survivable while the frontend was the only thing that could refuse a form; it is not now that expansion is part of evaluating. Both C-c C-c and C-x C-e run a clang driver through Build.macro_module, which answers with an exit status and a Failure, and a dlopen that finds no symbol answers with another one. Neither is a Loc.Error, so neither was answered, and an exception past serve is not a refused evaluation — it is a dead daemon with the program still on screen and a closed socket waiting for the editor's next request. The boundary is now one place, around the whole of a request, rather than a new arm at each of the dozens of calls. Out_of_memory, Stack_overflow and Sys.Break go through it: those say the process cannot continue, and answering "error" to them would claim a session survived something it did not. Everything else is about the form that was sent, and the message it carries is the one the user can act on, so a clang exit status reaches :message instead of being flattened to "internal error". The session's own state goes with it. Session.eval wrote the imported macro set above the checker, so a form that did not check left the session holding a package's macros and none of its declarations; it is held and committed at the bottom with decls, program and env. Session.eval_expr committed the generic copies it had instantiated before emitting the module that carries them, which is the session believing it holds a body nothing was written for; that assignment moved below Emit. Both are pinned. test_session drives the two rollbacks in process, and test_dev drives a real daemon whose macro module cannot be built — the expression path and the redefinition path, each followed by the same evaluation succeeding and by the session still knowing the program.
Description
Languages
OCaml
67.2%
Emacs Lisp
15.2%
C
10.4%
HTML
2.9%
Standard ML
2.8%
Other
1.5%