But couldn't one implement exceptions internally by returning error codes? Yes, this would change the ABI but as long as we're not talking about the interface of a library, i.e. are not leaving the realms of our source code, this should be ok, shouldn't it?
In a sense, try/catch would then just be syntactic sugar that frees you from manually checking for errors after every single function call. Instead, you just handle them in bulk in a catch block, potentially a couple stack frames further upstairs.
EDIT: I just realized my suggestion wouldn't exactly be equivalent to exceptions, in the sense that it wouldn't give stack traces but error return traces, like in Zig:
https://ziglang.org/documentation/master/#Error-Return-Trace...