[PATCH] c++, libstdc++: Implement C++26 P3068R5 - constexpr exceptions [PR117785]
Jason Merrill
jason@redhat.com
Tue Jun 3 15:02:30 GMT 2025
On 6/2/25 4:54 AM, Jakub Jelinek wrote:
> Hi!
>
> The following patch implements the C++26 P3068R5 - constexpr exceptions
> paper.
>
> As the IL cxx_eval_constant* functions see already contains the low
> level calls like __cxa_{allocate,free}_exception, __cxa_{,re}throw etc.,
> the patch just makes 10 extern "C" __cxa_* functions magic builtins which
> during constant evaluation pretend to be constexpr even when not declared
> so and handle them directly, plus does the same for 3 std namespace
> functions - std::uncaught_exceptions, std::current_exception and
> std::rethrow_exception and adds one new FE builtin -
> __builtin_eh_ptr_adjust_ref which the library can use instead of the
> _M_addref and _M_release out of line methods (this one instead of
> recognizing _M_* as magic too because those are clearly specific to
> libstdc++ and e.g. libc++ could use something else).
>
> The patch uses magic VAR_DECLs with heap_{uninit_,,deleted_}identifier
> DECL_NAME like for operator new/delete for objects allocated with
> __cxa_allocate_exception, just sets their DECL_LANG_SPECIFIC so that
> we can track their reference count as well (with std::exception_ptr
> the same exception object can be referenced multiple times and we want
> to destruct and free only when it reaches zero refcount).
>
> For uncaught exceptions being propagated, the patch uses new kind of
> *jump_target, which is that magic VAR_DECL described above.
> The largest change in the patch is making jump_target argument non-optional
> in cxa_eval_constant_exception and all functions it calls that need it.
> This is because exceptions can be thrown from pretty much everywhere, e.g.
> binary expression can throw in either operand. And the patch also adds
> if (*jump_target) return NULL_TREE; or similar in many spots, so that we
> don't crash because cxx_eval_constant_expression returned NULL_TREE
> somewhere before actually trying to use it and so that we don't uselessly
> dive into other operands etc.
> Note, with statement expressions actually this was something we just didn't
> handle correctly before, one can validly have:
> a = ({ if (x) return 42; 12; }) + b;
> or in the other operand, or break/continue instead of return if it is
> somewhere in a loop/switch; and it isn't ok to branch from one operand to
> another one through some kind of goto.
Sounds good.
> On the potential_constant_expression_1 side, important change was to
> set *jump_target conservatively on calls that could throw for C++26 (the
> patch uses magic void_node for potential_constant_expression* instead of
> VAR_DECL, so that we don't have to create new VAR_DECLs there uselessly).
> Without that change, several methods in libstdc++ wouldn't work correctly.
> I'm not sure what exactly potential_constant_expression_1 maps to in the
> C++26 standard wording now and whether doing that is ok, because basically
> after the first call to non-noexcept function it stops checking stuff.
I would expect that we could do better since for constexpr we need to be
able to see the definitions of all the functions and know whether or not
they can actually throw.
But that's not necessary if it's difficult; at this point
potential_constant_expression is just a conservative early filter to
avoid later trying to evaluate thigs that can't possibly succeed.
> And, in some spots where I know potential_constant_expression_1 didn't
> check some subexpressions (e.g. the EH only cleanups or TRY_BLOCK handlers)
> I've added *potential_constant_expression* calls during cxx_eval_constant*,
> not sure if I need to do that because potential_constant_expression_1 is
> very conservative and just doesn't recurse on subexpressions in many cases.
I think that shouldn't be necessary.
Actual patch review soon.
Jason
More information about the Libstdc++
mailing list