In previous installments, we’ve discussed (aka, recommended reading)
… which was proposing to add a nounwind
function attribute,
as part of fixing pure
/const
attributes that were previously erroneously implying it.
While that RFC was accepted, there has been a significant pushback
during implementation: ⚙ D138958 [clang] Better UX for Clang’s unwind-affecting attributes
Instead, let’s explore an alternative, more global solution:
What if we don’t introduce a new way to do the same thing differently,
but just fix the existing way of doing it? What if we simply make
noexcept
not mean “abort on exception”, but “(sanitized) UB on exception”?
While obviously we can’t just change it for everyone,
it can be done via a new opt-in C++ dialect, namely -fstrict-noexcept
.
Doing so sidesteps the usual woes of adding a new (expert-only) attribute,
and allows for much easier enablement story – a single flag is simpler
to add than spilling a new attribute everywhere.
Why might we want to do that, you might ask. The problem is, noexcept
means well,
but falls short. While it strives to help with optimizations – knowing that something is
a simple call is really really important for good straight-line code, failure to do so,
and ending with an invoke
, is really detrimental to many optimizations – we still end up
with an invoke
even if we use noexcept
: Compiler Explorer
How many times did someone intentionally concisely wrote such a code thinking
“yes, i really want to always to check that it does not throw, and abort otherwise”?
I’m sure not a zero times, but is that what everyone needs?
Sure, security-critical code may want that, but everyone?
Likewise, one could manually tell the compiler
that no exception happens: Compiler Explorer
Err, well, i guess you can’t? ¯\_(ツ)_/¯
. Not the outcome i expected, TBH.
This question here is a just yet another manifestation of an always-question of
the defaults, with other examples being “what should we do with concepts?
do we always verify preconditions? or can we just optimize on the assumption
that they are true”, and “what should assert
do? should it be always-on?
or can we optimize on the assumption that it is always true”, and
“__builtin_expect()/__builtin_unreachable() are footguns”.
In the end, such questions do not have a right answer. That is, assuming that
the developers implementing it are sufficiently non-homogeneous, and accept that
they don’t know better than everybody else. This proposes a low-cost solution to one of them.
One that is easy to implement, and does not cause language forking in the way zero-init did.
Are there any concrete reasons why this must not be done?
Thoughts?
Roman.