[RFC PATCH] c++, libstdc++, v2: Attempt to implement P3842R2 - A conservative fix for constexpr uncaught_exceptions() and current_exception()
Jakub Jelinek
jakub@redhat.com
Fri Mar 27 10:25:45 GMT 2026
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.
2026-03-27 Jakub Jelinek <jakub@redhat.com>
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.
--- 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)
+ 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);
Jakub
More information about the Libstdc++
mailing list