On Sat, 28 Mar 2026 at 16:58, Jakub Jelinek <[email protected]> wrote:
>
> On Fri, Mar 27, 2026 at 11:25:45AM +0100, Jakub Jelinek wrote:
> > On Thu, Mar 26, 2026 at 08:40:36AM +0100, Jakub Jelinek wrote:
> > > The following patch attempts to implement the
> > > P3842R1 - A conservative fix for constexpr uncaught_exceptions()
> > > and current_exception()
> > > paper. std::current_exception() and std::uncaught_exceptions() aren't
> > > constexpr anymore (admittedly, they weren't declared that way in the
> > > headers before either, but the FE magically treated them as such),
> > > instead two new FE builtins are introduced so that one can get their
> > > behavior before this patch when needed. So, at constant evaluation
> > > time they are constant evaluated and if they are not folded away,
> > > they are transformed into std::current_exception() or
> > > std::uncaught_exceptions() runtime calls during gimplification.
> > >
> > > Compared to the paper, I had to also deal with nested_exception default
> > > ctor which also calls current_exception.
> > >
> > > Lightly tested on x86_64-linux so far.
> >
> > Here is an updated version of the patch which implements P3842R2.
> > In particular, reverts all nested_exception.h changes over the last year
> > and removes it from the constexpr-eh3.C test. The proposed
> > __builtin_current_exception() is I believe exactly the
> > <it>current-exception</i>() in the paper.
>
> Here is a third version of the patch, no longer RFC PATCH as it has been
> voted in. Testing found a regression in
> 18_support/exception_ptr/exception_ptr_cast.cc
> caused by the earlier version of the patch, so this patch adjusts it to
> use __builtin_current_exception() if possible and fall back to not trying
> to test test01 during constant evaluation otherwise.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2026-03-28 Jakub Jelinek <[email protected]>
>
> gcc/cp/
> * cp-tree.h (enum cp_built_in_function): Add
> CP_BUILT_IN_CURRENT_EXCEPTION and CP_BUILT_IN_UNCAUGHT_EXCEPTIONS.
> * tree.cc (builtin_valid_in_constant_expr_p): Handle
> those.
> * decl.cc (cxx_init_decl_processing): Build
> decls for CP_BUILT_IN_CURRENT_EXCEPTION and
> CP_BUILT_IN_UNCAUGHT_EXCEPTIONS.
> (require_deduced_type): Deduce CP_BUILT_IN_CURRENT_EXCEPTION
> return type.
> * cp-gimplify.cc (cp_gimplify_expr): Handle
> CP_BUILT_IN_CURRENT_EXCEPTION and CP_BUILT_IN_UNCAUGHT_EXCEPTIONS.
> * constexpr.cc (enum cxa_builtin): Remove STD_UNCAUGHT_EXCEPTIONS
> and STD_CURRENT_EXCEPTION, add BUILTIN_UNCAUGHT_EXCEPTIONS and
> BUILTIN_CURRENT_EXCEPTION, renumber some enumerators.
> (cxx_cxa_builtin_fn_p): Don't check for std::uncaught_exceptions
> nor std::current_exception.
> (cxx_eval_cxa_builtin_fn): Handle BUILTIN_UNCAUGHT_EXCEPTIONS
> and BUILTIN_CURRENT_EXCEPTION instead of STD_UNCAUGHT_EXCEPTIONS
> and STD_CURRENT_EXCEPTION.
> (cxx_eval_builtin_function_call): Handle
> CP_BUILT_IN_CURRENT_EXCEPTION and CP_BUILT_IN_UNCAUGHT_EXCEPTIONS.
> Do just one fndecl_builtin_p check for BUILT_IN_FRONTEND and
> switch on DECL_FE_FUNCTION_CODE.
> gcc/testsuite/
> * g++.dg/cpp26/constexpr-eh3.C: Use __builtin_current_exception()
> instead of std::current_exception() and
> __builttin_uncaught_exceptions() instead of
> std::uncaught_exceptions(). Remove nested_exception related parts
> of the test.
> * g++.dg/cpp26/constexpr-eh8.C: Use __builtin_current_exception()
> instead of std::current_exception().
> libstdc++-v3/
> * libsupc++/exception_ptr.h (std::make_exception_ptr): Use
> __builtin_current_exception() instead of current_exception() if
> the builtin exists.
> * libsupc++/nested_exception.h: Revert 2026-01-07 and 2025-07-10
> changes.
> * testsuite/18_support/exception_ptr/exception_ptr_cast.cc (test01):
> Use __builtin_current_exception instead of std::current_exception
> if __has_builtin(__builtin_current_exception). Otherwise don't
> try to constant evaluate test01.
>
> --- gcc/cp/cp-tree.h.jj 2026-03-27 10:17:14.017332648 +0100
> +++ gcc/cp/cp-tree.h 2026-03-27 10:20:42.997381886 +0100
> @@ -7135,6 +7135,8 @@ enum cp_built_in_function {
> CP_BUILT_IN_EH_PTR_ADJUST_REF,
> CP_BUILT_IN_IS_STRING_LITERAL,
> CP_BUILT_IN_CONSTEXPR_DIAG,
> + CP_BUILT_IN_CURRENT_EXCEPTION,
> + CP_BUILT_IN_UNCAUGHT_EXCEPTIONS,
> CP_BUILT_IN_LAST
> };
>
> --- gcc/cp/tree.cc.jj 2026-03-27 10:17:14.036332338 +0100
> +++ gcc/cp/tree.cc 2026-03-27 10:20:42.998245213 +0100
> @@ -570,6 +570,8 @@ builtin_valid_in_constant_expr_p (const_
> case CP_BUILT_IN_EH_PTR_ADJUST_REF:
> case CP_BUILT_IN_IS_STRING_LITERAL:
> case CP_BUILT_IN_CONSTEXPR_DIAG:
> + case CP_BUILT_IN_CURRENT_EXCEPTION:
> + case CP_BUILT_IN_UNCAUGHT_EXCEPTIONS:
> return true;
> default:
> break;
> --- gcc/cp/decl.cc.jj 2026-03-27 10:17:14.019332616 +0100
> +++ gcc/cp/decl.cc 2026-03-27 10:20:42.999379349 +0100
> @@ -5627,6 +5627,20 @@ cxx_init_decl_processing (void)
> CP_BUILT_IN_EH_PTR_ADJUST_REF,
> BUILT_IN_FRONTEND, NULL, NULL_TREE);
> set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
> +
> + /* Similar case to __builtin_source_locaiton above. The concrete
> + return type is std::exception_ptr, but we can't form the type
> + at this point, so it is deduced later. */
> + decl = add_builtin_function ("__builtin_current_exception",
> + auto_ftype, CP_BUILT_IN_CURRENT_EXCEPTION,
> + BUILT_IN_FRONTEND, NULL, NULL_TREE);
> + set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
> +
> + tree int_ftype = build_function_type_list (integer_type_node,
> NULL_TREE);
> + decl = add_builtin_function ("__builtin_uncaught_exceptions",
> + int_ftype, CP_BUILT_IN_UNCAUGHT_EXCEPTIONS,
> + BUILT_IN_FRONTEND, NULL, NULL_TREE);
> + set_call_expr_flags (decl, ECF_PURE | ECF_NOTHROW | ECF_LEAF);
> }
>
> decl
> @@ -21226,8 +21240,8 @@ require_deduced_type (tree decl, tsubst_
> if (undeduced_auto_decl (decl))
> {
> if (TREE_CODE (decl) == FUNCTION_DECL
> - && fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
> - && DECL_FE_FUNCTION_CODE (decl) == CP_BUILT_IN_SOURCE_LOCATION)
> + && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
> + BUILT_IN_FRONTEND))
> {
> /* Set the return type of __builtin_source_location. */
> tree type = get_source_location_impl_type ();
> @@ -21242,6 +21256,33 @@ require_deduced_type (tree decl, tsubst_
> return true;
> }
>
> + if (TREE_CODE (decl) == FUNCTION_DECL
> + && fndecl_built_in_p (decl, CP_BUILT_IN_CURRENT_EXCEPTION,
> + BUILT_IN_FRONTEND))
> + {
> + /* Set the return type of __builtin_current_exception. */
> + tree name = get_identifier ("exception_ptr");
> + tree eptr = lookup_qualified_name (std_node, name);
> + tree fld;
> + if (TREE_CODE (eptr) != TYPE_DECL
> + || !CLASS_TYPE_P (TREE_TYPE (eptr))
> + || !COMPLETE_TYPE_P (TREE_TYPE (eptr))
> + || !(fld = next_aggregate_field (TYPE_FIELDS (TREE_TYPE
> (eptr))))
> + || DECL_ARTIFICIAL (fld)
> + || TREE_CODE (TREE_TYPE (fld)) != POINTER_TYPE
> + || next_aggregate_field (DECL_CHAIN (fld))
> + || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (eptr)),
> + TYPE_SIZE (TREE_TYPE (fld))))
> + {
> + error ("%qs used without %qs declaration",
> + "__builtin_current_exception", "std::exception_ptr");
> + return false;
> + }
> +
> + apply_deduced_return_type (decl, TREE_TYPE (eptr));
> + return true;
> + }
> +
> if (warning_suppressed_p (decl) && seen_error ())
> /* We probably already complained about deduction failure. */;
> else if (complain & tf_error)
> --- gcc/cp/cp-gimplify.cc.jj 2026-03-27 10:17:14.016332665 +0100
> +++ gcc/cp/cp-gimplify.cc 2026-03-27 10:20:43.000506227 +0100
> @@ -979,6 +979,32 @@ cp_gimplify_expr (tree *expr_p, gimple_s
> "__builtin_eh_ptr_adjust_ref");
> *expr_p = void_node;
> break;
> + case CP_BUILT_IN_CURRENT_EXCEPTION:
> + case CP_BUILT_IN_UNCAUGHT_EXCEPTIONS:
> + {
> + const char *name
> + = (DECL_FE_FUNCTION_CODE (decl)
> + == CP_BUILT_IN_CURRENT_EXCEPTION
> + ? "current_exception" : "uncaught_exceptions");
> + tree newdecl = lookup_qualified_name (std_node, name);
> + if (error_operand_p (newdecl))
> + *expr_p = build_zero_cst (TREE_TYPE (*expr_p));
> + else if (TREE_CODE (newdecl) != FUNCTION_DECL
> + || !same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
> + TREE_TYPE (TREE_TYPE (decl)))
> + || (TYPE_ARG_TYPES (TREE_TYPE (newdecl))
> + != void_list_node))
> + {
> + error_at (EXPR_LOCATION (*expr_p),
> + "unexpected %<std::%s%> declaration",
> + name);
> + *expr_p = build_zero_cst (TREE_TYPE (*expr_p));
> + }
> + else
> + *expr_p = build_call_expr_loc (EXPR_LOCATION (*expr_p),
> + newdecl, 0);
> + break;
> + }
> case CP_BUILT_IN_IS_STRING_LITERAL:
> *expr_p
> = fold_builtin_is_string_literal (EXPR_LOCATION (*expr_p),
> --- gcc/cp/constexpr.cc.jj 2026-03-27 10:17:14.014332697 +0100
> +++ gcc/cp/constexpr.cc 2026-03-27 10:20:43.001205329 +0100
> @@ -1804,10 +1804,10 @@ enum cxa_builtin {
> CXA_BAD_CAST = 8,
> CXA_BAD_TYPEID = 9,
> CXA_THROW_BAD_ARRAY_NEW_LENGTH = 10,
> - STD_UNCAUGHT_EXCEPTIONS = 11,
> - STD_CURRENT_EXCEPTION = 12,
> - STD_RETHROW_EXCEPTION = 13,
> - BUILTIN_EH_PTR_ADJUST_REF = 14
> + STD_RETHROW_EXCEPTION = 11,
> + BUILTIN_EH_PTR_ADJUST_REF = 12,
> + BUILTIN_UNCAUGHT_EXCEPTIONS = 13,
> + BUILTIN_CURRENT_EXCEPTION = 14
> };
>
> /* Return cxa_builtin if FNDECL is a __cxa_* function handled as
> @@ -1822,10 +1822,6 @@ cxx_cxa_builtin_fn_p (tree fndecl)
> {
> if (!decl_in_std_namespace_p (fndecl))
> return CXA_NONE;
> - if (id_equal (DECL_NAME (fndecl), "uncaught_exceptions"))
> - return STD_UNCAUGHT_EXCEPTIONS;
> - if (id_equal (DECL_NAME (fndecl), "current_exception"))
> - return STD_CURRENT_EXCEPTION;
> if (id_equal (DECL_NAME (fndecl), "rethrow_exception"))
> return STD_RETHROW_EXCEPTION;
> return CXA_NONE;
> @@ -2186,7 +2182,7 @@ cxx_eval_cxa_builtin_fn (const constexpr
> *jump_target = var;
> }
> return void_node;
> - case STD_UNCAUGHT_EXCEPTIONS:
> + case BUILTIN_UNCAUGHT_EXCEPTIONS:
> if (nargs != 0)
> goto invalid_nargs;
> /* Similarly to __builtin_is_constant_evaluated (), we don't
> @@ -2202,7 +2198,7 @@ cxx_eval_cxa_builtin_fn (const constexpr
> }
> return build_int_cst (integer_type_node,
> ctx->global->uncaught_exceptions);
> - case STD_CURRENT_EXCEPTION:
> + case BUILTIN_CURRENT_EXCEPTION:
> if (nargs != 0)
> goto invalid_nargs;
> else
> @@ -2489,40 +2485,53 @@ cxx_eval_builtin_function_call (const co
> return t;
> }
>
> - /* For __builtin_is_constant_evaluated, defer it if not
> - ctx->manifestly_const_eval (as sometimes we try to constant evaluate
> - without manifestly_const_eval even expressions or parts thereof which
> - will later be manifestly const_eval evaluated), otherwise fold it to
> - true. */
> - if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
> - BUILT_IN_FRONTEND))
> - {
> - if (ctx->manifestly_const_eval == mce_unknown)
> - {
> - *non_constant_p = true;
> - return t;
> - }
> - return constant_boolean_node (ctx->manifestly_const_eval == mce_true,
> - boolean_type_node);
> - }
> -
> - if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION,
> BUILT_IN_FRONTEND))
> - {
> - temp_override<tree> ovr (current_function_decl);
> - if (ctx->call && ctx->call->fundef)
> - current_function_decl = ctx->call->fundef->decl;
> - return fold_builtin_source_location (t);
> - }
> -
> - if (fndecl_built_in_p (fun, CP_BUILT_IN_EH_PTR_ADJUST_REF,
> - BUILT_IN_FRONTEND))
> - return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_EH_PTR_ADJUST_REF,
> - fun, non_constant_p, overflow_p,
> - jump_target);
> + if (fndecl_built_in_p (fun, BUILT_IN_FRONTEND))
> + switch (DECL_FE_FUNCTION_CODE (fun))
> + {
> + case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
> + /* For __builtin_is_constant_evaluated, defer it if not
> + ctx->manifestly_const_eval (as sometimes we try to constant
> evaluate
> + without manifestly_const_eval even expressions or parts thereof
> + which will later be manifestly const_eval evaluated), otherwise
> fold
> + it to true. */
> + if (ctx->manifestly_const_eval == mce_unknown)
> + {
> + *non_constant_p = true;
> + return t;
> + }
> + return constant_boolean_node (ctx->manifestly_const_eval == mce_true,
> + boolean_type_node);
>
> - if (fndecl_built_in_p (fun, CP_BUILT_IN_CONSTEXPR_DIAG, BUILT_IN_FRONTEND))
> - return cxx_eval_constexpr_diag (ctx, t, non_constant_p, overflow_p,
> - jump_target);
> + case CP_BUILT_IN_SOURCE_LOCATION:
> + {
> + temp_override<tree> ovr (current_function_decl);
> + if (ctx->call && ctx->call->fundef)
> + current_function_decl = ctx->call->fundef->decl;
> + return fold_builtin_source_location (t);
> + }
> +
> + case CP_BUILT_IN_EH_PTR_ADJUST_REF:
> + return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_EH_PTR_ADJUST_REF,
> + fun, non_constant_p, overflow_p,
> + jump_target);
> +
> + case CP_BUILT_IN_CURRENT_EXCEPTION:
> + return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_CURRENT_EXCEPTION,
> + fun, non_constant_p, overflow_p,
> + jump_target);
> +
> + case CP_BUILT_IN_UNCAUGHT_EXCEPTIONS:
> + return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_UNCAUGHT_EXCEPTIONS,
> + fun, non_constant_p, overflow_p,
> + jump_target);
> +
> + case CP_BUILT_IN_CONSTEXPR_DIAG:
> + return cxx_eval_constexpr_diag (ctx, t, non_constant_p, overflow_p,
> + jump_target);
> +
> + default:
> + break;
> + }
>
> int strops = 0;
> int strret = 0;
> --- gcc/testsuite/g++.dg/cpp26/constexpr-eh3.C.jj 2026-03-27
> 10:17:15.649306017 +0100
> +++ gcc/testsuite/g++.dg/cpp26/constexpr-eh3.C 2026-03-27 10:25:17.000451093
> +0100
> @@ -20,12 +20,10 @@ constexpr std::bad_typeid k;
> constexpr const char *l = k.what ();
> constexpr std::exception_ptr m = nullptr;
> static_assert (m == nullptr);
> -constexpr std::exception_ptr n = std::current_exception ();
> +constexpr std::exception_ptr n = __builtin_current_exception ();
> static_assert (n == nullptr);
> constexpr std::exception_ptr o;
> static_assert (o == nullptr);
> -constexpr std::nested_exception p;
> -static_assert (p.nested_ptr () == nullptr);
>
> struct A { virtual ~A () {} };
> struct B { virtual void b (); };
> @@ -33,20 +31,13 @@ struct C { virtual void c (); };
> struct D : private B { virtual void d (); };
> struct E { virtual void e (); };
> struct F : D, E, private C { virtual void f (); };
> -struct G { constexpr G () { if (std::uncaught_exceptions () != 0) asm ("");
> } };
> -struct H { constexpr H () : h (0) {} constexpr ~H () { if
> (std::uncaught_exceptions () != h) asm (""); } int h; };
> -struct I : std::nested_exception { };
> -struct J { virtual ~J () noexcept = default; };
> -struct K final { };
> -struct L : J, std::nested_exception { };
> -struct M { };
> -struct N : I, L { };
> -struct O : private std::nested_exception { };
> +struct G { constexpr G () { if (__builtin_uncaught_exceptions () != 0) asm
> (""); } };
> +struct H { constexpr H () : h (0) {} constexpr ~H () { if
> (__builtin_uncaught_exceptions () != h) asm (""); } int h; };
>
> constexpr int
> foo (int x)
> {
> - if (std::uncaught_exceptions () != 0)
> + if (__builtin_uncaught_exceptions () != 0)
> return -1;
> switch (x)
> {
> @@ -58,7 +49,7 @@ foo (int x)
> }
> catch (const std::bad_typeid &x)
> {
> - if (std::uncaught_exceptions () != 0)
> + if (__builtin_uncaught_exceptions () != 0)
> return -1;
> const char *p = x.what ();
> return 1;
> @@ -90,15 +81,15 @@ foo (int x)
> {
> H h;
> h.h = 1;
> - if (std::current_exception () != nullptr)
> + if (__builtin_current_exception () != nullptr)
> return -1;
> throw G ();
> }
> catch (const G &g)
> {
> - if (std::uncaught_exceptions () != 0)
> + if (__builtin_uncaught_exceptions () != 0)
> return -1;
> - if (std::current_exception () == nullptr)
> + if (__builtin_current_exception () == nullptr)
> return -1;
> return 3;
> }
> @@ -156,7 +147,7 @@ foo (int x)
> {
> if (a != 1)
> return -1;
> - b = std::current_exception ();
> + b = __builtin_current_exception ();
> if (b == nullptr)
> return -1;
> try
> @@ -167,14 +158,14 @@ foo (int x)
> {
> if (c != 2L)
> return -1;
> - d = std::current_exception ();
> + d = __builtin_current_exception ();
> if (d == nullptr || b == d)
> return -1;
> }
> - if (std::current_exception () != b)
> + if (__builtin_current_exception () != b)
> return -1;
> }
> - if (std::current_exception () != nullptr)
> + if (__builtin_current_exception () != nullptr)
> return -1;
> try
> {
> @@ -266,157 +257,6 @@ foo (int x)
> }
> return 8;
> }
> - case 8:
> - {
> - std::nested_exception a;
> - if (a.nested_ptr () != nullptr)
> - return -1;
> - try
> - {
> - std::nested_exception b;
> - if (b.nested_ptr () != nullptr)
> - return -1;
> - throw 42;
> - }
> - catch (...)
> - {
> - std::nested_exception c;
> - if (c.nested_ptr () != std::current_exception ())
> - return -1;
> - std::nested_exception d = c;
> - if (d.nested_ptr () != c.nested_ptr ())
> - return -1;
> - c = d;
> - try
> - {
> - c.rethrow_nested ();
> - }
> - catch (const int &e)
> - {
> - if (e != 42)
> - return -1;
> - }
> - }
> - return 9;
> - }
> - case 9:
> - try
> - {
> - std::throw_with_nested (I ());
> - }
> - catch (const std::nested_exception &a)
> - {
> - if (a.nested_ptr () != nullptr)
> - return -1;
> - try
> - {
> - throw;
> - }
> - catch (const I &)
> - {
> - return 10;
> - }
> - }
> - return -1;
> - case 10:
> - try
> - {
> - std::throw_with_nested (J ());
> - }
> - catch (const std::nested_exception &a)
> - {
> - if (a.nested_ptr () != nullptr)
> - return -1;
> - try
> - {
> - throw;
> - }
> - catch (const J &)
> - {
> - return 11;
> - }
> - }
> - return -1;
> - case 11:
> - try
> - {
> - std::throw_with_nested (K ());
> - }
> - catch (const std::nested_exception &)
> - {
> - return -1;
> - }
> - catch (const K &)
> - {
> - return 12;
> - }
> - return -1;
> - case 12:
> - try
> - {
> - throw 42;
> - }
> - catch (...)
> - {
> - I a;
> - try
> - {
> - std::rethrow_if_nested (a);
> - }
> - catch (const int &b)
> - {
> - if (b == 42)
> - return 13;
> - }
> - }
> - return -1;
> - case 13:
> - try
> - {
> - throw J ();
> - }
> - catch (const J &a)
> - {
> - std::rethrow_if_nested (a);
> - return 14;
> - }
> - return -1;
> - case 14:
> - try
> - {
> - throw 42;
> - }
> - catch (...)
> - {
> - try
> - {
> - throw L ();
> - }
> - catch (const J &a)
> - {
> - try
> - {
> - std::rethrow_if_nested (a);
> - }
> - catch (const int &b)
> - {
> - if (b == 42)
> - return 15;
> - }
> - }
> - }
> - return -1;
> - case 15:
> - {
> - std::rethrow_if_nested (1);
> - M m;
> - std::rethrow_if_nested (m);
> - N n;
> - std::rethrow_if_nested (n);
> - O o;
> - std::rethrow_if_nested (o);
> - return 16;
> - }
> default:
> break;
> }
> @@ -431,12 +271,4 @@ static_assert (foo (4) == 5);
> static_assert (foo (5) == 6);
> static_assert (foo (6) == 7);
> static_assert (foo (7) == 8);
> -static_assert (foo (8) == 9);
> -static_assert (foo (9) == 10);
> -static_assert (foo (10) == 11);
> -static_assert (foo (11) == 12);
> -static_assert (foo (12) == 13);
> -static_assert (foo (13) == 14);
> -static_assert (foo (14) == 15);
> -static_assert (foo (15) == 16);
> -static_assert (std::uncaught_exceptions () == 0);
> +static_assert (__builtin_uncaught_exceptions () == 0);
> --- gcc/testsuite/g++.dg/cpp26/constexpr-eh8.C.jj 2026-03-27
> 10:17:15.649306017 +0100
> +++ gcc/testsuite/g++.dg/cpp26/constexpr-eh8.C 2026-03-27 10:20:43.002066001
> +0100
> @@ -13,7 +13,7 @@ foo ()
> }
> catch (...)
> {
> - return std::current_exception ();
> + return __builtin_current_exception ();
> }
> }
>
> --- libstdc++-v3/libsupc++/exception_ptr.h.jj 2026-03-27 10:17:22.954186813
> +0100
> +++ libstdc++-v3/libsupc++/exception_ptr.h 2026-03-27 10:20:43.002212856
> +0100
> @@ -342,7 +342,11 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> }
> catch(...)
> {
> +#if __has_builtin(__builtin_current_exception)
Please use _GLIBCXX_USE_BUILTIN_TRAIT so it's a bit easier to create
preprocessed source that can be bisected with older releases. That's
only needed here, the test can use __has_builtin directly.
The library parts are OK with that change.
> + return __builtin_current_exception();
> +#else
> return current_exception();
> +#endif
> }
> #endif
> return exception_ptr();
> --- libstdc++-v3/libsupc++/nested_exception.h.jj 2026-03-27
> 10:17:22.955186796 +0100
> +++ libstdc++-v3/libsupc++/nested_exception.h 2026-03-27 10:22:08.043534576
> +0100
> @@ -62,25 +62,17 @@ namespace std _GLIBCXX_VISIBILITY(defaul
>
> public:
> /// The default constructor stores the current exception (if any).
> - _GLIBCXX26_CONSTEXPR
> nested_exception() noexcept : _M_ptr(current_exception()) { }
>
> - _GLIBCXX26_CONSTEXPR
> nested_exception(const nested_exception&) noexcept = default;
>
> - _GLIBCXX26_CONSTEXPR
> nested_exception& operator=(const nested_exception&) noexcept = default;
>
> -#if __cplusplus >= 202400L
> - [[__gnu__::__gnu_inline__]]
> - constexpr inline virtual ~nested_exception() noexcept {}
> -#else
> virtual ~nested_exception() noexcept;
> -#endif
>
> /// Rethrow the stored exception, or terminate if none was stored.
> [[noreturn]]
> - _GLIBCXX26_CONSTEXPR void
> + void
> rethrow_nested() const
> {
> if (_M_ptr)
> @@ -89,7 +81,7 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> }
>
> /// Access the stored exception.
> - _GLIBCXX26_CONSTEXPR exception_ptr
> + exception_ptr
> nested_ptr() const noexcept
> { return _M_ptr; }
> };
> @@ -99,11 +91,11 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> template<typename _Except>
> struct _Nested_exception : public _Except, public nested_exception
> {
> - _GLIBCXX26_CONSTEXPR explicit _Nested_exception(const _Except& __ex)
> + explicit _Nested_exception(const _Except& __ex)
> : _Except(__ex)
> { }
>
> - _GLIBCXX26_CONSTEXPR explicit _Nested_exception(_Except&& __ex)
> + explicit _Nested_exception(_Except&& __ex)
> : _Except(static_cast<_Except&&>(__ex))
> { }
> };
> @@ -152,7 +144,7 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> */
> template<typename _Tp>
> [[noreturn]]
> - _GLIBCXX26_CONSTEXPR inline void
> + inline void
> throw_with_nested(_Tp&& __t)
> {
> using _Up = typename decay<_Tp>::type;
> @@ -212,7 +204,7 @@ namespace std _GLIBCXX_VISIBILITY(defaul
> # if ! __cpp_rtti
> [[__gnu__::__always_inline__]]
> #endif
> - _GLIBCXX26_CONSTEXPR inline void
> + inline void
> rethrow_if_nested(const _Ex& __ex)
> {
> const _Ex* __ptr = __builtin_addressof(__ex);
> --- libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc.jj
> 2026-01-02 22:41:17.694546676 +0100
> +++ libstdc++-v3/testsuite/18_support/exception_ptr/exception_ptr_cast.cc
> 2026-03-28 17:37:27.595719313 +0100
> @@ -58,7 +58,11 @@ constexpr bool test01(bool x)
> }
> catch (...)
> {
> +#if __has_builtin(__builtin_current_exception)
> + auto h = __builtin_current_exception();
> +#else
> auto h = std::current_exception();
> +#endif
> auto i = std::exception_ptr_cast<G>(h);
> VERIFY( i != nullptr );
> VERIFY( i->a == 1 && i->e == 2 && i->f == 3 && i->g == 4 );
> @@ -78,7 +82,7 @@ constexpr bool test01(bool x)
> return true;
> }
>
> -#if _GLIBCXX_USE_CXX11_ABI
> +#if _GLIBCXX_USE_CXX11_ABI && __has_builtin(__builtin_current_exception)
> static_assert(test01(false));
> #endif
>
>
>
> Jakub
>