mirror of git://gcc.gnu.org/git/gcc.git
c++, libstdc++: Implement C++26 P3068R5 - constexpr exceptions [PR117785]
The following patch implements the C++26 P3068R5 - constexpr exceptions
paper.
As the IL cxx_eval_constant* functions process 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.
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.
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.
2025-07-10 Jakub Jelinek <jakub@redhat.com>
PR c++/117785
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_constexpr_exceptions=202411L for C++26.
gcc/cp/
* constexpr.cc: Implement C++26 P3068R5 - constexpr exceptions.
(class constexpr_global_ctx): Add caught_exceptions and
uncaught_exceptions members.
(constexpr_global_ctx::constexpr_global_ctx): Initialize
uncaught_exceptions.
(returns, breaks, continues, switches): Move earlier.
(throws): New function.
(exception_what_str, diagnose_std_terminate,
diagnose_uncaught_exception): New functions.
(enum cxa_builtin): New type.
(cxx_cxa_builtin_fn_p, cxx_eval_cxa_builtin_fn): New functions.
(cxx_eval_builtin_function_call): Add jump_target argument. Call
cxx_eval_cxa_builtin_fn for __builtin_eh_ptr_adjust_ref. Adjust
cxx_eval_constant_expression calls, if it results in jmp_target,
set *jump_target to it and return.
(cxx_bind_parameters_in_call): Add jump_target argument. Pass
it through to cxx_eval_constant_expression. If it sets *jump_target,
break.
(fold_operand): Adjust cxx_eval_constant_expression caller.
(cxx_eval_assert): Likewise. If it set jmp_target, return true.
(cxx_eval_internal_function): Add jump_target argument. Pass it
through to cxx_eval_constant_expression. Return early if *jump_target
after recursing on args.
(cxx_eval_dynamic_cast_fn): Likewise. Don't set reference_p for
C++26 with -fexceptions.
(cxx_eval_thunk_call): Add jump_target argument. Pass it through
to cxx_eval_constant_expression.
(cxx_set_object_constness): Likewise. Don't set TREE_READONLY if
throws (jump_target).
(cxx_eval_call_expression): Add jump_target argument. Pass it
through to cxx_eval_internal_function, cxx_eval_builtin_function_call,
cxx_eval_thunk_call, cxx_eval_dynamic_cast_fn and
cxx_set_object_constness. Pass it through also
cxx_eval_constant_expression on arguments, cxx_bind_parameters_in_call
and cxx_fold_indirect_ref and for those cases return early
if *jump_target. Call cxx_eval_cxa_builtin_fn for cxx_cxa_builtin_fn_p
functions. For cxx_eval_constant_expression on body, pass address of
cleared jmp_target automatic variable, if it throws propagate
to *jump_target and make it non-cacheable. For C++26 don't diagnose
calls to non-constexpr functions before cxx_bind_parameters_in_call
could report some argument throwing an exception.
(cxx_eval_unary_expression): Add jump_target argument. Pass it
through to cxx_eval_constant_expression and return early
if *jump_target after the call.
(cxx_fold_pointer_plus_expression): Likewise.
(cxx_eval_binary_expression): Likewise and similarly for
cxx_fold_pointer_plus_expression call.
(cxx_eval_conditional_expression): Pass jump_target to
cxx_eval_constant_expression on first operand and return early
if *jump_target after the call.
(cxx_eval_vector_conditional_expression): Add jump_target argument.
Pass it through to cxx_eval_constant_expression for all 3 arguments
and return early if *jump_target after any of those calls.
(get_array_or_vector_nelts): Add jump_target argument. Pass it
through to cxx_eval_constant_expression.
(eval_and_check_array_index): Add jump_target argument. Pass it
through to cxx_eval_constant_expression calls and return early after
each of them if *jump_target.
(cxx_eval_array_reference): Likewise.
(cxx_eval_component_reference): Likewise.
(cxx_eval_bit_field_ref): Likewise.
(cxx_eval_bit_cast): Likewise. Assert CHECKING_P call doesn't
throw or return.
(cxx_eval_logical_expression): Add jump_target argument. Pass it
through to cxx_eval_constant_expression calls and return early after
each of them if *jump_target.
(cxx_eval_bare_aggregate): Likewise.
(cxx_eval_vec_init_1): Add jump_target argument. Pass it through
to cxx_eval_bare_aggregate and recursive call. Pass it through
to get_array_or_vector_nelts and cxx_eval_constant_expression
and return early after it if *jump_target.
(cxx_eval_vec_init): Add jump_target argument. Pass it through
to cxx_eval_constant_expression and cxx_eval_vec_init_1.
(cxx_union_active_member): Add jump_target argument. Pass it
through to cxx_eval_constant_expression and return early after it
if *jump_target.
(cxx_fold_indirect_ref_1): Add jump_target argument. Pass it
through to cxx_union_active_member and recursive calls.
(cxx_eval_indirect_ref): Add jump_target argument. Pass it through
to cxx_fold_indirect_ref_1 calls and to recursive call, in which
case return early after it if *jump_target.
(cxx_fold_indirect_ref): Add jump_target argument. Pass it through
to cxx_fold_indirect_ref and cxx_eval_constant_expression calls and
return early after those if *jump_target.
(cxx_eval_trinary_expression): Add jump_target argument. Pass it
through to cxx_eval_constant_expression calls and return early after
those if *jump_target.
(cxx_eval_store_expression): Add jump_target argument. Pass it
through to cxx_eval_constant_expression and eval_and_check_array_index
calls and return early after those if *jump_target.
(cxx_eval_increment_expression): Add jump_target argument. Pass it
through to cxx_eval_constant_expression calls and return early after
those if *jump_target.
(label_matches): Handle VAR_DECL case.
(cxx_eval_statement_list): Remove local_target variable and
!jump_target handling. Handle throws (jump_target) like returns or
breaks.
(cxx_eval_loop_expr): Remove local_target variable and !jump_target
handling. Pass it through to cxx_eval_constant_expression. Handle
throws (jump_target) like returns.
(cxx_eval_switch_expr): Pass jump_target through to
cxx_eval_constant_expression on cond, return early after it
if *jump_target.
(build_new_constexpr_heap_type): Add jump_target argument. Pass it
through to cxx_eval_constant_expression calls, return early after
those if *jump_target.
(merge_jump_target): New function.
(cxx_eval_constant_expression): Make jump_target argument no longer
defaulted, don't test jump_target for NULL. Pass jump_target
through to recursive calls, cxx_eval_call_expression,
cxx_eval_store_expression, cxx_eval_indirect_ref,
cxx_eval_unary_expression, cxx_eval_binary_expression,
cxx_eval_logical_expression, cxx_eval_array_reference,
cxx_eval_component_reference, cxx_eval_bit_field_ref,
cxx_eval_vector_conditional_expression, cxx_eval_bare_aggregate,
cxx_eval_vec_init, cxx_eval_trinary_expression, cxx_fold_indirect_ref,
build_new_constexpr_heap_type, cxx_eval_increment_expression,
cxx_eval_bit_cast and return earlyu after some of those
if *jump_target as needed.
(cxx_eval_constant_expression) <case TARGET_EXPR>: For C++26 push
also CLEANUP_EH_ONLY cleanups, with NULL_TREE marker after them.
(cxx_eval_constant_expression) <case RETURN_EXPR>: Don't
override *jump_target if throws (jump_target).
(cxx_eval_constant_expression) <case TRY_CATCH_EXPR, case TRY_BLOCK,
case MUST_NOT_THROW_EXPR, case TRY_FINALLY_EXPR, case CLEANUP_STMT>:
Handle C++26 constant expressions.
(cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR>: For C++26
with throws (jump_target) evaluate the CLEANUP_EH_ONLY cleanups as
well, and if not throws (jump_target) skip those. Set *jump_target
if some of the cleanups threw.
(cxx_eval_constant_expression) <case THROW_EXPR>: Recurse on operand
for C++26.
(cxx_eval_outermost_constant_expr): Diagnose uncaught exceptions both
from main expression and cleanups, diagnose also
break/continue/returns from the main expression. Handle
CLEANUP_EH_ONLY cleanup markers. Don't diagnose mutable poison stuff
if non_constant_p. Use different diagnostics for non-deleted heap
allocations if they were allocated by __cxa_allocate_exception.
(callee_might_throw): New function.
(struct check_for_return_continue_data): Add could_throw field.
(check_for_return_continue): Handle AGGR_INIT_EXPR and CALL_EXPR and
set d->could_throw if they could throw.
(potential_constant_expression_1): For CALL_EXPR allow
cxx_dynamic_cast_fn_p calls. For C++26 set *jump_target to void_node
for calls that could throw. For C++26 if call to non-constexpr call
is seen, try to evaluate arguments first and if they could throw,
don't diagnose call to non-constexpr function nor return false.
Adjust check_for_return_continue_data initializers and
set *jump_target to void_node if data.could_throw_p. For C++26
recurse on THROW_EXPR argument. Add comment explaining TRY_BLOCK
handling with C++26 exceptions. Handle throws like returns in some
cases.
* cp-tree.h (MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P,
MUST_NOT_THROW_CATCH_P, DECL_EXCEPTION_REFCOUNT): Define.
(DECL_LOCAL_DECL_P): Fix comment typo, VARIABLE_DECL -> VAR_DECL.
(enum cp_built_in_function): Add CP_BUILT_IN_EH_PTR_ADJUST_REF,
(handler_match_for_exception_type): Declare.
* call.cc (handler_match_for_exception_type): New function.
* except.cc (initialize_handler_parm): Set MUST_NOT_THROW_CATCH_P
on newly created MUST_NOT_THROW_EXPR.
(begin_eh_spec_block): Set MUST_NOT_THROW_NOEXCEPT_P.
(wrap_cleanups_r): Set MUST_NOT_THROW_THROW_P.
(build_throw): Add another TARGET_EXPR whose scope spans
until after the __cxa_throw call and copy pointer value from ptr
to it and use it in __cxa_throw argument.
* tree.cc (builtin_valid_in_constant_expr_p): Handle
CP_BUILT_IN_EH_PTR_ADJUST_REF.
* decl.cc (cxx_init_decl_processing): Initialize
__builtin_eh_ptr_adjust_ref FE builtin.
* pt.cc (tsubst_stmt) <case MUST_NOT_THROW_EXPR>: Copy the
MUST_NOT_THROW_NOEXCEPT_P, MUST_NOT_THROW_THROW_P and
MUST_NOT_THROW_CATCH_P flags.
* cp-gimplify.cc (cp_gimplify_expr) <case CALL_EXPR>: Error on
non-folded CP_BUILT_IN_EH_PTR_ADJUST_REF calls.
gcc/testsuite/
* g++.dg/cpp0x/constexpr-ellipsis2.C: Expect different diagnostics for
C++26.
* g++.dg/cpp0x/constexpr-throw.C: Likewise.
* g++.dg/cpp1y/constexpr-84192.C: Expect different diagnostics.
* g++.dg/cpp1y/constexpr-throw.C: Expect different diagnostics for
C++26.
* g++.dg/cpp1z/constexpr-asm-5.C: Likewise.
* g++.dg/cpp26/constexpr-eh1.C: New test.
* g++.dg/cpp26/constexpr-eh2.C: New test.
* g++.dg/cpp26/constexpr-eh3.C: New test.
* g++.dg/cpp26/constexpr-eh4.C: New test.
* g++.dg/cpp26/constexpr-eh5.C: New test.
* g++.dg/cpp26/constexpr-eh6.C: New test.
* g++.dg/cpp26/constexpr-eh7.C: New test.
* g++.dg/cpp26/constexpr-eh8.C: New test.
* g++.dg/cpp26/constexpr-eh9.C: New test.
* g++.dg/cpp26/constexpr-eh10.C: New test.
* g++.dg/cpp26/constexpr-eh11.C: New test.
* g++.dg/cpp26/constexpr-eh12.C: New test.
* g++.dg/cpp26/constexpr-eh13.C: New test.
* g++.dg/cpp26/constexpr-eh14.C: New test.
* g++.dg/cpp26/constexpr-eh15.C: New test.
* g++.dg/cpp26/feat-cxx26.C: Change formatting in __cpp_pack_indexing
and __cpp_pp_embed test. Add __cpp_constexpr_exceptions test.
* g++.dg/cpp26/static_assert1.C: Expect different diagnostics for
C++26.
* g++.dg/cpp2a/consteval34.C: Likewise.
* g++.dg/cpp2a/consteval-memfn1.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic4.C: For C++26 add std::exception and
std::bad_cast definitions and expect different diagnostics.
* g++.dg/cpp2a/constexpr-dynamic6.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic7.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic8.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic9.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic11.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic14.C: Likewise.
* g++.dg/cpp2a/constexpr-dynamic18.C: Likewise.
* g++.dg/cpp2a/constexpr-new27.C: New test.
* g++.dg/cpp2a/constexpr-typeid5.C: New test.
libstdc++-v3/
* include/bits/version.def (constexpr_exceptions): New.
* include/bits/version.h: Regenerate.
* libsupc++/exception (std::bad_exception::bad_exception): Add
_GLIBCXX26_CONSTEXPR.
(std::bad_exception::~bad_exception, std::bad_exception::what): For
C++26 add constexpr and define inline.
* libsupc++/exception.h (std::exception::exception,
std::exception::operator=): Add _GLIBCXX26_CONSTEXPR.
(std::exception::~exception, std::exception::what): For C++26 add
constexpr and define inline.
* libsupc++/exception_ptr.h (std::make_exception_ptr): Add
_GLIBCXX26_CONSTEXPR. For if consteval use just throw with
current_exception() in catch.
(std::exception_ptr::exception_ptr(void*)): For C++26 add constexpr
and define inline.
(std::exception_ptr::exception_ptr()): Add _GLIBCXX26_CONSTEXPR.
(std::exception_ptr::exception_ptr(const exception_ptr&)): Likewise.
Use __builtin_eh_ptr_adjust_ref if consteval and compiler has it
instead of _M_addref.
(std::exception_ptr::exception_ptr(nullptr_t)): Add
_GLIBCXX26_CONSTEXPR.
(std::exception_ptr::exception_ptr(exception_ptr&&)): Likewise.
(std::exception_ptr::operator=): Likewise.
(std::exception_ptr::~exception_ptr): Likewise. Use
__builtin_eh_ptr_adjust_ref if consteval and compiler has it
instead of _M_release.
(std::exception_ptr::swap): Add _GLIBCXX26_CONSTEXPR.
(std::exception_ptr::operator bool): Likewise.
(std::exception_ptr::operator==): Likewise.
* libsupc++/nested_exception.h
(std::nested_exception::nested_exception): Add _GLIBCXX26_CONSTEXPR.
(std::nested_exception::operator=): Likewise.
(std::nested_exception::~nested_exception): For C++26 add constexpr
and define inline.
(std::nested_exception::rethrow_if_nested): Add _GLIBCXX26_CONSTEXPR.
(std::nested_exception::nested_ptr): Likewise.
(std::_Nested_exception::_Nested_exception): Likewise.
(std::throw_with_nested, std::rethrow_if_nested): Likewise.
* libsupc++/new (std::bad_alloc::bad_alloc): Likewise.
(std::bad_alloc::operator=): Likewise.
(std::bad_alloc::~bad_alloc): For C++26 add constexpr and define
inline.
(std::bad_alloc::what): Likewise.
(std::bad_array_new_length::bad_array_new_length): Add
_GLIBCXX26_CONSTEXPR.
(std::bad_array_new_length::~bad_array_new_length): For C++26 add
constexpr and define inline.
(std::bad_array_new_length::what): Likewise.
* libsupc++/typeinfo (std::bad_cast::bad_cast): Add
_GLIBCXX26_CONSTEXPR.
(std::bad_cast::~bad_cast): For C++26 add constexpr and define inline.
(std::bad_cast::what): Likewise.
(std::bad_typeid::bad_typeid): Add _GLIBCXX26_CONSTEXPR.
(std::bad_typeid::~bad_typeid): For C++26 add constexpr and define
inline.
(std::bad_typeid::what): Likewise.
This commit is contained in:
parent
a1e616955e
commit
baaee10123
|
|
@ -1087,6 +1087,7 @@ c_cpp_builtins (cpp_reader *pfile)
|
|||
{
|
||||
/* Set feature test macros for C++26. */
|
||||
cpp_define (pfile, "__cpp_constexpr=202406L");
|
||||
cpp_define (pfile, "__cpp_constexpr_exceptions=202411L");
|
||||
cpp_define (pfile, "__cpp_static_assert=202306L");
|
||||
cpp_define (pfile, "__cpp_placeholder_variables=202306L");
|
||||
cpp_define (pfile, "__cpp_structured_bindings=202403L");
|
||||
|
|
|
|||
|
|
@ -1723,6 +1723,56 @@ involves_qualification_conversion_p (tree to, tree from)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Return true if HANDLER is a match for exception object with EXCEPT_TYPE as
|
||||
per [except.handle]/3. */
|
||||
|
||||
bool
|
||||
handler_match_for_exception_type (tree handler, tree except_type)
|
||||
{
|
||||
tree handler_type = HANDLER_TYPE (handler);
|
||||
if (handler_type == NULL_TREE)
|
||||
return true; /* ... */
|
||||
if (same_type_ignoring_top_level_qualifiers_p (handler_type, except_type))
|
||||
return true;
|
||||
if (CLASS_TYPE_P (except_type) && CLASS_TYPE_P (handler_type))
|
||||
{
|
||||
base_kind b_kind;
|
||||
tree binfo = lookup_base (except_type, handler_type, ba_check, &b_kind,
|
||||
tf_none);
|
||||
if (binfo && binfo != error_mark_node)
|
||||
return true;
|
||||
}
|
||||
if (TYPE_PTR_P (handler_type) || TYPE_PTRDATAMEM_P (handler_type))
|
||||
{
|
||||
if (TREE_CODE (except_type) == NULLPTR_TYPE)
|
||||
return true;
|
||||
if ((TYPE_PTR_P (handler_type) && TYPE_PTR_P (except_type))
|
||||
|| (TYPE_PTRDATAMEM_P (handler_type)
|
||||
&& TYPE_PTRDATAMEM_P (except_type)))
|
||||
{
|
||||
conversion *conv
|
||||
= standard_conversion (handler_type, except_type, NULL_TREE,
|
||||
/*c_cast_p=*/false, 0, tf_none);
|
||||
if (conv && !conv->bad_p)
|
||||
{
|
||||
for (conversion *t = conv; t; t = next_conversion (t))
|
||||
switch (t->kind)
|
||||
{
|
||||
case ck_ptr:
|
||||
case ck_fnptr:
|
||||
case ck_qual:
|
||||
case ck_identity:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* A reference of the indicated TYPE is being bound directly to the
|
||||
expression represented by the implicit conversion sequence CONV.
|
||||
Return a conversion sequence for this binding. */
|
||||
|
|
|
|||
1803
gcc/cp/constexpr.cc
1803
gcc/cp/constexpr.cc
File diff suppressed because it is too large
Load Diff
|
|
@ -889,6 +889,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
|
|||
(EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p),
|
||||
&CALL_EXPR_ARG (*expr_p, 0));
|
||||
break;
|
||||
case CP_BUILT_IN_EH_PTR_ADJUST_REF:
|
||||
error_at (EXPR_LOCATION (*expr_p),
|
||||
"%qs used outside of constant expressions",
|
||||
"__builtin_eh_ptr_adjust_ref");
|
||||
*expr_p = void_node;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -452,6 +452,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
|||
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
|
||||
RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR)
|
||||
PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*)
|
||||
MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR)
|
||||
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
TEMPLATE_PARMS_FOR_INLINE.
|
||||
|
|
@ -472,6 +473,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
|||
BIND_EXPR_VEC_DTOR (in BIND_EXPR)
|
||||
ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
|
||||
STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
|
||||
MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
|
||||
2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
|
||||
ICS_THIS_FLAG (in _CONV)
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||
|
|
@ -493,6 +495,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
|||
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
|
||||
STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST
|
||||
for {static,tls}_aggregates)
|
||||
MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR)
|
||||
3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
|
||||
ICS_BAD_FLAG (in _CONV)
|
||||
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
||||
|
|
@ -3016,6 +3019,8 @@ struct GTY(()) lang_decl_min {
|
|||
In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE.
|
||||
In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL,
|
||||
this is DECL_DISCRIMINATOR.
|
||||
In constexpr exception artificial VAR_DECL, this is
|
||||
DECL_EXCEPTION_REFCOUNT.
|
||||
In a DECL_LOCAL_DECL_P decl, this is the namespace decl it aliases.
|
||||
Otherwise, in a class-scope DECL, this is DECL_ACCESS. */
|
||||
tree access;
|
||||
|
|
@ -4470,6 +4475,23 @@ get_vec_init_expr (tree t)
|
|||
#define MUST_NOT_THROW_COND(NODE) \
|
||||
TREE_OPERAND (MUST_NOT_THROW_EXPR_CHECK (NODE), 1)
|
||||
|
||||
/* Reasons why MUST_NOT_THROW_EXPR has been created. */
|
||||
|
||||
/* Indicates MUST_NOT_THROW_EXPR has been created to wrap body of
|
||||
a noexcept function. */
|
||||
#define MUST_NOT_THROW_NOEXCEPT_P(NODE) \
|
||||
TREE_LANG_FLAG_0 (MUST_NOT_THROW_EXPR_CHECK (NODE))
|
||||
|
||||
/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of
|
||||
exception object during throw. */
|
||||
#define MUST_NOT_THROW_THROW_P(NODE) \
|
||||
TREE_LANG_FLAG_1 (MUST_NOT_THROW_EXPR_CHECK (NODE))
|
||||
|
||||
/* Indicates MUST_NOT_THROW_EXPR has been created to wrap construction of
|
||||
handler parameter during catch. */
|
||||
#define MUST_NOT_THROW_CATCH_P(NODE) \
|
||||
TREE_LANG_FLAG_2 (MUST_NOT_THROW_EXPR_CHECK (NODE))
|
||||
|
||||
/* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
|
||||
TEMPLATE_DECL. This macro determines whether or not a given class
|
||||
type is really a template type, as opposed to an instantiation or
|
||||
|
|
@ -4512,7 +4534,7 @@ get_vec_init_expr (tree t)
|
|||
#define TYPE_CONTAINS_VPTR_P(NODE) \
|
||||
(TYPE_POLYMORPHIC_P (NODE) || CLASSTYPE_VBASECLASSES (NODE))
|
||||
|
||||
/* Nonzero if NODE is a FUNCTION_DECL or VARIABLE_DECL (for a decl
|
||||
/* Nonzero if NODE is a FUNCTION_DECL or VAR_DECL (for a decl
|
||||
with namespace scope) declared in a local scope. */
|
||||
#define DECL_LOCAL_DECL_P(NODE) \
|
||||
DECL_LANG_FLAG_0 (VAR_OR_FUNCTION_DECL_CHECK (NODE))
|
||||
|
|
@ -5153,6 +5175,10 @@ get_vec_init_expr (tree t)
|
|||
protected_access_node will appear in the DECL_ACCESS for the node. */
|
||||
#define DECL_ACCESS(NODE) (LANG_DECL_MIN_CHECK (NODE)->access)
|
||||
|
||||
/* In artificial VAR_DECL created by cxa_allocate_exception
|
||||
this is reference count. */
|
||||
#define DECL_EXCEPTION_REFCOUNT(NODE) (LANG_DECL_MIN_CHECK (NODE)->access)
|
||||
|
||||
/* Nonzero if the FUNCTION_DECL is a global constructor. */
|
||||
#define DECL_GLOBAL_CTOR_P(NODE) \
|
||||
(LANG_DECL_FN_CHECK (NODE)->global_ctor_p)
|
||||
|
|
@ -6813,6 +6839,7 @@ enum cp_built_in_function {
|
|||
CP_BUILT_IN_IS_CORRESPONDING_MEMBER,
|
||||
CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
|
||||
CP_BUILT_IN_SOURCE_LOCATION,
|
||||
CP_BUILT_IN_EH_PTR_ADJUST_REF,
|
||||
CP_BUILT_IN_LAST
|
||||
};
|
||||
|
||||
|
|
@ -6993,6 +7020,7 @@ extern bool type_has_extended_temps (tree);
|
|||
extern tree strip_top_quals (tree);
|
||||
extern bool reference_related_p (tree, tree);
|
||||
extern bool reference_compatible_p (tree, tree);
|
||||
extern bool handler_match_for_exception_type (tree, tree);
|
||||
extern int remaining_arguments (tree);
|
||||
extern tree build_implicit_conv_flags (tree, tree, int);
|
||||
extern tree perform_implicit_conversion (tree, tree, tsubst_flags_t);
|
||||
|
|
|
|||
|
|
@ -5082,6 +5082,18 @@ cxx_init_decl_processing (void)
|
|||
BUILT_IN_FRONTEND, NULL, NULL_TREE);
|
||||
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
|
||||
|
||||
if (cxx_dialect >= cxx26)
|
||||
{
|
||||
tree void_ptrintftype
|
||||
= build_function_type_list (void_type_node, ptr_type_node,
|
||||
integer_type_node, NULL_TREE);
|
||||
decl = add_builtin_function ("__builtin_eh_ptr_adjust_ref",
|
||||
void_ptrintftype,
|
||||
CP_BUILT_IN_EH_PTR_ADJUST_REF,
|
||||
BUILT_IN_FRONTEND, NULL, NULL_TREE);
|
||||
set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
|
||||
}
|
||||
|
||||
integer_two_node = build_int_cst (NULL_TREE, 2);
|
||||
|
||||
/* Guess at the initial static decls size. */
|
||||
|
|
|
|||
|
|
@ -367,6 +367,8 @@ initialize_handler_parm (tree decl, tree exp)
|
|||
MUST_NOT_THROW_EXPR. */
|
||||
init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
|
||||
init = build_must_not_throw_expr (init, NULL_TREE);
|
||||
if (init && TREE_CODE (init) == MUST_NOT_THROW_EXPR)
|
||||
MUST_NOT_THROW_CATCH_P (init) = 1;
|
||||
}
|
||||
|
||||
decl = pushdecl (decl);
|
||||
|
|
@ -523,6 +525,7 @@ begin_eh_spec_block (void)
|
|||
r = build_stmt (spec_location, MUST_NOT_THROW_EXPR,
|
||||
NULL_TREE, NULL_TREE);
|
||||
TREE_SIDE_EFFECTS (r) = 1;
|
||||
MUST_NOT_THROW_NOEXCEPT_P (r) = 1;
|
||||
}
|
||||
else
|
||||
r = build_stmt (spec_location, EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
|
||||
|
|
@ -614,6 +617,7 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees, void * /*data*/)
|
|||
{
|
||||
cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup,
|
||||
NULL_TREE);
|
||||
MUST_NOT_THROW_THROW_P (cleanup) = 1;
|
||||
TARGET_EXPR_CLEANUP (exp) = cleanup;
|
||||
}
|
||||
|
||||
|
|
@ -712,6 +716,11 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain)
|
|||
allocate_expr = do_allocate_exception (temp_type);
|
||||
if (allocate_expr == error_mark_node)
|
||||
return error_mark_node;
|
||||
/* Copy ptr inside of the CLEANUP_POINT_EXPR
|
||||
added below to a TARGET_EXPR slot added outside of it,
|
||||
otherwise during constant evaluation of throw expression
|
||||
we'd diagnose accessing ptr outside of its lifetime. */
|
||||
tree ptr_copy = get_internal_target_expr (null_pointer_node);
|
||||
allocate_expr = get_internal_target_expr (allocate_expr);
|
||||
ptr = TARGET_EXPR_SLOT (allocate_expr);
|
||||
TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr);
|
||||
|
|
@ -763,10 +772,17 @@ build_throw (location_t loc, tree exp, tsubst_flags_t complain)
|
|||
/* Prepend the allocation. */
|
||||
exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
|
||||
|
||||
exp = build2 (COMPOUND_EXPR, void_type_node, exp,
|
||||
build2 (MODIFY_EXPR, void_type_node,
|
||||
TARGET_EXPR_SLOT (ptr_copy), ptr));
|
||||
ptr = TARGET_EXPR_SLOT (ptr_copy);
|
||||
|
||||
/* Force all the cleanups to be evaluated here so that we don't have
|
||||
to do them during unwinding. */
|
||||
exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp);
|
||||
|
||||
exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), ptr_copy, exp);
|
||||
|
||||
throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
|
||||
|
||||
cleanup = NULL_TREE;
|
||||
|
|
|
|||
|
|
@ -20147,7 +20147,14 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
{
|
||||
tree op0 = RECUR (TREE_OPERAND (t, 0));
|
||||
tree cond = RECUR (MUST_NOT_THROW_COND (t));
|
||||
RETURN (build_must_not_throw_expr (op0, cond));
|
||||
stmt = build_must_not_throw_expr (op0, cond);
|
||||
if (stmt && TREE_CODE (stmt) == MUST_NOT_THROW_EXPR)
|
||||
{
|
||||
MUST_NOT_THROW_NOEXCEPT_P (stmt) = MUST_NOT_THROW_NOEXCEPT_P (t);
|
||||
MUST_NOT_THROW_THROW_P (stmt) = MUST_NOT_THROW_THROW_P (t);
|
||||
MUST_NOT_THROW_CATCH_P (stmt) = MUST_NOT_THROW_CATCH_P (t);
|
||||
}
|
||||
RETURN (stmt);
|
||||
}
|
||||
|
||||
case EXPR_PACK_EXPANSION:
|
||||
|
|
|
|||
|
|
@ -488,6 +488,7 @@ builtin_valid_in_constant_expr_p (const_tree decl)
|
|||
case CP_BUILT_IN_SOURCE_LOCATION:
|
||||
case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
|
||||
case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
|
||||
case CP_BUILT_IN_EH_PTR_ADJUST_REF:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ struct A
|
|||
|
||||
constexpr int ellipsis(...) { return 1; }
|
||||
|
||||
static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition|empty" }
|
||||
static_assert(ellipsis(A().empty()), "Error"); // { dg-error "non-constant condition" }
|
||||
// { dg-error "call to non-'constexpr' function 'bool A::empty\\\(\\\)'" "" { target c++23_down } .-1 }
|
||||
// { dg-error "temporary of non-literal type 'A' in a constant expression" "" { target c++26 } .-2 }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Explicit { dg-require-effective-target exceptions_enabled } to avoid verify compiler messages FAILs for '-fno-exceptions'.
|
||||
|
||||
constexpr int may_throw(bool decide) {
|
||||
return decide ? 42 : throw -1; // { dg-error "throw" }
|
||||
return decide ? 42 : throw -1; // { dg-error "throw" "" { target c++23_down } }
|
||||
}
|
||||
|
||||
constexpr int x = may_throw(false); // { dg-message "may_throw" }
|
||||
constexpr int y = may_throw(true);
|
||||
constexpr int x = may_throw(false); // { dg-message "may_throw" "" { target c++23_down } }
|
||||
constexpr int y = may_throw(true); // { dg-error "uncaught exception '-1'" "" { target c++26 } .-1 }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ void
|
|||
f2 ()
|
||||
{
|
||||
for (;;)
|
||||
constexpr bool b = ({ break; false; }) && false; // { dg-error "is not a constant expression" }
|
||||
constexpr bool b = ({ break; false; }) && false; // { dg-error "'break' outside of a loop or 'switch'" }
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ constexpr int fun(int n) {
|
|||
case 0:
|
||||
return 1;
|
||||
default:
|
||||
throw; // { dg-error "not a constant expression" }
|
||||
}
|
||||
throw; // { dg-error "not a constant expression" "" { target c++23_down } }
|
||||
} // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 }
|
||||
}
|
||||
|
||||
static_assert(fun(0), "");
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ struct H { short size () const { return 0; }
|
|||
constexpr const char *data () const { return ""; } };
|
||||
struct I { constexpr signed char size () const { return 0; }
|
||||
const char *data () const { return ""; } };
|
||||
struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" }
|
||||
struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_down } }
|
||||
constexpr const char *data () const { return ""; };
|
||||
constexpr J (int x) : j (x) {}
|
||||
int j; };
|
||||
|
|
@ -114,6 +114,7 @@ foo ()
|
|||
|
||||
asm ((J (0)));
|
||||
asm ("" :: (J (1)) (1)); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
asm ((M {}));
|
||||
#if __cpp_constexpr_dynamic_alloc >= 201907L
|
||||
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
|
||||
|
|
@ -188,6 +189,7 @@ bar ()
|
|||
|
||||
asm ((J (0)));
|
||||
asm ("" :: (J (1)) (1)); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
asm ((M {}));
|
||||
#if __cpp_constexpr_dynamic_alloc >= 201907L
|
||||
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
|
||||
|
|
@ -272,7 +274,7 @@ namespace NN
|
|||
#if __cplusplus >= 201402L
|
||||
struct J {
|
||||
static constexpr int size () { return 0; }
|
||||
static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++14 } }
|
||||
static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target { c++14 && c++23_down } } }
|
||||
#endif
|
||||
#if __cpp_if_consteval >= 202106L
|
||||
struct K {
|
||||
|
|
@ -284,12 +286,12 @@ namespace NN
|
|||
static constexpr const char *data () { if consteval { return "test"; } else { throw 1; } }
|
||||
};
|
||||
struct M {
|
||||
static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } }
|
||||
static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } }
|
||||
static constexpr const char *data () { return "test"; }
|
||||
};
|
||||
struct N {
|
||||
static constexpr int size () { return 4; }
|
||||
static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } }
|
||||
static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } }
|
||||
};
|
||||
#endif
|
||||
struct O { constexpr int operator () () const { return 12; } };
|
||||
|
|
@ -318,12 +320,15 @@ namespace NN
|
|||
asm ((I {}));
|
||||
#if __cplusplus >= 201402L
|
||||
asm ((J {})); // { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
#endif
|
||||
#if __cpp_if_consteval >= 202106L
|
||||
asm ((K {}));
|
||||
asm ((L {}));
|
||||
asm ((M {})); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
#endif
|
||||
asm ((Q {}));
|
||||
asm ((R {}));
|
||||
|
|
@ -348,12 +353,15 @@ namespace NN
|
|||
asm ((I {}));
|
||||
#if __cplusplus >= 201402L
|
||||
asm ((J {})); // { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
#endif
|
||||
#if __cpp_if_consteval >= 202106L
|
||||
asm ((K {}));
|
||||
asm ((L {}));
|
||||
asm ((M {})); // { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
#endif
|
||||
asm ((Q {}));
|
||||
asm ((R {}));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct S {
|
||||
constexpr S () : s (new int (0)) {}
|
||||
constexpr S (int x) : s (new int (x)) {}
|
||||
constexpr S (const S &x) : s (new int (*x.s)) {}
|
||||
constexpr ~S () { delete s; }
|
||||
int *s;
|
||||
};
|
||||
struct T : public S {
|
||||
constexpr T () : S () {}
|
||||
constexpr T (int x) : S (x) {}
|
||||
constexpr T (const T &x) : S (*x.s) {}
|
||||
constexpr ~T () {}
|
||||
};
|
||||
struct U : public T {
|
||||
constexpr U () : T () {}
|
||||
constexpr U (int x) : T (x) {}
|
||||
constexpr U (const U &x) : T (*x.s) {}
|
||||
constexpr ~U () {}
|
||||
};
|
||||
struct V : public T {
|
||||
constexpr V () : T () {}
|
||||
constexpr V (int x) : T (x) {}
|
||||
constexpr V (const U &x) : T (*x.s) {}
|
||||
constexpr ~V () {}
|
||||
};
|
||||
|
||||
template <typename X>
|
||||
constexpr int
|
||||
foo (X x)
|
||||
{
|
||||
try { throw x; }
|
||||
catch (int &a) { return 42 + a; }
|
||||
catch (const unsigned b) { return 43 + b; }
|
||||
catch (const long &c) { return 44 + c; }
|
||||
catch (bool d) { return 45 + d; }
|
||||
catch (const U &e) { return 46 + *e.s; }
|
||||
catch (const T &f) { return 47 + *f.s; }
|
||||
catch (S g) { return 48 + *g.s; }
|
||||
catch (int *const &h) { return 49; }
|
||||
catch (long long *) { return 50; }
|
||||
catch (const S *const &) { return 51; }
|
||||
catch (...) { return 52; }
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
constexpr int
|
||||
bar (const X &x)
|
||||
{
|
||||
throw x;
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
constexpr int
|
||||
baz (const X &x)
|
||||
{
|
||||
try
|
||||
{
|
||||
try { bar (x); }
|
||||
catch (int &a) { a += 80; throw; }
|
||||
catch (long b) { b += 80; throw; }
|
||||
catch (U &c) { c.s[0] += 82; throw; }
|
||||
catch (V d) { d.s[0] += 83; throw; }
|
||||
}
|
||||
catch (int a) { return 42 + a; }
|
||||
catch (const long &b) { return 43 + b; }
|
||||
catch (S &c) { return 44 + c.s[0]; }
|
||||
catch (long long d) { return 45 + d; }
|
||||
catch (...) { return -1; }
|
||||
}
|
||||
|
||||
constexpr int
|
||||
qux (int x, bool y = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0: throw 42; break;
|
||||
case 1: x = y ? throw 43 : 5; break;
|
||||
case 2: x = -(throw 44, 6); break;
|
||||
case 3: x = x + (throw 45, 7); break;
|
||||
case 4: x = (throw 46, 8) + x; break;
|
||||
case 5: x = (throw 47, y) ? 4 : 5; break;
|
||||
case 6: x += (throw 48, y); break;
|
||||
case 7: x = (double) (throw 49, y); break;
|
||||
case 8: x = foo ((throw 50, x)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
catch (int a) { return a; }
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
corge ()
|
||||
{
|
||||
try { throw 0; }
|
||||
catch (int *const &h) { return 49; }
|
||||
catch (long long *) { return 50; }
|
||||
catch (const S *const &) { return 51; }
|
||||
catch (...) { return 52; }
|
||||
}
|
||||
|
||||
static_assert (foo (12) == 54);
|
||||
static_assert (foo (12U) == 55);
|
||||
static_assert (foo (12L) == 56);
|
||||
static_assert (foo (false) == 45);
|
||||
static_assert (foo (true) == 46);
|
||||
static_assert (foo (U (12)) == 58);
|
||||
static_assert (foo (T (20)) == 67);
|
||||
static_assert (foo (S (30)) == 78);
|
||||
static_assert (foo (nullptr) == 49);
|
||||
static_assert (foo ((int *)nullptr) == 49);
|
||||
static_assert (foo ((long long *)nullptr) == 50);
|
||||
static_assert (foo ((const S *)nullptr) == 51);
|
||||
static_assert (foo ((const T *)nullptr) == 51);
|
||||
static_assert (foo ((const U *)nullptr) == 51);
|
||||
static_assert (foo (12ULL) == 52);
|
||||
static_assert (baz (5) == 127);
|
||||
static_assert (baz (6L) == 49);
|
||||
static_assert (baz (U (25)) == 151);
|
||||
static_assert (baz (V (26)) == 70);
|
||||
static_assert (baz (T (27)) == 71);
|
||||
static_assert (baz (S (28)) == 72);
|
||||
static_assert (baz (7LL) == 52);
|
||||
static_assert (baz (8ULL) == -1);
|
||||
static_assert (qux (0) == 42);
|
||||
static_assert (qux (1) == 43);
|
||||
static_assert (qux (2) == 44);
|
||||
static_assert (qux (3) == 45);
|
||||
static_assert (qux (4) == 46);
|
||||
static_assert (qux (5) == 47);
|
||||
static_assert (qux (6) == 48);
|
||||
static_assert (qux (7) == 49);
|
||||
static_assert (qux (8) == 50);
|
||||
static_assert (corge () == 52);
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct S {
|
||||
};
|
||||
struct T {
|
||||
constexpr ~T () noexcept (false) { throw S {}; }
|
||||
};
|
||||
struct U {
|
||||
int u;
|
||||
};
|
||||
struct V {
|
||||
int v;
|
||||
constexpr V (int x)
|
||||
try : v { x }
|
||||
{
|
||||
if (v > 42)
|
||||
throw U { 42 };
|
||||
}
|
||||
catch (U &u)
|
||||
{
|
||||
--u.u;
|
||||
}
|
||||
};
|
||||
struct W {
|
||||
constexpr ~W () { ++w; }
|
||||
int &w;
|
||||
};
|
||||
struct X : public V {
|
||||
constexpr X (int x)
|
||||
try : V(x)
|
||||
{
|
||||
}
|
||||
catch (U &u)
|
||||
{
|
||||
--u.u;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int
|
||||
foo (bool x)
|
||||
{
|
||||
try
|
||||
{
|
||||
T t; // { dg-error "'std::terminate' called after throwing an exception '42'" }
|
||||
if (x) // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 }
|
||||
throw 42;
|
||||
return 10;
|
||||
}
|
||||
catch (S)
|
||||
{
|
||||
return 11;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar ()
|
||||
{
|
||||
V v { 42 };
|
||||
try
|
||||
{
|
||||
V w { 43 };
|
||||
}
|
||||
catch (const U &u)
|
||||
{
|
||||
if (u.u == 41)
|
||||
return 44;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
baz ()
|
||||
{
|
||||
int i = 42;
|
||||
try
|
||||
{
|
||||
W w { i };
|
||||
throw S ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (i == 43)
|
||||
return 42;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
qux ()
|
||||
{
|
||||
X v { 42 };
|
||||
try
|
||||
{
|
||||
X w { 43 };
|
||||
}
|
||||
catch (const U &u)
|
||||
{
|
||||
if (u.u == 40)
|
||||
return 48;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static_assert (foo (false) == 11);
|
||||
constexpr int a = foo (true); // { dg-message "in 'constexpr' expansion of" }
|
||||
static_assert (bar () == 44);
|
||||
static_assert (baz () == 42);
|
||||
static_assert (qux () == 48);
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct A {
|
||||
explicit constexpr A (int x) noexcept : a (x) {}
|
||||
constexpr virtual int foo () const noexcept { return a; }
|
||||
constexpr virtual ~A () {}
|
||||
int a;
|
||||
};
|
||||
struct B : public A {
|
||||
explicit constexpr B (int x) noexcept : A (x) {}
|
||||
constexpr int foo () const noexcept override { return a | 0x10; }
|
||||
};
|
||||
struct C : public A {
|
||||
explicit constexpr C (int x) noexcept : A (x) {}
|
||||
};
|
||||
struct D : public A {
|
||||
explicit constexpr D (int x) noexcept : A (x) {}
|
||||
};
|
||||
struct E {
|
||||
constexpr E () noexcept : e (0) {}
|
||||
explicit constexpr E (int x) noexcept : e (x) {}
|
||||
int e;
|
||||
};
|
||||
struct F : public E, public B {
|
||||
explicit constexpr F (int x) noexcept : B (x) {}
|
||||
};
|
||||
struct G : public E, public C {
|
||||
explicit constexpr G (int x) noexcept : C (x) {}
|
||||
};
|
||||
struct H : public E, public D {
|
||||
explicit constexpr H (int x) noexcept : D (x) {}
|
||||
};
|
||||
|
||||
consteval int
|
||||
bar (void (*fn) ())
|
||||
{
|
||||
try
|
||||
{
|
||||
fn ();
|
||||
}
|
||||
catch (C &a)
|
||||
{
|
||||
return a.foo () | 0x20;
|
||||
}
|
||||
catch (const C &b) // { dg-warning "exception of type 'C' will be caught by earlier handler" }
|
||||
{
|
||||
return b.foo () | 0x60;
|
||||
}
|
||||
catch (A &c)
|
||||
{
|
||||
return c.foo ();
|
||||
}
|
||||
catch (const A &d) // { dg-warning "exception of type 'A' will be caught by earlier handler" }
|
||||
{
|
||||
return d.foo () | 0x40;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static_assert (bar ([] { throw A { 1 }; }) == 1);
|
||||
static_assert (bar ([] { throw B { 2 }; }) == 0x12);
|
||||
static_assert (bar ([] { throw C { 3 }; }) == 0x23);
|
||||
static_assert (bar ([] { throw D { 4 }; }) == 4);
|
||||
constexpr int a = bar ([] { throw E { 5 }; }); // { dg-error "uncaught exception 'E\\\{5\\\}'" }
|
||||
static_assert (bar ([] { throw F { 6 }; }) == 0x16);
|
||||
static_assert (bar ([] { throw G { 7 }; }) == 0x27);
|
||||
static_assert (bar ([] { throw H { 8 }; }) == 8);
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct A {
|
||||
explicit constexpr A (int x) noexcept : a (x) {}
|
||||
constexpr virtual int foo () const noexcept { return a; }
|
||||
constexpr virtual ~A () {}
|
||||
int a;
|
||||
};
|
||||
struct B : public A {
|
||||
explicit constexpr B (int x) noexcept : A (x) {}
|
||||
constexpr int foo () const noexcept override { return a | 0x10; }
|
||||
};
|
||||
struct C : public A {
|
||||
explicit constexpr C (int x) noexcept : A (x) {}
|
||||
};
|
||||
struct D : public A {
|
||||
explicit constexpr D (int x) noexcept : A (x) {}
|
||||
};
|
||||
struct E {
|
||||
constexpr E () noexcept : e (0) {}
|
||||
explicit constexpr E (int x) noexcept : e (x) {}
|
||||
int e;
|
||||
};
|
||||
struct F : public E, public B {
|
||||
explicit constexpr F (int x) noexcept : B (x) {}
|
||||
};
|
||||
struct G : public E, public C {
|
||||
explicit constexpr G (int x) noexcept : C (x) {}
|
||||
};
|
||||
struct H : public E, public D {
|
||||
explicit constexpr H (int x) noexcept : D (x) {}
|
||||
};
|
||||
|
||||
consteval int
|
||||
bar (void (*fn) ())
|
||||
{
|
||||
int r = 0;
|
||||
try
|
||||
{
|
||||
fn ();
|
||||
}
|
||||
catch (C *a)
|
||||
{
|
||||
r = a->foo () | 0x20;
|
||||
delete a;
|
||||
}
|
||||
catch (const C *b)
|
||||
{
|
||||
r = b->foo () | 0x60;
|
||||
delete b;
|
||||
}
|
||||
catch (A *c)
|
||||
{
|
||||
r = c->foo ();
|
||||
delete c;
|
||||
}
|
||||
catch (const A *d)
|
||||
{
|
||||
r = d->foo () | 0x40;
|
||||
delete d;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static_assert (bar ([] { throw new A { 1 }; }) == 1);
|
||||
static_assert (bar ([] { throw new B { 2 }; }) == 0x12);
|
||||
static_assert (bar ([] { throw new C { 3 }; }) == 0x23);
|
||||
static_assert (bar ([] { throw new D { 4 }; }) == 4);
|
||||
constexpr int a = bar ([] { throw new E { 5 }; }); // { dg-error "uncaught exception of type 'E\\\*'" }
|
||||
static_assert (bar ([] { throw new F { 6 }; }) == 0x16);
|
||||
static_assert (bar ([] { throw new G { 7 }; }) == 0x27);
|
||||
static_assert (bar ([] { throw new H { 8 }; }) == 8);
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
template <typename T>
|
||||
consteval T
|
||||
foo (T x)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw &x;
|
||||
}
|
||||
catch (void *ptr) // { dg-message "for type 'void\\\*'" }
|
||||
{
|
||||
return *static_cast<T *> (ptr) | 0x10;
|
||||
}
|
||||
catch (const void *ptr) // { dg-message "for type 'const void\\\*'" }
|
||||
{
|
||||
return *static_cast<const T *> (ptr) | 0x20;
|
||||
}
|
||||
catch (T *ptr) // { dg-warning "exception of type 'T\\\*' will be caught by earlier handler" }
|
||||
{ // { dg-warning "exception of type 'int\\\*' will be caught by earlier handler" "" { target *-*-* } .-1 }
|
||||
return *ptr | 0x30; // { dg-warning "exception of type 'long long unsigned int\\\*' will be caught by earlier handler" "" { target *-*-* } .-2 }
|
||||
}
|
||||
catch (const T *ptr)
|
||||
{
|
||||
return *ptr | 0x40;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert (foo (1) == 0x11);
|
||||
static_assert (foo (2ULL) == 0x12ULL);
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
template <typename T>
|
||||
constexpr T
|
||||
foo (T x, auto... y)
|
||||
{
|
||||
const T z[] = { x, y... };
|
||||
try
|
||||
{
|
||||
throw z;
|
||||
}
|
||||
catch (const T (&a)[4])
|
||||
{
|
||||
return T ();
|
||||
}
|
||||
catch (const T *b)
|
||||
{
|
||||
return b[0];
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return T ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bar ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
baz ()
|
||||
{
|
||||
}
|
||||
|
||||
static_assert (foo (42, 43, 44, 45, 46) == 42);
|
||||
static_assert (foo (43U, 44U, 45U, 46U) == 43U);
|
||||
static_assert (foo (44LL, 45LL) == 44LL);
|
||||
static_assert (foo (bar, baz, bar, baz) == bar);
|
||||
static_assert (foo (baz, bar) == baz);
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
int
|
||||
foo (int x, int y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar (int x)
|
||||
{
|
||||
if (x < 0)
|
||||
throw x;
|
||||
return x;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
baz (int x, int y)
|
||||
{
|
||||
return foo (bar (x), bar (y));
|
||||
}
|
||||
|
||||
constexpr int
|
||||
qux (int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
return baz (x, y);
|
||||
}
|
||||
catch (int)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert (qux (12, -1) == 42);
|
||||
static_assert (qux (-7, 12) == 42);
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct S {
|
||||
constexpr S () : s (0) {}
|
||||
constexpr S (int x) : s (x) { if (x == 42) throw 42; }
|
||||
constexpr S (const S &x) : s (x.s) {}
|
||||
constexpr ~S () noexcept (false) { if (s == 41) throw 41; }
|
||||
constexpr const char *what () const noexcept { return "S"; }
|
||||
int s;
|
||||
};
|
||||
struct T : public S {
|
||||
constexpr T () {}
|
||||
constexpr T (int x) : S (x) {}
|
||||
constexpr T (const T &x) : S (x.s) {}
|
||||
constexpr ~T () {}
|
||||
constexpr const char *what () const noexcept { return "T"; }
|
||||
};
|
||||
struct U {
|
||||
constexpr U () : u (0) {}
|
||||
constexpr U (int x) : u (x) {}
|
||||
constexpr U (const S &x) : u (0) {}
|
||||
constexpr U (const U &x) : u (x.u) { if (u == 42) throw 43; }
|
||||
constexpr ~U () {}
|
||||
constexpr const char *what () const noexcept { return "U"; }
|
||||
int u;
|
||||
};
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
if (x == 1)
|
||||
throw 43;
|
||||
return x;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar (int x) noexcept // { dg-error "'std::terminate' called" }
|
||||
{ // { dg-message "uncaught exception exited from 'noexcept' function 'constexpr int bar\\\(int\\\)'" "" { target *-*-* } .-1 }
|
||||
return foo (x);
|
||||
}
|
||||
|
||||
constexpr int
|
||||
baz (int x)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 0: throw 1; break;
|
||||
case 1: try { x = bar (x); } catch (...) {} break; // { dg-message "in 'constexpr' expansion of" }
|
||||
case 2: throw S (2); break;
|
||||
case 3: try { throw S (42); } catch (int a) { if (a != 42) throw -1; } break;
|
||||
case 4: try { S s (41); throw 2; } catch (...) {} break; // { dg-error "'std::terminate' called" }
|
||||
case 5: return 5; // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 }
|
||||
case 6:
|
||||
try
|
||||
{
|
||||
throw S (5);
|
||||
}
|
||||
catch (const T &) {}
|
||||
catch (int) {}
|
||||
catch (const bool &) {}
|
||||
catch (const T **const &) {}
|
||||
break;
|
||||
case 7: try { constexpr int y = foo (2); } catch (...) {} break;
|
||||
case 8:
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
throw U ();
|
||||
}
|
||||
catch (U &u)
|
||||
{
|
||||
u.u = 42;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (U u) // { dg-error "'std::terminate' called" }
|
||||
{ // { dg-message "constructor exited with another exception while entering handler" "" { target *-*-* } .-1 }
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
try
|
||||
{
|
||||
throw U (S (41)); // { dg-error "'std::terminate' called" }
|
||||
} // { dg-message "destructor exited with an exception" "" { target *-*-* } .-1 }
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
qux (int x)
|
||||
{
|
||||
try { constexpr int y = foo (1); } catch (...) {} // { dg-error "uncaught exception" }
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr int a = baz (0); // { dg-error "uncaught exception" }
|
||||
constexpr int b = baz (1); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int c = baz (2); // { dg-error "uncaught exception" }
|
||||
constexpr int d = baz (3);
|
||||
constexpr int e = baz (4); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int f = baz (5);
|
||||
constexpr int g = baz (6); // { dg-error "uncaught exception" }
|
||||
constexpr int h = baz (7);
|
||||
constexpr int i = baz (8); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int j = baz (9); // { dg-message "in 'constexpr' expansion of" }
|
||||
|
|
@ -0,0 +1,442 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
#include <exception>
|
||||
#include <new>
|
||||
#include <typeinfo>
|
||||
|
||||
constexpr std::exception a;
|
||||
constexpr const char *b = a.what ();
|
||||
constexpr std::bad_exception c;
|
||||
constexpr const char *d = c.what ();
|
||||
constexpr std::bad_alloc e;
|
||||
constexpr const char *f = e.what ();
|
||||
constexpr std::bad_array_new_length g;
|
||||
constexpr const char *h = g.what ();
|
||||
constexpr std::bad_cast i;
|
||||
constexpr const char *j = i.what ();
|
||||
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 ();
|
||||
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 (); };
|
||||
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 { };
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
if (std::uncaught_exceptions () != 0)
|
||||
return -1;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
try
|
||||
{
|
||||
const std::type_info &s = typeid (*(A *) 0);
|
||||
return -1;
|
||||
}
|
||||
catch (const std::bad_typeid &x)
|
||||
{
|
||||
if (std::uncaught_exceptions () != 0)
|
||||
return -1;
|
||||
const char *p = x.what ();
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
try
|
||||
{
|
||||
static constexpr F f;
|
||||
D &d = dynamic_cast<D &>((B &) f);
|
||||
return -1;
|
||||
}
|
||||
catch (std::bad_cast x)
|
||||
{
|
||||
const char *p = x.what ();
|
||||
return 2;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
try
|
||||
{
|
||||
H h;
|
||||
h.h = 1;
|
||||
if (std::current_exception () != nullptr)
|
||||
return -1;
|
||||
throw G ();
|
||||
}
|
||||
catch (const G &g)
|
||||
{
|
||||
if (std::uncaught_exceptions () != 0)
|
||||
return -1;
|
||||
if (std::current_exception () == nullptr)
|
||||
return -1;
|
||||
return 3;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
try
|
||||
{
|
||||
decltype (sizeof 0) x = -64;
|
||||
char (*a)[2] = new char[x][2];
|
||||
delete[] a;
|
||||
}
|
||||
catch (std::bad_array_new_length x)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
try
|
||||
{
|
||||
int y = -1;
|
||||
int *a = new int[y];
|
||||
delete[] a;
|
||||
}
|
||||
catch (const std::bad_array_new_length &)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
try
|
||||
{
|
||||
int z = 1;
|
||||
int *a = new int[z]{1, 2, 3};
|
||||
delete[] a;
|
||||
}
|
||||
catch (std::bad_array_new_length &)
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
std::exception_ptr b, d;
|
||||
if (b != nullptr || d != nullptr)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
catch (int a)
|
||||
{
|
||||
if (a != 1)
|
||||
return -1;
|
||||
b = std::current_exception ();
|
||||
if (b == nullptr)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
throw 2L;
|
||||
}
|
||||
catch (long int c)
|
||||
{
|
||||
if (c != 2L)
|
||||
return -1;
|
||||
d = std::current_exception ();
|
||||
if (d == nullptr || b == d)
|
||||
return -1;
|
||||
}
|
||||
if (std::current_exception () != b)
|
||||
return -1;
|
||||
}
|
||||
if (std::current_exception () != nullptr)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (d);
|
||||
}
|
||||
catch (long int &e)
|
||||
{
|
||||
if (e != 2L)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (b);
|
||||
}
|
||||
catch (const int &f)
|
||||
{
|
||||
if (f != 1)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (d);
|
||||
}
|
||||
catch (const long int g)
|
||||
{
|
||||
if (g != 2L)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (b);
|
||||
}
|
||||
catch (int h)
|
||||
{
|
||||
if (h != 1)
|
||||
return -1;
|
||||
std::exception_ptr i (b);
|
||||
std::exception_ptr j;
|
||||
if (j != nullptr || i == nullptr || i != b || bool (j))
|
||||
return -1;
|
||||
j = i;
|
||||
if (j != b || !bool (j))
|
||||
return -1;
|
||||
j = nullptr;
|
||||
std::swap (i, j);
|
||||
if (j == nullptr || j != b || i != nullptr)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
std::exception_ptr a = std::make_exception_ptr (42);
|
||||
std::exception_ptr b = std::make_exception_ptr (std::exception ());
|
||||
std::exception_ptr c
|
||||
= std::make_exception_ptr (std::bad_array_new_length ());
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (a);
|
||||
}
|
||||
catch (int d)
|
||||
{
|
||||
if (d != 42)
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (b);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
const char *f = e.what ();
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (c);
|
||||
}
|
||||
catch (const std::bad_alloc &g)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const std::bad_array_new_length &h)
|
||||
{
|
||||
const char *i = h.what ();
|
||||
const char *j = g.what ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static_assert (foo (0) == 1);
|
||||
static_assert (foo (1) == 2);
|
||||
static_assert (foo (2) == 3);
|
||||
static_assert (foo (3) == 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);
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct A { virtual ~A () {} };
|
||||
struct B { virtual void b (); };
|
||||
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 (); };
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case 1:
|
||||
try
|
||||
{
|
||||
static constexpr F f;
|
||||
D &d = dynamic_cast<D &>((B &) f); // { dg-error "called without 'std::bad_cast' being defined" }
|
||||
return -1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
try
|
||||
{
|
||||
decltype (sizeof 0) x = -64;
|
||||
char (*a)[2] = new char[x][2]; // { dg-error "called without 'std::bad_array_new_length' being defined" }
|
||||
delete[] a;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
try
|
||||
{
|
||||
int y = -1;
|
||||
int *a = new int[y]; // { dg-error "called without 'std::bad_array_new_length' being defined" }
|
||||
delete[] a;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
try
|
||||
{
|
||||
int z = 1;
|
||||
int *a = new int[z]{1, 2, 3}; // { dg-error "called without 'std::bad_array_new_length' being defined" }
|
||||
delete[] a;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
constexpr int a = foo (1); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int b = foo (3); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int c = foo (4); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int d = foo (5); // { dg-message "in 'constexpr' expansion of" }
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
constexpr void
|
||||
foo ()
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
|
||||
void
|
||||
bar ()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr void
|
||||
baz ()
|
||||
{
|
||||
foo ();
|
||||
bar ();
|
||||
}
|
||||
|
||||
constexpr void
|
||||
qux ()
|
||||
{
|
||||
if consteval {
|
||||
throw 2;
|
||||
}
|
||||
bar ();
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
corge ()
|
||||
{
|
||||
try
|
||||
{
|
||||
baz ();
|
||||
}
|
||||
catch (int a)
|
||||
{
|
||||
if (a != 1)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
qux ();
|
||||
}
|
||||
catch (int b)
|
||||
{
|
||||
return b == 2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert (corge ());
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
struct S {
|
||||
constexpr S () : s (0) {}
|
||||
constexpr S (int x) : s (x) {}
|
||||
constexpr S (const S &x) : s (x.s) {}
|
||||
constexpr ~S () {}
|
||||
int s;
|
||||
};
|
||||
struct T {
|
||||
constexpr T () : t (0) {}
|
||||
constexpr T (int x) : t (x) {}
|
||||
constexpr T (const T &x) : t (x.t) {}
|
||||
constexpr ~T () {}
|
||||
int t;
|
||||
};
|
||||
struct U : public S, public T {
|
||||
constexpr U () : S (0), T (0) {}
|
||||
constexpr U (int x, int y) : S (x), T (y) {}
|
||||
constexpr U (const U &x) : S (x.s), T (x.t) {}
|
||||
constexpr ~U () {}
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
foo ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw U (1, 2);
|
||||
}
|
||||
catch (const U &x)
|
||||
{
|
||||
if (x.s != 1 || x.t != 2)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const S &y)
|
||||
{
|
||||
if (y.s != 1)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const T &z)
|
||||
{
|
||||
if (z.t != 2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
bar ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw U (1, 2);
|
||||
}
|
||||
catch (U &x)
|
||||
{
|
||||
if (x.s != 1 || x.t != 2)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
x.s = 3;
|
||||
x.t = 4;
|
||||
throw;
|
||||
}
|
||||
catch (S &y)
|
||||
{
|
||||
if (y.s != 3)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (T &z)
|
||||
{
|
||||
if (z.t != 4)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
baz ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw U (1, 2);
|
||||
}
|
||||
catch (U x)
|
||||
{
|
||||
if (x.s != 1 || x.t != 2)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
x.s = 3;
|
||||
x.t = 4;
|
||||
throw;
|
||||
}
|
||||
catch (S y)
|
||||
{
|
||||
if (y.s != 1)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (T z)
|
||||
{
|
||||
if (z.t != 2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert (foo ());
|
||||
static_assert (bar ());
|
||||
static_assert (baz ());
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
constexpr char p[] = "hello";
|
||||
constexpr const char *q[] = { &p[0], &p[3] };
|
||||
constexpr const char *const *r = &q[0];
|
||||
const char *s[] = { &p[0], &p[3] };
|
||||
constexpr const char **t = &s[0];
|
||||
|
||||
constexpr bool
|
||||
foo ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw t;
|
||||
}
|
||||
catch (const char **const &x)
|
||||
{
|
||||
if (x != t)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char **&y)
|
||||
{
|
||||
if (y != t)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char **z)
|
||||
{
|
||||
if (z != t)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *const &v)
|
||||
{
|
||||
if (v != (const char *const *) t)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *w)
|
||||
{
|
||||
if (w != (const char *const *) t)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
bar ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw nullptr;
|
||||
}
|
||||
catch (const char **const &x)
|
||||
{
|
||||
if (x != nullptr)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char **&y)
|
||||
{
|
||||
if (y != nullptr)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char **z)
|
||||
{
|
||||
if (z != nullptr)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *const &v)
|
||||
{
|
||||
if (v != nullptr)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *w)
|
||||
{
|
||||
if (w != nullptr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
baz ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw r;
|
||||
}
|
||||
catch (const char *const *const &x)
|
||||
{
|
||||
if (x != r || **x != 'h')
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *&y)
|
||||
{
|
||||
if (y != r || **y != 'h')
|
||||
return false;
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const char *const *z)
|
||||
{
|
||||
if (z != r || **z != 'h')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert (foo ());
|
||||
static_assert (bar ());
|
||||
static_assert (baz ());
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
#include <exception>
|
||||
|
||||
constexpr std::exception_ptr
|
||||
foo ()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw 42;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return std::current_exception ();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
bar ()
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception (foo ());
|
||||
}
|
||||
catch (const int &a)
|
||||
{
|
||||
return a == 42;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert (bar ());
|
||||
constexpr std::exception_ptr a = foo (); // { dg-error "is not a constant expression because it refers to exception object allocated with '__cxa_allocate_exception'" }
|
||||
constexpr std::exception_ptr b = std::make_exception_ptr (42ULL); // { dg-error "is not a constant expression because it refers to exception object allocated with '__cxa_allocate_exception'" }
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
// C++26 P3068R5 - Allowing exception throwing in constant-evaluation
|
||||
// { dg-do compile { target c++26 } }
|
||||
// { dg-require-effective-target exceptions_enabled }
|
||||
|
||||
namespace std
|
||||
{
|
||||
struct exception
|
||||
{
|
||||
constexpr exception () noexcept { }
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr exception (exception &&) = default;
|
||||
constexpr exception &operator= (exception &&) = default;
|
||||
constexpr virtual const char *what () const noexcept
|
||||
{ return "std::exception"; }
|
||||
};
|
||||
}
|
||||
|
||||
struct S : public std::exception {
|
||||
constexpr S () : s (0) {}
|
||||
constexpr S (int x) : s (x) {}
|
||||
constexpr S (const S &x) : s (x.s) {}
|
||||
constexpr virtual ~S () {}
|
||||
constexpr virtual const char *what () noexcept { return "this is S"; }
|
||||
int s;
|
||||
};
|
||||
struct T : public std::exception {
|
||||
constexpr T () : s (new char[1]), t (0) { s[0] = '\0'; }
|
||||
constexpr T (const char *p, int q) : s (new char[q + 1]), t (q)
|
||||
{
|
||||
for (int i = 0; i <= t; ++i)
|
||||
s[i] = p[i];
|
||||
}
|
||||
constexpr T (const T &x) : s (new char[x.t + 1]), t (x.t)
|
||||
{
|
||||
for (int i = 0; i <= t; ++i)
|
||||
s[i] = x.s[i];
|
||||
}
|
||||
constexpr virtual ~T () { delete[] s; }
|
||||
constexpr virtual const char *what () noexcept { return s; }
|
||||
char *s;
|
||||
int t;
|
||||
};
|
||||
struct U {
|
||||
constexpr U () : x (0), y (0), z (0) {}
|
||||
constexpr U (int a, long b, unsigned long long c) : x (a), y (b), z (c) {}
|
||||
constexpr U (const U &u) = default;
|
||||
int x;
|
||||
long y;
|
||||
unsigned long long z;
|
||||
};
|
||||
struct V {
|
||||
constexpr V () : v (0) {}
|
||||
constexpr V (int x) : v (x) {}
|
||||
constexpr V (const V &x) : v (x.v) {}
|
||||
constexpr virtual ~V () {}
|
||||
constexpr virtual const char *what () noexcept { return "this is V"; }
|
||||
int v;
|
||||
};
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
if (x == 1)
|
||||
throw S (42);
|
||||
else if (x == 2)
|
||||
throw T ("hello, world", sizeof ("hello, world") - 1);
|
||||
else if (x == 3)
|
||||
throw U (1, -2L, 42ULL);
|
||||
else if (x == 4)
|
||||
throw 42;
|
||||
else if (x == 5)
|
||||
throw 1.0;
|
||||
else if (x == 6)
|
||||
throw V (42);
|
||||
else
|
||||
return 42;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar (int x) noexcept
|
||||
// { dg-error "'std::terminate' called after throwing an exception of type 'S'; 'what\\\(\\\)': 'this is S'" "" { target *-*-* } .-1 }
|
||||
// { dg-message "uncaught exception exited from 'noexcept' function 'constexpr int bar\\\(int\\\)'" "" { target *-*-* } .-2 }
|
||||
// { dg-error "'std::terminate' called after throwing an exception of type 'T'; 'what\\\(\\\)': 'hello, world'" "" { target *-*-* } .-3 }
|
||||
// { dg-error "'std::terminate' called after throwing an exception 'U\\\{1, -2, 42\\\}'" "" { target *-*-* } .-4 }
|
||||
// { dg-error "'std::terminate' called after throwing an exception '42'" "" { target *-*-* } .-5 }
|
||||
// { dg-error "'std::terminate' called after throwing an exception '1\\\.0e\\\+0'" "" { target *-*-* } .-6 }
|
||||
// { dg-error "'std::terminate' called after throwing an exception 'V\\\{\[^\n\r]*42\\\}" "" { target *-*-* } .-7 }
|
||||
{
|
||||
return foo (x);
|
||||
}
|
||||
|
||||
constexpr int
|
||||
baz (int x)
|
||||
{
|
||||
try
|
||||
{
|
||||
return foo (x);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert (bar (0) == 42);
|
||||
constexpr int a = bar (1); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int b = bar (2); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int c = bar (3); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int d = bar (4); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int e = bar (5); // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr int f = bar (6); // { dg-message "in 'constexpr' expansion of" }
|
||||
static_assert (baz (0) == 42);
|
||||
static_assert (baz (1) == -1);
|
||||
static_assert (baz (2) == -1);
|
||||
static_assert (baz (3) == -1);
|
||||
static_assert (baz (4) == -1);
|
||||
static_assert (baz (5) == -1);
|
||||
static_assert (baz (6) == -1);
|
||||
static_assert (foo (0) == 42);
|
||||
constexpr int g = foo (1); // { dg-error "uncaught exception of type 'S'; 'what\\\(\\\)': 'this is S'" }
|
||||
constexpr int h = foo (2); // { dg-error "uncaught exception of type 'T'; 'what\\\(\\\)': 'hello, world'" }
|
||||
constexpr int i = foo (3); // { dg-error "uncaught exception 'U\\\{1, -2, 42\\\}'" }
|
||||
constexpr int j = foo (4); // { dg-error "uncaught exception '42'" }
|
||||
constexpr int k = foo (5); // { dg-error "uncaught exception '1\\\.0e\\\+0'" }
|
||||
constexpr int l = foo (6); // { dg-error "uncaught exception 'V\\\{\[^\n\r]*42\\\}'" }
|
||||
|
|
@ -624,19 +624,25 @@
|
|||
#endif
|
||||
|
||||
#ifndef __cpp_pack_indexing
|
||||
# error "__cpp_pack_indexing"
|
||||
# error "__cpp_pack_indexing"
|
||||
#elif __cpp_pack_indexing != 202311
|
||||
# error "__cpp_pack_indexing != 202311"
|
||||
#endif
|
||||
|
||||
#ifndef __cpp_pp_embed
|
||||
# error "__cpp_pp_embed"
|
||||
# error "__cpp_pp_embed"
|
||||
#elif __cpp_pp_embed != 202502
|
||||
# error "__cpp_pp_embed != 202502"
|
||||
#endif
|
||||
|
||||
#ifndef __cpp_constexpr_virtual_inheritance
|
||||
# error "__cpp_constexpr_virtual_inheritance"
|
||||
# error "__cpp_constexpr_virtual_inheritance"
|
||||
#elif __cpp_constexpr_virtual_inheritance != 202506
|
||||
# error "__cpp_constexpr_virtual_inheritance != 202506"
|
||||
#endif
|
||||
|
||||
#ifndef __cpp_constexpr_exceptions
|
||||
# error "__cpp_constexpr_exceptions"
|
||||
#elif __cpp_constexpr_exceptions != 202411
|
||||
# error "__cpp_constexpr_exceptions != 202411"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ static_assert (true, H {}); // { dg-warning "'static_assert' with non-string mes
|
|||
struct I { constexpr signed char size () const { return 0; }
|
||||
const char *data () const { return ""; } };
|
||||
static_assert (true, I {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_down } }
|
||||
struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" }
|
||||
struct J { constexpr int size () const { return j ? throw 1 : 0; } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_down } }
|
||||
constexpr const char *data () const { return ""; };
|
||||
constexpr J (int x) : j (x) {}
|
||||
int j; };
|
||||
|
|
@ -60,6 +60,7 @@ static_assert (false, J (0)); // { dg-warning "'static_assert' with non-string m
|
|||
// { dg-error "static assertion failed" "" { target *-*-* } .-1 }
|
||||
static_assert (false, J (1)); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_down } }
|
||||
// { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target *-*-* } .-1 }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
struct K { constexpr operator int () { return 4; } };
|
||||
struct L { constexpr operator const char * () { return "test"; } };
|
||||
struct M { constexpr K size () const { return {}; }
|
||||
|
|
@ -261,10 +262,11 @@ namespace NN
|
|||
#if __cplusplus >= 201402L
|
||||
struct J {
|
||||
static constexpr int size () { return 0; }
|
||||
static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++14 } }
|
||||
static constexpr const char *data (int x = 0) { if (x) return nullptr; else throw 1; } }; // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target { c++14 && c++23_down } } }
|
||||
static_assert (true, J{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++14 && c++23_down } } }
|
||||
static_assert (false, J{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++14 && c++23_down } } }
|
||||
// { dg-error "constexpr string 'data\\\(\\\)' must be a core constant expression" "" { target c++14 } .-1 }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
#endif
|
||||
#if __cpp_if_consteval >= 202106L
|
||||
struct K {
|
||||
|
|
@ -282,19 +284,21 @@ namespace NN
|
|||
static_assert (false, L{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } }
|
||||
// { dg-error "static assertion failed: test" "" { target c++23 } .-1 }
|
||||
struct M {
|
||||
static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } }
|
||||
static constexpr int size () { if consteval { throw 1; } else { return 4; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } }
|
||||
static constexpr const char *data () { return "test"; }
|
||||
};
|
||||
static_assert (true, M{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } }
|
||||
static_assert (false, M{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } }
|
||||
// { dg-error "constexpr string 'size\\\(\\\)' must be a constant expression" "" { target c++23 } .-1 }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
struct N {
|
||||
static constexpr int size () { return 4; }
|
||||
static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23 } }
|
||||
static constexpr const char *data () { if consteval { throw 1; } else { return "test"; } } // { dg-error "expression '<throw-expression>' is not a constant expression" "" { target c++23_only } }
|
||||
};
|
||||
static_assert (true, N{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } }
|
||||
static_assert (false, N{}); // { dg-warning "'static_assert' with non-string message only available with" "" { target c++23_only } }
|
||||
// { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++23 } .-1 }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
#endif
|
||||
struct O { constexpr int operator () () const { return 12; } };
|
||||
struct P { constexpr const char *operator () () const { return "another test"; } };
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
struct fixed_string {
|
||||
consteval int size(int n) const {
|
||||
if (n < 0) throw; // { dg-error "not a constant" }
|
||||
return n;
|
||||
if (n < 0) throw; // { dg-error "not a constant" "" { target c++23_down } }
|
||||
return n; // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 }
|
||||
}
|
||||
|
||||
static consteval int size_static(int n) {
|
||||
if (n < 0) throw; // { dg-error "not a constant" }
|
||||
return n;
|
||||
if (n < 0) throw; // { dg-error "not a constant" "" { target c++23_down } }
|
||||
return n; // { dg-error "'void __cxa_rethrow\\\(\\\)' called with no caught exceptions active" "" { target c++26 } .-1 }
|
||||
}
|
||||
|
||||
consteval void operator()() const { }
|
||||
|
|
|
|||
|
|
@ -1,42 +1,51 @@
|
|||
// { dg-do compile { target c++20 } }
|
||||
// Explicit { dg-require-effective-target exceptions_enabled } to avoid verify compiler messages FAILs for '-fno-exceptions'.
|
||||
|
||||
consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" }
|
||||
consteval int bar (int i) { if (i != 1) throw 1; return 0; } // { dg-error "is not a constant expression" "" { target c++23_down } }
|
||||
|
||||
constexpr int
|
||||
foo (bool b)
|
||||
{
|
||||
return b ? bar (3) : 2; // { dg-message "in .constexpr. expansion" }
|
||||
return b ? bar (3) : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
}
|
||||
} // { dg-error "uncaught exception '1'" "" { target c++26 } }
|
||||
|
||||
static_assert (foo (false) == 2);
|
||||
|
||||
__extension__ constexpr int g1 = false ?: bar (2); // { dg-message "in .constexpr. expansion" }
|
||||
__extension__ constexpr int g2 = false ?: (1 + bar (2)); // { dg-message "in .constexpr. expansion" }
|
||||
__extension__ constexpr int g1 = false ?: bar (2); // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
__extension__ constexpr int g2 = false ?: (1 + bar (2)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
__extension__ constexpr int g3 = true ?: bar (2);
|
||||
__extension__ constexpr int g4 = true ?: (1 + bar (2));
|
||||
constexpr int g5 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" }
|
||||
constexpr int g6 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" }
|
||||
constexpr int g5 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
constexpr int g6 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-1 }
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
__extension__ int a1[bar(3)]; // { dg-message "in .constexpr. expansion" }
|
||||
__extension__ int a1[bar(3)]; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
int a2[sizeof (bar(3))];
|
||||
|
||||
int a3 = false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" }
|
||||
int a3 = false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
a3 += false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
a3 += false ? (1 + bar (8)) : 1; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
|
||||
__extension__ int a4 = false ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" }
|
||||
__extension__ int a4 = false ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
__extension__ int a5 = true ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
__extension__ int a5 = true ?: (1 + bar (8)); // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
int a6 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
int a6 = bar (2) ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
int a7 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" }
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
int a7 = bar (2) - 1 ? 1 : 2; // { dg-message "in .constexpr. expansion" "" { target c++23_down } }
|
||||
// { dg-error "call to consteval function" "" { target *-*-* } .-1 }
|
||||
}
|
||||
// { dg-error "uncaught exception '1'" "" { target c++26 } .-2 }
|
||||
} // { dg-error "uncaught exception '1'" "" { target c++26 } }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,22 @@
|
|||
// a pointer to or object of the constructor or destructor's own class or one
|
||||
// of its bases, the dynamic_cast results in undefined behavior.
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
struct V {
|
||||
virtual void f();
|
||||
};
|
||||
|
|
@ -19,7 +35,7 @@ struct B : V {
|
|||
};
|
||||
|
||||
struct D : A, B {
|
||||
constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr D() : B((A*)this, this) { } // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
};
|
||||
|
||||
constexpr B::B(V* v, A* a)
|
||||
|
|
@ -29,8 +45,9 @@ constexpr B::B(V* v, A* a)
|
|||
if (b != nullptr)
|
||||
__builtin_abort ();
|
||||
|
||||
B& br = dynamic_cast<B&>(*v); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .B." "" { target *-*-* } .-1 }
|
||||
B& br = dynamic_cast<B&>(*v); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .B." "" { target c++23_down } .-1 }
|
||||
}
|
||||
|
||||
constexpr D d; // { dg-message "in 'constexpr' expansion of" }
|
||||
constexpr D d; // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-1 }
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@
|
|||
// Adopted from g++.old-deja/g++.other/dyncast1.C.
|
||||
// But use reference dynamic_cast.
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. downcast
|
||||
// 1.1. single inheritance case
|
||||
|
||||
|
|
@ -21,27 +37,35 @@ class CCC : protected B {};
|
|||
class DDD : protected CCC {};
|
||||
|
||||
constexpr D d;
|
||||
constexpr bool b01 = (dynamic_cast<D&> ((A&)d), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 }
|
||||
constexpr bool b02 = (dynamic_cast<D&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 }
|
||||
constexpr bool b01 = (dynamic_cast<D&> ((A&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b02 = (dynamic_cast<D&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
static_assert (&d == &dynamic_cast<const D&> ((C&)d));
|
||||
constexpr bool b03 = (dynamic_cast<C&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target *-*-* } .-1 }
|
||||
constexpr bool b03 = (dynamic_cast<C&> ((B&)d), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .D." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
constexpr DD dd;
|
||||
constexpr bool b04 = (dynamic_cast<DD&> ((A&)dd), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DD." "" { target *-*-* } .-1 }
|
||||
constexpr bool b05 = (dynamic_cast<DD&> ((B&)dd), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DD." "" { target *-*-* } .-1 }
|
||||
constexpr bool b04 = (dynamic_cast<DD&> ((A&)dd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DD." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b05 = (dynamic_cast<DD&> ((B&)dd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DD." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
constexpr DDD ddd;
|
||||
constexpr bool b06 = (dynamic_cast<DDD&> ((A&)ddd), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 }
|
||||
constexpr bool b07 = (dynamic_cast<DDD&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 }
|
||||
constexpr bool b08 = (dynamic_cast<CCC&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target *-*-* } .-1 }
|
||||
constexpr bool b06 = (dynamic_cast<DDD&> ((A&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const A. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b07 = (dynamic_cast<DDD&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b08 = (dynamic_cast<CCC&> ((B&)ddd), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .DDD." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
// 1.2. multiple inheritance case
|
||||
// 1.2.1. all bases are public
|
||||
|
|
@ -50,19 +74,23 @@ struct E : D, CC {};
|
|||
struct EE : CC, D {}; //Will search in reverse order.
|
||||
|
||||
constexpr E e;
|
||||
constexpr bool b09 = (dynamic_cast<E&> ((A&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .E." "" { target *-*-* } .-1 }
|
||||
constexpr bool b10 = (dynamic_cast<E&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .E." "" { target *-*-* } .-1 }
|
||||
constexpr bool b09 = (dynamic_cast<E&> ((A&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .E." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b10 = (dynamic_cast<E&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .E." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
static_assert (&e == &dynamic_cast<E&> ((C&)(D&)e));
|
||||
static_assert (&e == &dynamic_cast<E&> ((B&)(CC&)e));
|
||||
static_assert (&(CC&)e == &dynamic_cast<CC&> ((B&)(CC&)e));
|
||||
|
||||
constexpr EE ee;
|
||||
constexpr bool b11 = (dynamic_cast<EE&> ((A&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .EE." "" { target *-*-* } .-1 }
|
||||
constexpr bool b12 = (dynamic_cast<EE&> ((B&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .EE." "" { target *-*-* } .-1 }
|
||||
constexpr bool b11 = (dynamic_cast<EE&> ((A&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .EE." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b12 = (dynamic_cast<EE&> ((B&)(D&)ee), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .EE." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
static_assert (&ee == &dynamic_cast<EE&> ((C&)(D&)ee));
|
||||
static_assert (&ee == &dynamic_cast<EE&> ((B&)(CC&)ee));
|
||||
static_assert (&(CC&)ee == &dynamic_cast<CC&> ((B&)(CC&)ee));
|
||||
|
|
@ -78,14 +106,17 @@ constexpr X x;
|
|||
static_assert (&x == &dynamic_cast<X&>((B&)(CC&)(E&)x));
|
||||
|
||||
constexpr XX xx;
|
||||
constexpr bool b13 = (dynamic_cast<XX&>((B&)(CC&)(E&)xx), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .XX." "" { target *-*-* } .-1 }
|
||||
constexpr bool b13 = (dynamic_cast<XX&>((B&)(CC&)(E&)xx), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .XX." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
constexpr Y y;
|
||||
constexpr bool b14 = (dynamic_cast<Y&>((B&)y), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .Y." "" { target *-*-* } .-1 }
|
||||
constexpr bool b15 = (dynamic_cast<Y&>((A&)(B&)y), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .Y." "" { target *-*-* } .-1 }
|
||||
constexpr bool b14 = (dynamic_cast<Y&>((B&)y), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const B. of its operand is a non-public base class of dynamic type .Y." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b15 = (dynamic_cast<Y&>((A&)(B&)y), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .A. of its operand is a non-public base class of dynamic type .Y." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
// 2. crosscast
|
||||
|
||||
|
|
@ -93,13 +124,16 @@ struct J { virtual void j(); };
|
|||
struct K : CC, private J {};
|
||||
class KK : J, CC{};
|
||||
|
||||
constexpr bool b16 = (dynamic_cast<CC&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .CC." "" { target *-*-* } .-1 }
|
||||
constexpr bool b16 = (dynamic_cast<CC&> ((B&)(D&)e), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .B. of its operand is a non-public base class of dynamic type .CC." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
static_assert (&(CC&)e == &dynamic_cast<CC&> ((C&)(D&)e));
|
||||
|
||||
constexpr K k;
|
||||
constexpr bool b17 = (dynamic_cast<J&> ((B&)k), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .K. of its operand does not have an unambiguous public base class .J." "" { target *-*-* } .-1 }
|
||||
constexpr bool b17 = (dynamic_cast<J&> ((B&)k), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .K. of its operand does not have an unambiguous public base class .J." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr KK kk;
|
||||
constexpr bool b18 = (dynamic_cast<J&> ((CC&)kk), true); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const CC. of its operand is a non-public base class of dynamic type .KK." "" { target *-*-* } .-1 }
|
||||
constexpr bool b18 = (dynamic_cast<J&> ((CC&)kk), true); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const CC. of its operand is a non-public base class of dynamic type .KK." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,22 @@
|
|||
// { dg-do compile { target c++20 } }
|
||||
// Here 'b' doesn't point/refer to a public base of Derived.
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Base {
|
||||
constexpr virtual ~Base(){}
|
||||
};
|
||||
|
|
@ -11,12 +27,12 @@ struct Derived: Base {
|
|||
};
|
||||
|
||||
constexpr const Derived& cast(const Base& b) {
|
||||
return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target *-*-* } .-1 }
|
||||
return dynamic_cast<const Derived&>(b); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .const Base. of its operand does not have a base class of type .Derived." "" { target c++23_down } .-1 }
|
||||
}
|
||||
|
||||
auto test() {
|
||||
static constexpr Base b;
|
||||
constexpr auto res = cast(b);
|
||||
constexpr auto res = cast(b); // { dg-error "uncaught exception" "" { target c++26 } }
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@
|
|||
|
||||
// From clang's constant-expression-cxx2a.cpp.
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
struct A2 { virtual void a2(); };
|
||||
struct A : A2 { virtual void a(); };
|
||||
struct B : A {};
|
||||
|
|
@ -26,31 +42,36 @@ static_assert(dynamic_cast<const A*>(static_cast<const C2*>(&g)) == nullptr);
|
|||
static_assert(g.f == (void*)(F*)&g);
|
||||
static_assert(dynamic_cast<const void*>(static_cast<const D*>(&g)) == &g);
|
||||
|
||||
constexpr int d_a = (dynamic_cast<const A&>(static_cast<const D&>(g)), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target *-*-* } .-1 }
|
||||
|
||||
constexpr int d_a = (dynamic_cast<const A&>(static_cast<const D&>(g)), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
// Can navigate from A2 to its A...
|
||||
static_assert(&dynamic_cast<A&>((A2&)(B&)g) == &(A&)(B&)g);
|
||||
// ... and from B to its A ...
|
||||
static_assert(&dynamic_cast<A&>((B&)g) == &(A&)(B&)g);
|
||||
// ... but not from D.
|
||||
static_assert(&dynamic_cast<A&>((D&)g) == &(A&)(B&)g); // { dg-error "non-constant condition for static assertion|reference .dynamic_cast. failed" }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target *-*-* } .-1 }
|
||||
|
||||
static_assert(&dynamic_cast<A&>((D&)g) == &(A&)(B&)g); // { dg-error "non-constant condition for static assertion" }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .G." "" { target c++23_down } .-1 }
|
||||
// { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } .-2 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-3 }
|
||||
// Can cast from A2 to sibling class D.
|
||||
static_assert(&dynamic_cast<D&>((A2&)(B&)g) == &(D&)g);
|
||||
|
||||
// Cannot cast from private base E to derived class F.
|
||||
constexpr int e_f = (dynamic_cast<F&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target *-*-* } .-1 }
|
||||
constexpr int e_f = (dynamic_cast<F&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
// Cannot cast from B to private sibling E.
|
||||
constexpr int b_e = (dynamic_cast<E&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .E." "" { target *-*-* } .-1 }
|
||||
constexpr int b_e = (dynamic_cast<E&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .E." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
struct Unrelated { virtual void unrelated(); };
|
||||
|
||||
constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .Unrelated." "" { target *-*-* } .-1 }
|
||||
constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target *-*-* } .-1 }
|
||||
constexpr int b_unrelated = (dynamic_cast<Unrelated&>((B&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .G. of its operand does not have an unambiguous public base class .Unrelated." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const E. of its operand is a non-public base class of dynamic type .G." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,22 @@
|
|||
// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// Private base.
|
||||
|
||||
struct P1 { virtual void p1(); };
|
||||
|
|
@ -12,14 +28,16 @@ struct A : B, C, private P2 { virtual void a(); };
|
|||
constexpr A a;
|
||||
|
||||
// P1 is a non-public base of A.
|
||||
constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
// Don't error here.
|
||||
static_assert (dynamic_cast<B*>((P1*)&a) == nullptr);
|
||||
|
||||
constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
static_assert (dynamic_cast<C*>((P1*)&a) == nullptr);
|
||||
static_assert (dynamic_cast<C*>((P2*)&a) == nullptr);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,22 @@
|
|||
// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// Protected base.
|
||||
|
||||
struct P1 { virtual void p1(); };
|
||||
|
|
@ -12,14 +28,16 @@ struct A : B, C, protected P2 { virtual void a(); };
|
|||
constexpr A a;
|
||||
|
||||
// P1 is a non-public base of A.
|
||||
constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b1 = (dynamic_cast<B&>((P1&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
// Don't error here.
|
||||
static_assert (dynamic_cast<B*>((P1*)&a) == nullptr);
|
||||
|
||||
constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b2 = (dynamic_cast<C&>((P2&)a), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
static_assert (dynamic_cast<C*>((P1*)&a) == nullptr);
|
||||
static_assert (dynamic_cast<C*>((P2*)&a) == nullptr);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,22 @@
|
|||
// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unrelated type.
|
||||
|
||||
struct B { virtual void b(); };
|
||||
|
|
@ -12,12 +28,15 @@ constexpr A a;
|
|||
|
||||
struct U { virtual void u(); };
|
||||
|
||||
constexpr bool b1 = (dynamic_cast<U&>((B&)a), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .U." "" { target *-*-* } .-1 }
|
||||
constexpr bool b2 = (dynamic_cast<U&>((P1&)a), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b3 = (dynamic_cast<U&>((P2&)a), 0); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target *-*-* } .-1 }
|
||||
constexpr bool b1 = (dynamic_cast<U&>((B&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "dynamic type .A. of its operand does not have an unambiguous public base class .U." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b2 = (dynamic_cast<U&>((P1&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P1. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
constexpr bool b3 = (dynamic_cast<U&>((P2&)a), 0); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message "static type .const P2. of its operand is a non-public base class of dynamic type .A." "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
static_assert (dynamic_cast<U*>((B*)&a) == nullptr);
|
||||
static_assert (dynamic_cast<U*>((P1*)&a) == nullptr);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,22 @@
|
|||
// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_cast : public exception {
|
||||
constexpr virtual ~bad_cast () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_cast"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ambiguous base.
|
||||
|
||||
struct A { virtual void a(); };
|
||||
|
|
@ -11,7 +27,8 @@ struct E : B, C, D { virtual void d(); };
|
|||
|
||||
constexpr E e;
|
||||
|
||||
constexpr bool b1 = (dynamic_cast<A&>((D&)e), false); // { dg-error "reference .dynamic_cast. failed" }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .E. of its operand" "" { target *-*-* } .-1 }
|
||||
constexpr bool b1 = (dynamic_cast<A&>((D&)e), false); // { dg-error "reference .dynamic_cast. failed" "" { target c++23_down } }
|
||||
// { dg-message ".A. is an ambiguous base class of dynamic type .E. of its operand" "" { target c++23_down } .-1 }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-2 }
|
||||
|
||||
static_assert (dynamic_cast<A*>((D*)&e) == nullptr);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
// { dg-do compile { target c++20 } }
|
||||
|
||||
#if __cpp_constexpr_exceptions >= 202411L
|
||||
namespace std {
|
||||
struct exception {
|
||||
constexpr exception () noexcept {}
|
||||
constexpr virtual ~exception () noexcept {}
|
||||
constexpr exception (const exception &) = default;
|
||||
constexpr exception &operator= (const exception &) = default;
|
||||
constexpr virtual const char *what () const noexcept { return "std::exception"; }
|
||||
};
|
||||
struct bad_alloc : public exception {
|
||||
constexpr virtual ~bad_alloc () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_alloc"; }
|
||||
};
|
||||
struct bad_array_new_length : public bad_alloc {
|
||||
constexpr virtual ~bad_array_new_length () noexcept {}
|
||||
constexpr virtual const char *what () const noexcept { return "std::bad_array_new_length"; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
constexpr int
|
||||
foo (__SIZE_TYPE__ x, int y, int z)
|
||||
{
|
||||
char (*a)[2] = new char[x][2]; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } }
|
||||
delete[] a; // { dg-message "declared here" "" { target c++23_down } .-1 }
|
||||
int *b = new int[y]; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } }
|
||||
delete[] b;
|
||||
int *c = new int[z]{1, 2, 3}; // { dg-error "call to non-'constexpr' function 'void __cxa_throw_bad_array_new_length\\\(\\\)'" "" { target c++23_down } }
|
||||
delete[] c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr int a = foo (16, 2, 3);
|
||||
constexpr int b = foo (-64, 2, 3); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-1 }
|
||||
constexpr int c = foo (16, -1, 3); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-1 }
|
||||
constexpr int d = foo (16, 2, 1); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-1 }
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// PR c++/88337 - Implement P1327R1: Allow dynamic_cast/typeid in constexpr.
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
template <class T>
|
||||
constexpr bool foo ()
|
||||
{
|
||||
bool r = false;
|
||||
const std::type_info &s = typeid( (r = true), *(T *) 0); // { dg-error "call to non-'constexpr' function 'void __cxa_bad_typeid\\\(\\\)'" "" { target c++23_down } }
|
||||
return r; // { dg-message "declared here" "" { target c++23_down } .-1 }
|
||||
}
|
||||
|
||||
struct A {};
|
||||
struct B { virtual ~B () {} };
|
||||
|
||||
static_assert (!foo <int> ());
|
||||
static_assert (!foo <A> ());
|
||||
constexpr bool a = foo <B> (); // { dg-message "in 'constexpr' expansion of" "" { target c++23_down } }
|
||||
// { dg-error "uncaught exception" "" { target c++26 } .-1 }
|
||||
|
|
@ -2050,6 +2050,15 @@ ftms = {
|
|||
};
|
||||
};
|
||||
|
||||
ftms = {
|
||||
name = constexpr_exceptions;
|
||||
values = {
|
||||
v = 202502;
|
||||
cxxmin = 26;
|
||||
extra_cond = "__cpp_constexpr_exceptions >= 202411L";
|
||||
};
|
||||
};
|
||||
|
||||
// Standard test specifications.
|
||||
stds[97] = ">= 199711L";
|
||||
stds[03] = ">= 199711L";
|
||||
|
|
|
|||
|
|
@ -2299,4 +2299,14 @@
|
|||
#endif /* !defined(__cpp_lib_bitset) && defined(__glibcxx_want_bitset) */
|
||||
#undef __glibcxx_want_bitset
|
||||
|
||||
#if !defined(__cpp_lib_constexpr_exceptions)
|
||||
# if (__cplusplus > 202302L) && (__cpp_constexpr_exceptions >= 202411L)
|
||||
# define __glibcxx_constexpr_exceptions 202502L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_exceptions)
|
||||
# define __cpp_lib_constexpr_exceptions 202502L
|
||||
# endif
|
||||
# endif
|
||||
#endif /* !defined(__cpp_lib_constexpr_exceptions) && defined(__glibcxx_want_constexpr_exceptions) */
|
||||
#undef __glibcxx_want_constexpr_exceptions
|
||||
|
||||
#undef __glibcxx_want_all
|
||||
|
|
|
|||
|
|
@ -57,8 +57,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
class bad_exception : public exception
|
||||
{
|
||||
public:
|
||||
bad_exception() _GLIBCXX_USE_NOEXCEPT { }
|
||||
_GLIBCXX26_CONSTEXPR bad_exception() _GLIBCXX_USE_NOEXCEPT { }
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~bad_exception() _GLIBCXX_TXN_SAFE_DYN noexcept {}
|
||||
|
||||
constexpr virtual const char* what() const _GLIBCXX_TXN_SAFE_DYN noexcept
|
||||
{
|
||||
return "std::bad_exception";
|
||||
}
|
||||
#else
|
||||
// This declaration is not useless:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
|
||||
virtual ~bad_exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
|
||||
|
|
@ -66,6 +74,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
// See comment in eh_exception.cc.
|
||||
virtual const char*
|
||||
what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// If you write a replacement %terminate handler, it must be of this type.
|
||||
|
|
|
|||
|
|
@ -61,19 +61,28 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
class exception
|
||||
{
|
||||
public:
|
||||
exception() _GLIBCXX_NOTHROW { }
|
||||
_GLIBCXX26_CONSTEXPR exception() _GLIBCXX_NOTHROW { }
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~exception() _GLIBCXX_TXN_SAFE_DYN noexcept {}
|
||||
#else
|
||||
virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
|
||||
#endif
|
||||
#if __cplusplus >= 201103L
|
||||
exception(const exception&) = default;
|
||||
exception& operator=(const exception&) = default;
|
||||
exception(exception&&) = default;
|
||||
exception& operator=(exception&&) = default;
|
||||
_GLIBCXX26_CONSTEXPR exception(const exception&) = default;
|
||||
_GLIBCXX26_CONSTEXPR exception& operator=(const exception&) = default;
|
||||
_GLIBCXX26_CONSTEXPR exception(exception&&) = default;
|
||||
_GLIBCXX26_CONSTEXPR exception& operator=(exception&&) = default;
|
||||
#endif
|
||||
|
||||
/** Returns a C-style character string describing the general cause
|
||||
* of the current error. */
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual const char*
|
||||
what() const _GLIBCXX_TXN_SAFE_DYN noexcept { return "std::exception"; }
|
||||
#else
|
||||
virtual const char*
|
||||
what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
exception_ptr current_exception() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
template<typename _Ex>
|
||||
exception_ptr make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT;
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr make_exception_ptr(_Ex)
|
||||
_GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
/// Throw the object pointed to by the exception_ptr.
|
||||
void rethrow_exception(exception_ptr) __attribute__ ((__noreturn__));
|
||||
|
|
@ -105,7 +106,25 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
{
|
||||
void* _M_exception_object;
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr explicit exception_ptr(void* __e) noexcept
|
||||
: _M_exception_object(__e)
|
||||
{
|
||||
if (_M_exception_object)
|
||||
{
|
||||
#if __cpp_if_consteval >= 202106L \
|
||||
&& _GLIBCXX_HAS_BUILTIN(__builtin_eh_ptr_adjust_ref)
|
||||
if consteval {
|
||||
__builtin_eh_ptr_adjust_ref(_M_exception_object, 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_M_addref();
|
||||
}
|
||||
}
|
||||
#else
|
||||
explicit exception_ptr(void* __e) _GLIBCXX_USE_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
void _M_addref() _GLIBCXX_USE_NOEXCEPT;
|
||||
void _M_release() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
|
@ -115,7 +134,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
friend exception_ptr std::current_exception() _GLIBCXX_USE_NOEXCEPT;
|
||||
friend void std::rethrow_exception(exception_ptr);
|
||||
template<typename _Ex>
|
||||
friend exception_ptr std::make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT;
|
||||
friend _GLIBCXX26_CONSTEXPR exception_ptr std::make_exception_ptr(_Ex)
|
||||
_GLIBCXX_USE_NOEXCEPT;
|
||||
#if __cpp_lib_exception_ptr_cast >= 202506L
|
||||
template<typename _Ex>
|
||||
friend const _Ex* std::exception_ptr_cast(const exception_ptr&) noexcept;
|
||||
|
|
@ -125,16 +145,17 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
_GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
public:
|
||||
exception_ptr() _GLIBCXX_USE_NOEXCEPT;
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
exception_ptr(const exception_ptr&) _GLIBCXX_USE_NOEXCEPT;
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr(const exception_ptr&)
|
||||
_GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
exception_ptr(nullptr_t) noexcept
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr(nullptr_t) noexcept
|
||||
: _M_exception_object(nullptr)
|
||||
{ }
|
||||
|
||||
exception_ptr(exception_ptr&& __o) noexcept
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr(exception_ptr&& __o) noexcept
|
||||
: _M_exception_object(__o._M_exception_object)
|
||||
{ __o._M_exception_object = nullptr; }
|
||||
#endif
|
||||
|
|
@ -146,11 +167,11 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
exception_ptr(__safe_bool) _GLIBCXX_USE_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
exception_ptr&
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr&
|
||||
operator=(const exception_ptr&) _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
exception_ptr&
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr&
|
||||
operator=(exception_ptr&& __o) noexcept
|
||||
{
|
||||
exception_ptr(static_cast<exception_ptr&&>(__o)).swap(*this);
|
||||
|
|
@ -158,9 +179,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
}
|
||||
#endif
|
||||
|
||||
~exception_ptr() _GLIBCXX_USE_NOEXCEPT;
|
||||
_GLIBCXX26_CONSTEXPR ~exception_ptr() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
void
|
||||
_GLIBCXX26_CONSTEXPR void
|
||||
swap(exception_ptr&) _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
#ifdef _GLIBCXX_EH_PTR_COMPAT
|
||||
|
|
@ -172,13 +193,13 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
explicit operator bool() const noexcept
|
||||
_GLIBCXX26_CONSTEXPR explicit operator bool() const noexcept
|
||||
{ return _M_exception_object; }
|
||||
#endif
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201907L \
|
||||
&& ! defined _GLIBCXX_EH_PTR_RELOPS_COMPAT
|
||||
friend bool
|
||||
_GLIBCXX26_CONSTEXPR friend bool
|
||||
operator==(const exception_ptr&, const exception_ptr&) noexcept = default;
|
||||
#else
|
||||
friend _GLIBCXX_EH_PTR_USED bool
|
||||
|
|
@ -198,31 +219,49 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
};
|
||||
|
||||
_GLIBCXX_EH_PTR_USED
|
||||
inline
|
||||
_GLIBCXX26_CONSTEXPR inline
|
||||
exception_ptr::exception_ptr() _GLIBCXX_USE_NOEXCEPT
|
||||
: _M_exception_object(0)
|
||||
{ }
|
||||
|
||||
_GLIBCXX_EH_PTR_USED
|
||||
inline
|
||||
_GLIBCXX26_CONSTEXPR inline
|
||||
exception_ptr::exception_ptr(const exception_ptr& __other)
|
||||
_GLIBCXX_USE_NOEXCEPT
|
||||
: _M_exception_object(__other._M_exception_object)
|
||||
{
|
||||
if (_M_exception_object)
|
||||
_M_addref();
|
||||
{
|
||||
#if __cpp_if_consteval >= 202106L \
|
||||
&& _GLIBCXX_HAS_BUILTIN(__builtin_eh_ptr_adjust_ref)
|
||||
if consteval {
|
||||
__builtin_eh_ptr_adjust_ref(_M_exception_object, 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_M_addref();
|
||||
}
|
||||
}
|
||||
|
||||
_GLIBCXX_EH_PTR_USED
|
||||
inline
|
||||
_GLIBCXX26_CONSTEXPR inline
|
||||
exception_ptr::~exception_ptr() _GLIBCXX_USE_NOEXCEPT
|
||||
{
|
||||
if (_M_exception_object)
|
||||
_M_release();
|
||||
{
|
||||
#if __cpp_if_consteval >= 202106L \
|
||||
&& _GLIBCXX_HAS_BUILTIN(__builtin_eh_ptr_adjust_ref)
|
||||
if consteval {
|
||||
__builtin_eh_ptr_adjust_ref(_M_exception_object, -1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_M_release();
|
||||
}
|
||||
}
|
||||
|
||||
_GLIBCXX_EH_PTR_USED
|
||||
inline exception_ptr&
|
||||
_GLIBCXX26_CONSTEXPR inline exception_ptr&
|
||||
exception_ptr::operator=(const exception_ptr& __other) _GLIBCXX_USE_NOEXCEPT
|
||||
{
|
||||
exception_ptr(__other).swap(*this);
|
||||
|
|
@ -230,7 +269,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
}
|
||||
|
||||
_GLIBCXX_EH_PTR_USED
|
||||
inline void
|
||||
_GLIBCXX26_CONSTEXPR inline void
|
||||
exception_ptr::swap(exception_ptr &__other) _GLIBCXX_USE_NOEXCEPT
|
||||
{
|
||||
void *__tmp = _M_exception_object;
|
||||
|
|
@ -239,7 +278,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
}
|
||||
|
||||
/// @relates exception_ptr
|
||||
inline void
|
||||
_GLIBCXX26_CONSTEXPR inline void
|
||||
swap(exception_ptr& __lhs, exception_ptr& __rhs)
|
||||
{ __lhs.swap(__rhs); }
|
||||
|
||||
|
|
@ -258,9 +297,21 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
/// Obtain an exception_ptr pointing to a copy of the supplied object.
|
||||
#if (__cplusplus >= 201103L && __cpp_rtti) || __cpp_exceptions
|
||||
template<typename _Ex>
|
||||
exception_ptr
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr
|
||||
make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT
|
||||
{
|
||||
#if __cplusplus >= 202400L
|
||||
if consteval {
|
||||
try
|
||||
{
|
||||
throw __ex;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return current_exception();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if __cplusplus >= 201103L && __cpp_rtti
|
||||
using _Ex2 = typename decay<_Ex>::type;
|
||||
void* __e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex));
|
||||
|
|
@ -293,7 +344,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
// instead of a working one compiled with RTTI and/or exceptions enabled.
|
||||
template<typename _Ex>
|
||||
__attribute__ ((__always_inline__))
|
||||
inline exception_ptr
|
||||
_GLIBCXX26_CONSTEXPR inline exception_ptr
|
||||
make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT
|
||||
{ return exception_ptr(); }
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,17 +62,24 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
|
||||
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
|
||||
constexpr virtual ~nested_exception() noexcept {}
|
||||
#else
|
||||
virtual ~nested_exception() noexcept;
|
||||
#endif
|
||||
|
||||
/// Rethrow the stored exception, or terminate if none was stored.
|
||||
[[noreturn]]
|
||||
void
|
||||
_GLIBCXX26_CONSTEXPR void
|
||||
rethrow_nested() const
|
||||
{
|
||||
if (_M_ptr)
|
||||
|
|
@ -81,7 +88,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
}
|
||||
|
||||
/// Access the stored exception.
|
||||
exception_ptr
|
||||
_GLIBCXX26_CONSTEXPR exception_ptr
|
||||
nested_ptr() const noexcept
|
||||
{ return _M_ptr; }
|
||||
};
|
||||
|
|
@ -91,11 +98,11 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
template<typename _Except>
|
||||
struct _Nested_exception : public _Except, public nested_exception
|
||||
{
|
||||
explicit _Nested_exception(const _Except& __ex)
|
||||
_GLIBCXX26_CONSTEXPR explicit _Nested_exception(const _Except& __ex)
|
||||
: _Except(__ex)
|
||||
{ }
|
||||
|
||||
explicit _Nested_exception(_Except&& __ex)
|
||||
_GLIBCXX26_CONSTEXPR explicit _Nested_exception(_Except&& __ex)
|
||||
: _Except(static_cast<_Except&&>(__ex))
|
||||
{ }
|
||||
};
|
||||
|
|
@ -144,7 +151,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
*/
|
||||
template<typename _Tp>
|
||||
[[noreturn]]
|
||||
inline void
|
||||
_GLIBCXX26_CONSTEXPR inline void
|
||||
throw_with_nested(_Tp&& __t)
|
||||
{
|
||||
using _Up = typename decay<_Tp>::type;
|
||||
|
|
@ -204,7 +211,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
# if ! __cpp_rtti
|
||||
[[__gnu__::__always_inline__]]
|
||||
#endif
|
||||
inline void
|
||||
_GLIBCXX26_CONSTEXPR inline void
|
||||
rethrow_if_nested(const _Ex& __ex)
|
||||
{
|
||||
const _Ex* __ptr = __builtin_addressof(__ex);
|
||||
|
|
|
|||
|
|
@ -66,33 +66,51 @@ namespace std
|
|||
class bad_alloc : public exception
|
||||
{
|
||||
public:
|
||||
bad_alloc() throw() { }
|
||||
_GLIBCXX26_CONSTEXPR bad_alloc() throw() { }
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
bad_alloc(const bad_alloc&) = default;
|
||||
bad_alloc& operator=(const bad_alloc&) = default;
|
||||
_GLIBCXX26_CONSTEXPR bad_alloc(const bad_alloc&) = default;
|
||||
_GLIBCXX26_CONSTEXPR bad_alloc& operator=(const bad_alloc&) = default;
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~bad_alloc() noexcept {}
|
||||
|
||||
constexpr virtual const char* what() const noexcept
|
||||
{
|
||||
return "std::bad_alloc";
|
||||
}
|
||||
#else
|
||||
// This declaration is not useless:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
|
||||
virtual ~bad_alloc() throw();
|
||||
|
||||
// See comment in eh_exception.cc.
|
||||
virtual const char* what() const throw();
|
||||
#endif
|
||||
};
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
class bad_array_new_length : public bad_alloc
|
||||
{
|
||||
public:
|
||||
bad_array_new_length() throw() { }
|
||||
_GLIBCXX26_CONSTEXPR bad_array_new_length() throw() { }
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~bad_array_new_length() noexcept {}
|
||||
|
||||
constexpr virtual const char* what() const noexcept
|
||||
{
|
||||
return "std::bad_array_new_length";
|
||||
}
|
||||
#else
|
||||
// This declaration is not useless:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
|
||||
virtual ~bad_array_new_length() throw();
|
||||
|
||||
// See comment in eh_exception.cc.
|
||||
virtual const char* what() const throw();
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -224,14 +224,23 @@ namespace std
|
|||
class bad_cast : public exception
|
||||
{
|
||||
public:
|
||||
bad_cast() _GLIBCXX_USE_NOEXCEPT { }
|
||||
_GLIBCXX26_CONSTEXPR bad_cast() _GLIBCXX_USE_NOEXCEPT { }
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~bad_cast() noexcept {}
|
||||
|
||||
constexpr virtual const char* what() const noexcept
|
||||
{
|
||||
return "std::bad_cast";
|
||||
}
|
||||
#else
|
||||
// This declaration is not useless:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
|
||||
virtual ~bad_cast() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
// See comment in eh_exception.cc.
|
||||
virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -241,14 +250,23 @@ namespace std
|
|||
class bad_typeid : public exception
|
||||
{
|
||||
public:
|
||||
bad_typeid () _GLIBCXX_USE_NOEXCEPT { }
|
||||
_GLIBCXX26_CONSTEXPR bad_typeid () _GLIBCXX_USE_NOEXCEPT { }
|
||||
|
||||
#if __cplusplus >= 202400L
|
||||
constexpr virtual ~bad_typeid() noexcept {}
|
||||
|
||||
constexpr virtual const char* what() const noexcept
|
||||
{
|
||||
return "std::bad_typeid";
|
||||
}
|
||||
#else
|
||||
// This declaration is not useless:
|
||||
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
|
||||
virtual ~bad_typeid() _GLIBCXX_USE_NOEXCEPT;
|
||||
|
||||
// See comment in eh_exception.cc.
|
||||
virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
|
||||
#endif
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue