This is an implementation of the following RFC:
https://discourse.llvm.org/t/rfc-better-ux-for-clangs-unwind-affecting-attributes/66890
In C++, there are 3 possible behaviors when the
exception escapes out an function that can not unwind:
- exception propagates into function's caller
- defined behavior of immediate program termination
- the wild UB case, behavior is undefined.
Let's look at obvious examples:
- exception propagates into caller, is caught there, and all is good: https://godbolt.org/z/MbTW9rofn
- exception can not exit noexcept function, program is terminated: https://godbolt.org/z/ffeaPz1dK
Now, the third case, the wild UB case, is the most interesting one.
There are 3 clang/gcc attributes that are relevant here, let's look at them:
- __attribute__((pure)): https://godbolt.org/z/PY3KrETb7, there the fun begins. In clang, we get UB, in gcc we get "exception propagates into function's caller"
- __attribute__((const)): https://godbolt.org/z/ozxoW16e9, same as __attribute__((pure))
- __attribute__((nothrow)): https://godbolt.org/z/YMf4sTcfa, the behavior is consistently defined as immediate program termination. I do not understand why it was defined as such, in the sense of how is that different from plain noexcept, but at least we are consistent.
Now, there are 3 problems:
- Our modelling of __attribute__((const))/__attribute__((pure)) differs from that of GCC, we add UB.
- We can not ask for __attribute__((const))/__attribute__((pure)) behavior, without it acting as exception barrier.
- We can not separately ask for the exception propagation to be UB. This would be a handy optimization tool, especially given how brittle our IRGen for the case 2. (program termination) is.
Therefore, this patch does two things:
- Match GCC's implementation-defined behavior on __attribute__((pure))/__attribute__((const))
- they should not cause UB on exception escape, nor should they cause immediate program termination, exceptions should be free to escape into their caller.
Introduce __attribute__((nounwind)), which would be lowered into LLVM IR's nounwind attribute, and if an exception escapes out of an function marked with such an attribute, wild UB happens.
Please note, while currently such an UB is indeed not sanitized,
i have a patch in progress to handle it:
https://reviews.llvm.org/D137381,
so we would not be introducing something that is impossible to deal with.
unrelated changes here?