Feel free to correct me if I'm wrong, but I thought this is not valid use of the lua C api.
To my knowledge, compiling lua as C++ does NOT make it okay to throw exceptions through lua.
To my knowledge, compiling lua as C++ ONLY serves to make it so that if you raise lua error, e.g. by calling luaL_error, the longjmp is instead performed by an exception throw which is caught by lua.
This means that any local variables with nontrivial destructors in the function that called luaL_error will have their destructors called and you won't have UB. That's very helpful for C++ programs, but it's not "lua is a C++ library now and behaves like something you would find in boost". It's a very limited form of support that e.g. makes it possible to put nontrivial C++ objects in userdata without leaks, and not a lot more than that.
To my knowledge, in general you need to treat lua like it is an ANSI C library, which happens to compile as both C and C++ -- because that's what it is. Throwing your own exceptions through such a library is inherently broken. Such a program, written in the common subset of C and C++, has to swallow them because there's nothing else it can realistically do with them. And it doesn't simply translate them as an error code "lua_user_exception_thrown == -1" or whatnot because that would discard all relevant info and defeat the point of C++ exceptions, which are supposed to be structured error signals, which represent problems that are so serious that we need to drop everything to handle them *right now*. If you are writing a program where it seems like exception -> error code translation would be useful, most likely you are abusing / overusing C++ exceptions, which should only be used for truly exceptional situations which might warrant bringing down the program.
The general advice is, think of lua as a C library. It's not nice to throw exceptions through a C library -- it can't in general handle them correctly. Did you ever perform the exercise of writing an exception-safe standard container, like vector? There's a pretty famous series of GOTW where Herb Sutter walks through the pitfalls. It's not trivial, and if you don't have many carefully placed `try` and `catch` blocks there's definitely no way you will succeed.
It's true that `LUAI_TRY` does have some try and catch blocks when we compile in C++ mode, but this macro is pretty limited and if these are the only try-catch blocks in lua (they are), it should be clear that it's not going to be fully strongly exception-safe.
So I don't think you should think of `LUAI_TRY` having a `try { ... } catch (...) { ... }` format as license to throw anything and everything into lua.
My interpretation is that the code you posted is bugged and
falls outside the spec of lua. IMO it should be corrected to this:
// Compile Lua 5.3.3 as C++
// no extern "C" { ... }
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int thrower(lua_State* L) {
lua_pushnil(L);
}
int main() {
lua_State* L = luaL_newstate();
lua_pushcclosure(L, thrower, 0);
int top_before = lua_gettop(L);
int code = lua_pcallk(L, 0, 0, LUA_NOREF, 0, NULL);
int top_after = lua_gettop(L);
return 0;
}
Would love to hear confirmation or corrections from developers, or alternative interpretations.
Chris