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
>

Reply via email to