aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog619
-rw-r--r--gcc/cp/call.cc109
-rw-r--r--gcc/cp/class.cc4
-rw-r--r--gcc/cp/constexpr.cc1860
-rw-r--r--gcc/cp/constraint.cc272
-rw-r--r--gcc/cp/coroutines.cc39
-rw-r--r--gcc/cp/cp-gimplify.cc20
-rw-r--r--gcc/cp/cp-trait.def3
-rw-r--r--gcc/cp/cp-tree.h135
-rw-r--r--gcc/cp/cvt.cc13
-rw-r--r--gcc/cp/decl.cc93
-rw-r--r--gcc/cp/error.cc112
-rw-r--r--gcc/cp/except.cc30
-rw-r--r--gcc/cp/expr.cc14
-rw-r--r--gcc/cp/init.cc6
-rw-r--r--gcc/cp/lambda.cc18
-rw-r--r--gcc/cp/method.cc230
-rw-r--r--gcc/cp/module.cc138
-rw-r--r--gcc/cp/name-lookup.cc2
-rw-r--r--gcc/cp/parser.cc376
-rw-r--r--gcc/cp/pt.cc104
-rw-r--r--gcc/cp/semantics.cc105
-rw-r--r--gcc/cp/tree.cc374
-rw-r--r--gcc/cp/typeck.cc57
-rw-r--r--gcc/cp/typeck2.cc20
25 files changed, 3899 insertions, 854 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 38a2d68..3f76afd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,622 @@
+2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/108080
+ * module.cc (trees_out::core_vals): Warn when streaming
+ target/optimize node; adjust comments.
+ (trees_in::core_vals): Don't stream a target/optimize node.
+
+2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/121238
+ * module.cc (trees_in::fn_parms_fini): Merge properties for
+ definitions.
+
+2025-07-31 Jason Merrill <jason@redhat.com>
+
+ PR c++/120800
+ * constexpr.cc (cxx_eval_vec_init_1): Suppress access control.
+
+2025-07-31 Marek Polacek <polacek@redhat.com>
+
+ PR c++/120775
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Use
+ extract_call_expr.
+ * cp-tree.h (CONSTEVAL_BLOCK_P, LAMBDA_EXPR_CONSTEVAL_BLOCK_P): Define.
+ (finish_static_assert): Adjust declaration.
+ (current_nonlambda_function): Likewise.
+ * lambda.cc (current_nonlambda_function): New parameter. Only keep
+ iterating if the function represents a consteval block.
+ * parser.cc (cp_parser_lambda_expression): New parameter for
+ consteval blocks. Use it. Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P.
+ (cp_parser_lambda_declarator_opt): Likewise.
+ (build_empty_string): New.
+ (cp_parser_next_tokens_are_consteval_block_p): New.
+ (cp_parser_consteval_block): New.
+ (cp_parser_block_declaration): Handle consteval blocks.
+ (cp_parser_static_assert): Use build_empty_string.
+ (cp_parser_member_declaration): Handle consteval blocks.
+ * pt.cc (tsubst_stmt): Adjust a call to finish_static_assert.
+ * semantics.cc (finish_fname): Warn for consteval blocks.
+ (finish_static_assert): New parameter for consteval blocks. Set
+ CONSTEVAL_BLOCK_P. Evaluate consteval blocks specially.
+
+2025-07-30 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/121291
+ * constraint.cc (diagnose_trait_expr): Remove assumption about
+ failures returning error_mark_node.
+ * except.cc (explain_not_noexcept): Allow expr not being
+ noexcept.
+ * method.cc (build_invoke): Adjust comment.
+ (is_trivially_xible): Always note non-trivial components if expr
+ is not null or error_mark_node.
+ (is_nothrow_xible): Likewise for non-noexcept components.
+ (is_nothrow_convertible): Likewise.
+
+2025-07-30 Jason Merrill <jason@redhat.com>
+
+ * pt.cc (convert_nontype_argument_function): Check
+ cxx_constant_value on failure.
+ (invalid_tparm_referent_p): Likewise.
+
+2025-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121133
+ * parser.cc (cp_parser_unary_expression): Adjust
+ cp_parser_extension_opt caller and restore warn_long_long.
+ (cp_parser_declaration): Likewise.
+ (cp_parser_block_declaration): Likewise.
+ (cp_parser_member_declaration): Likewise.
+ (cp_parser_extension_opt): Add SAVED_LONG_LONG argument,
+ save previous warn_long_long state into it and clear it
+ for __extension__.
+
+2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * cp-tree.h (struct lang_type): Add comment mentioning modules.
+ * module.cc (trees_out::lang_type_bools): Stream new flags, use
+ gcc_checking_assert.
+ (trees_in::lang_type_bools): Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * constexpr.cc: Update usage of "diagnostic_info" to explicitly
+ refer to "diagnostics::diagnostic_info".
+ * cp-tree.h: Likewise.
+ * error.cc: Likewise.
+ * module.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * call.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * constexpr.cc: Likewise.
+ * cp-tree.h: Likewise.
+ * decl.cc: Likewise.
+ * error.cc: Likewise.
+ * init.cc: Likewise.
+ * method.cc: Likewise.
+ * module.cc: Likewise.
+ * parser.cc: Likewise.
+ * pt.cc: Likewise.
+ * semantics.cc: Likewise.
+ * typeck.cc: Likewise.
+ * typeck2.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for renaming of diagnostic_option_id to
+ diagnostics::option_id.
+ * decl.cc: Likewise.
+ * error.cc: Likewise.
+ * name-lookup.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update for move of diagnostic-color.h to
+ diagnostics/color.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for diagnostic_context becoming
+ diagnostics::context.
+ * error.cc: Likewise.
+ * module.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * constexpr.cc: Update to add "m_" prefix to fields of
+ diagnostic_info throughout.
+ * error.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for move of diagnostics output formats into
+ namespace "diagnostics" as "sinks".
+ * error.cc: Likewise.
+
+2025-07-25 Patrick Palka <ppalka@redhat.com>
+
+ * call.cc (build_new_op): If the selected candidate is
+ rewritten, communicate the LOOKUP_REWRITTEN/REVERSED flags to
+ the caller via the 'overload' out-parameter, and stop clearing
+ '*overload' in that case.
+ * tree.cc (build_min_non_dep_op_overload): Handle rebuilding all
+ C++20 rewritten comparison operator expressions.
+
+2025-07-25 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/121219
+ * coroutines.cc
+ (cp_coroutine_transform::build_ramp_function): Reorder the return
+ expressions for the 'normal' and 'allocation failed' cases so that
+ NRV constraints are met.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/117294
+ PR c++/113854
+ * call.cc (implicit_conversion_error): Hide label when printing
+ a stub object.
+ (convert_like_internal): Likewise, and nest candidate
+ diagnostics.
+ * constexpr.cc (diagnose_failing_condition): Nest diagnostics,
+ attempt to provide more helpful diagnostics for traits.
+ * constraint.cc (satisfy_atom): Pass result before constant
+ evaluation to diagnose_atomic_constraint.
+ (diagnose_trait_expr): Adjust diagnostics for clarity and
+ detail.
+ (maybe_diagnose_standard_trait): New function.
+ (diagnose_atomic_constraint): Attempt to provide more helpful
+ diagnostics for more traits.
+ * cp-tree.h (explain_not_noexcept): Declare new function.
+ (is_trivially_xible): Add parameter.
+ (is_nothrow_xible): Likewise.
+ (is_xible): Likewise.
+ (is_convertible): Likewise.
+ (is_nothrow_convertible): Likewise.
+ (diagnose_trait_expr): Declare new function.
+ (maybe_diagnose_standard_trait): Declare new function.
+ * error.cc (dump_type) <case TREE_VEC>: Handle trait types.
+ * except.cc (explain_not_noexcept): New function.
+ * method.cc (build_trait_object): Add complain parameter.
+ (build_invoke): Propagate complain parameter.
+ (assignable_expr): Add explain parameter to show diagnostics.
+ (constructible_expr): Likewise.
+ (destructible_expr): Likewise.
+ (is_xible_helper): Replace trivial flag with explain flag,
+ add diagnostics.
+ (is_trivially_xible): New explain flag.
+ (is_nothrow_xible): Likewise.
+ (is_xible): Likewise.
+ (is_convertible_helper): Add complain flag.
+ (is_convertible): New explain flag.
+ (is_nothrow_convertible): Likewise.
+ * typeck.cc (cp_build_function_call_vec): Add handling for stub
+ objects.
+ (convert_arguments): Always return -1 on error.
+ * typeck2.cc (cxx_readonly_error): Add handling for stub
+ objects.
+
+2025-07-24 Jason Merrill <jason@redhat.com>
+
+ * pt.cc (tsubst_lambda_expr): Revert r9-5971 change.
+
+2025-07-24 Jason Merrill <jason@redhat.com>
+
+ PR c++/114632
+ PR c++/101233
+ * lambda.cc (maybe_add_lambda_conv_op): Not for xobj lambda.
+ * pt.cc (tsubst_function_decl): Add cp_evaluated.
+ (alias_ctad_tweaks): Revert PR101233 fix.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120412
+ * module.cc (trees_out::core_vals): Write TU_LOCAL_ENTITY bits.
+ (trees_in::core_vals): Read it.
+ (trees_in::tree_node): Handle TU_LOCAL_ENTITY typedefs.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121179
+ * call.cc (build_new_op): Don't clear *overload for a simple
+ != to == rewrite.
+ * tree.cc (build_min_non_dep_op_overload): Handle TRUTH_NOT_EXPR
+ appearing in a rewritten operator expression.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121055
+ * method.cc (build_invoke): Correct reference_wrapper handling.
+
+2025-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/121068
+ * constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs
+ when activating an array member of a union.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * semantics.cc (finish_asm_stmt): Pass null pointer to
+ parse_{input,output}_constraint().
+
+2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com>
+
+ * pt.cc (tsubst_omp_clause_decl): Use OMP_ITERATOR_DECL_P.
+ * semantics.cc (handle_omp_array_sections): Likewise.
+ (finish_omp_clauses): Likewise.
+
+2025-07-16 Alfie Richards <alfie.richards@arm.com>
+
+ * class.cc (add_method): Remove argument.
+ * cp-tree.h (maybe_version_functions): Ditto.
+ * decl.cc (decls_match): Ditto.
+ (maybe_version_functions): Ditto.
+
+2025-07-16 Jeremy Rifkin <jeremy@rifkin.dev>
+
+ PR c/82134
+ * call.cc (build_call_a): Add suppress_warning
+ * cp-gimplify.cc (cp_gimplify_expr): Add suppress_warning
+
+2025-07-15 Jason Merrill <jason@redhat.com>
+
+ PR c++/44677
+ * cp-gimplify.cc (cp_fold) [CLEANUP_POINT_EXPR]: Don't force rvalue.
+ [COMPOUND_EXPR]: Likewise.
+ * cvt.cc (convert_to_void): Call mark_exp_read later.
+ * expr.cc (mark_use): Turn off read_p for any void argument.
+ (mark_exp_read): Return early for void argument.
+
+2025-07-15 Jason Merrill <jason@redhat.com>
+
+ PR c++/120577
+ * constexpr.cc (cxx_eval_call_expression): Set
+ CONSTRUCTOR_NO_CLEARING on initial value for ctor.
+ (cxx_eval_component_reference): Make value-initialization
+ of an aggregate member explicit.
+
+2025-07-15 Jakub Jelinek <jakub@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR c/44677
+ * cp-gimplify.cc (cp_fold): Clear DECL_READ_P on lhs of MODIFY_EXPR
+ after cp_fold_rvalue if it wasn't set before.
+ * decl.cc (poplevel): Use OPT_Wunused_but_set_variable_
+ instead of OPT_Wunused_but_set_variable.
+ (finish_function): Use OPT_Wunused_but_set_parameter_
+ instead of OPT_Wunused_but_set_parameter.
+ * expr.cc (mark_use): Clear read_p for {PRE,POST}{IN,DE}CREMENT_EXPR
+ cast to void on {VAR,PARM}_DECL for
+ -Wunused-but-set-{parameter,variable}={2,3}.
+ (mark_exp_read): Handle {PRE,POST}{IN,DE}CREMENT_EXPR and don't handle
+ it when cast to void.
+ * module.cc (trees_in::fn_parms_fini): Remove unused but set variable
+ ix.
+ * semantics.cc (finish_unary_op_expr): Return early for
+ PRE{IN,DE}CREMENT_EXPR.
+ * typeck.cc (cp_build_unary_op): Clear DECL_READ_P
+ after mark_lvalue_use for -Wunused-but-set-{parameter,variable}={2,3}
+ on PRE{IN,DE}CREMENT_EXPR argument.
+ (cp_build_modify_expr): Clear DECL_READ_P after cp_build_binary_op
+ for -Wunused-but-set-{parameter,variable}=3.
+
+2025-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119064
+ * cp-tree.h: Implement C++26 P2786R13 - Trivial Relocatability.
+ (struct lang_type): Add trivially_relocatable,
+ trivially_relocatable_computed, replaceable and replaceable_computed
+ bitfields. Change width of dummy from 2 to 30.
+ (CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT,
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, CLASSTYPE_REPLACEABLE_BIT,
+ CLASSTYPE_REPLACEABLE_COMPUTED): Define.
+ (enum virt_specifier): Add VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
+ and VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE enumerators.
+ (trivially_relocatable_type_p, replaceable_type_p): Declare.
+ * cp-trait.def (IS_NOTHROW_RELOCATABLE, IS_REPLACEABLE,
+ IS_TRIVIALLY_RELOCATABLE): New traits.
+ * parser.cc (cp_parser_class_property_specifier_seq_opt): Handle
+ trivially_relocatable_if_eligible,
+ __trivially_relocatable_if_eligible, replaceable_if_eligible and
+ __replaceable_if_eligible.
+ (cp_parser_class_head): Set CLASSTYPE_REPLACEABLE_BIT
+ and/or CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT if corresponding
+ conditional keywords were parsed and assert corresponding *_COMPUTED
+ macro is false.
+ * pt.cc (instantiate_class_template): Copy over also
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_{BIT,COMPUTED} and
+ CLASSTYPE_REPLACEABLE_{BIT,COMPUTED} bits.
+ * semantics.cc (referenceable_type_p): Move definition earlier.
+ (trait_expr_value): Handle CPTK_IS_NOTHROW_RELOCATABLE,
+ CPTK_IS_REPLACEABLE and CPTK_IS_TRIVIALLY_RELOCATABLE.
+ (finish_trait_expr): Likewise.
+ * tree.cc (default_movable_type_p): New function.
+ (union_with_no_declared_special_member_fns): Likewise.
+ (trivially_relocatable_type_p): Likewise.
+ (replaceable_type_p): Likewise.
+ * constraint.cc (diagnose_trait_expr): Handle
+ CPTK_IS_NOTHROW_RELOCATABLE, CPTK_IS_REPLACEABLE and
+ CPTK_IS_TRIVIALLY_RELOCATABLE.
+
+2025-07-10 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-tree.h (struct lang_type): Add comment before key_method.
+ Remove lambda_expr.
+ (CLASSTYPE_KEY_METHOD): Give NULL_TREE if not TYPE_POLYMORPHIC_P.
+ (SET_CLASSTYPE_KEY_METHOD): Define.
+ (CLASSTYPE_LAMBDA_EXPR): Give NULL_TREE if TYPE_POLYMORPHIC_P.
+ Use key_method member instead of lambda_expr.
+ (SET_CLASSTYPE_LAMBDA_EXPR): Define.
+ * class.cc (determine_key_method): Use SET_CLASSTYPE_KEY_METHOD
+ macro.
+ * decl.cc (xref_tag): Use SET_CLASSTYPE_LAMBDA_EXPR macro.
+ * lambda.cc (begin_lambda_type): Likewise.
+ * module.cc (trees_in::read_class_def): Use SET_CLASSTYPE_LAMBDA_EXPR
+ and SET_CLASSTYPE_KEY_METHOD macros, assert lambda is NULL if
+ TYPE_POLYMORPHIC_P and otherwise assert key_method is NULL.
+
+2025-07-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120628
+ * parser.cc (cp_parser_elaborated_type_specifier): Use
+ cp_parser_nth_token_starts_class_definition_p with extra argument 1
+ instead of cp_parser_next_token_starts_class_definition_p.
+ (cp_parser_class_property_specifier_seq_opt): For final conditional
+ keyword in C++98 check if the token after it isn't
+ cp_parser_nth_token_starts_class_definition_p nor CPP_NAME and in
+ that case break without consuming it nor warning.
+ (cp_parser_class_head): Use
+ cp_parser_nth_token_starts_class_definition_p with extra argument 1
+ instead of cp_parser_next_token_starts_class_definition_p.
+ (cp_parser_next_token_starts_class_definition_p): Renamed to ...
+ (cp_parser_nth_token_starts_class_definition_p): ... this. Add N
+ argument. Use cp_lexer_peek_nth_token instead of cp_lexer_peek_token.
+
+2025-07-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120569
+ * parser.cc (cp_parser_class_property_specifier_seq_opt): New
+ function.
+ (cp_parser_class_head): Use it instead of
+ cp_parser_property_specifier_seq_opt. Don't diagnose
+ VIRT_SPEC_OVERRIDE here. Formatting fix.
+
+2025-07-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117785
+ * 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.
+
+2025-07-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/121012
+ PR c++/120917
+ * parser.cc (cp_parser_lambda_expression): Clear
+ parser->in_template_argument_list_p.
+
+2025-07-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/121008
+ PR c++/113563
+ * semantics.cc (finish_this_expr): Do check current_class_ref for
+ non-lambda.
+
+2025-07-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/119838
+ * parser.cc (cp_parser_nested_name_specifier_opt): New global_p
+ parameter. Look for "template" when global_p is true.
+ (cp_parser_simple_type_specifier): Pass global_p to
+ cp_parser_nested_name_specifier_opt.
+
+2025-07-08 Marek Polacek <polacek@redhat.com>
+ Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR c++/83469
+ PR c++/93809
+ * cp-tree.h (UNION_TYPE_P): Define.
+ (TYPENAME_IS_UNION_P): Define.
+ * decl.cc (struct typename_info): Add union_p field.
+ (struct typename_hasher::equal): Compare union_p field.
+ (build_typename_type): Use ti.union_p for union_type. Set
+ TYPENAME_IS_UNION_P.
+ * error.cc (dump_type) <case TYPENAME_TYPE>: Handle
+ TYPENAME_IS_UNION_P.
+ * module.cc (trees_out::type_node): Likewise.
+ * parser.cc (cp_parser_check_class_key): Allow typename key for union
+ types and allow union keyword for typename types.
+ * pt.cc (tsubst) <case TYPENAME_TYPE>: Don't conflate unions with
+ class_type. For TYPENAME_IS_CLASS_P, check NON_UNION_CLASS_TYPE_P
+ rather than CLASS_TYPE_P. Add TYPENAME_IS_UNION_P handling.
+
+2025-07-08 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117784
+ * decl.cc: Implement part of C++26 P2686R4 - constexpr structured
+ bindings.
+ (cp_finish_decl): Pedwarn for C++23 and older on constinit on
+ structured bindings except for static/thread_local where it uses
+ earlier error.
+ (grokdeclarator): Pedwarn on constexpr structured bindings for
+ C++23 and older instead of emitting error always, don't clear
+ constexpr_p in that case.
+ * parser.cc (cp_parser_decomposition_declaration): Copy over
+ DECL_DECLARED_CONSTEXPR_P and DECL_DECLARED_CONSTINIT_P flags.
+
2025-07-07 Alfie Richards <alfie.richards@arm.com>
PR c++/119498
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 2c3ef3d..9283d97 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -220,7 +220,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
bool, tree, tree, int, struct z_candidate **,
tsubst_flags_t);
static conversion *merge_conversion_sequences (conversion *, conversion *);
-static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
+static tree build_temp (tree, tree, int, enum diagnostics::kind *,
+ tsubst_flags_t);
static conversion *build_identity_conv (tree, tree);
static inline bool conv_binds_to_array_of_unknown_bound (conversion *);
static bool conv_is_prvalue (conversion *);
@@ -412,6 +413,7 @@ build_call_a (tree function, int n, tree *argarray)
/* We're disconnecting the initializer from its target,
don't create a temporary. */
arg = TARGET_EXPR_INITIAL (arg);
+ suppress_warning (arg, OPT_Wunused_result);
tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
CALL_EXPR_ARG (function, i) = arg;
@@ -1723,6 +1725,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. */
@@ -4876,6 +4928,11 @@ implicit_conversion_error (location_t loc, tree type, tree expr)
&& !CP_AGGREGATE_TYPE_P (type))
error_at (loc, "designated initializers cannot be used with a "
"non-aggregate type %qT", type);
+ else if (is_stub_object (expr))
+ /* The expression is generated by a trait check, we don't have
+ a useful location to highlight the label. */
+ error_at (loc, "could not convert %qH to %qI",
+ TREE_TYPE (expr), type);
else
{
range_label_for_type_mismatch label (TREE_TYPE (expr), type);
@@ -6404,7 +6461,9 @@ build_conditional_expr (const op_location_t &loc,
types when the enumeration is still being defined. */;
else if (complain & (cxx_dialect >= cxx26
? tf_warning_or_error : tf_warning))
- emit_diagnostic (cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
loc, OPT_Wenum_compare, "enumerated mismatch "
"in conditional expression: %qT vs %qT",
arg2_type, arg3_type);
@@ -7435,7 +7494,16 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
{
if (overload)
- *overload = cand->fn;
+ {
+ if (cand->rewritten ())
+ /* build_min_non_dep_op_overload needs to know whether the
+ candidate is rewritten/reversed. */
+ *overload = build_tree_list (build_int_cst (integer_type_node,
+ cand->flags),
+ cand->fn);
+ else
+ *overload = cand->fn;
+ }
if (resolve_args (arglist, complain) == NULL)
result = error_mark_node;
@@ -7484,9 +7552,6 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
/* If this was a C++20 rewritten comparison, adjust the result. */
if (cand->rewritten ())
{
- /* FIXME build_min_non_dep_op_overload can't handle rewrites. */
- if (overload)
- *overload = NULL_TREE;
switch (code)
{
case EQ_EXPR:
@@ -7585,8 +7650,9 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
&& (complain & tf_warning_or_error) == 0)
result = error_mark_node;
else if (cxx_dialect >= cxx26 || (complain & tf_warning))
- emit_diagnostic (cxx_dialect >= cxx26
- ? DK_PEDWARN : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
loc, OPT_Wenum_compare,
"comparison between %q#T and %q#T",
arg1_type, arg2_type);
@@ -8400,11 +8466,11 @@ complain_about_access (tree decl, tree diag_decl, tree diag_location,
static tree
build_temp (tree expr, tree type, int flags,
- diagnostic_t *diagnostic_kind, tsubst_flags_t complain)
+ enum diagnostics::kind *diagnostic_kind, tsubst_flags_t complain)
{
int savew, savee;
- *diagnostic_kind = DK_UNSPECIFIED;
+ *diagnostic_kind = diagnostics::kind::unspecified;
/* If the source is a packed field, calling the copy constructor will require
binding the field to the reference parameter to the copy constructor, and
@@ -8428,9 +8494,9 @@ build_temp (tree expr, tree type, int flags,
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
&args, type, flags, complain);
if (warningcount + werrorcount > savew)
- *diagnostic_kind = DK_WARNING;
+ *diagnostic_kind = diagnostics::kind::warning;
else if (errorcount > savee)
- *diagnostic_kind = DK_ERROR;
+ *diagnostic_kind = diagnostics::kind::error;
return expr;
}
@@ -8642,9 +8708,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
bool nested_p, tsubst_flags_t complain)
{
tree totype = convs->type;
- diagnostic_t diag_kind;
+ enum diagnostics::kind diag_kind;
int flags;
location_t loc = cp_expr_loc_or_input_loc (expr);
+ const bool stub_object_p = is_stub_object (expr);
if (convs->bad_p && !(complain & tf_error))
return error_mark_node;
@@ -8721,7 +8788,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
"from %qH to %qI", TREE_TYPE (expr),
totype);
if (complained)
- print_z_candidate (loc, N_("candidate is:"), t->cand);
+ {
+ auto_diagnostic_nesting_level sentinel;
+ print_z_candidate (loc, N_("candidate is:"), t->cand);
+ }
expr = convert_like (t, expr, fn, argnum,
/*issue_conversion_warnings=*/false,
/*c_cast_p=*/false, /*nested_p=*/true,
@@ -8746,7 +8816,14 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
else if (t->kind == ck_identity)
break;
}
- if (!complained && expr != error_mark_node)
+ if (!complained && stub_object_p)
+ {
+ /* An error diagnosed within a trait, don't give extra labels. */
+ error_at (loc, "invalid conversion from %qH to %qI",
+ TREE_TYPE (expr), totype);
+ complained = 1;
+ }
+ else if (!complained && expr != error_mark_node)
{
range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
gcc_rich_location richloc (loc, &label, highlight_colors::percent_h);
@@ -9169,7 +9246,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
if (convs->copy_init_p)
flags |= LOOKUP_ONLYCONVERTING;
expr = build_temp (expr, totype, flags, &diag_kind, complain);
- if (diag_kind && complain)
+ if (diag_kind != diagnostics::kind::unspecified && complain)
{
auto_diagnostic_group d;
maybe_print_user_conv_context (convs);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 9a41c00..f5d20e5 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -1407,7 +1407,7 @@ add_method (tree type, tree method, bool via_using)
/* If these are versions of the same function, process and
move on. */
if (TREE_CODE (fn) == FUNCTION_DECL
- && maybe_version_functions (method, fn, true))
+ && maybe_version_functions (method, fn))
continue;
if (DECL_INHERITED_CTOR (method))
@@ -7452,7 +7452,7 @@ determine_key_method (tree type)
&& ! DECL_DECLARED_INLINE_P (method)
&& ! DECL_PURE_VIRTUAL_P (method))
{
- CLASSTYPE_KEY_METHOD (type) = method;
+ SET_CLASSTYPE_KEY_METHOD (type, method);
break;
}
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f9066bc..be24ae2 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -153,7 +153,7 @@ static bool
constexpr_error (location_t location, bool constexpr_fundef_p,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, gmsgid);
@@ -161,14 +161,17 @@ constexpr_error (location_t location, bool constexpr_fundef_p,
if (!constexpr_fundef_p)
{
/* Report an error that cannot be suppressed. */
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::error);
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
else if (warn_invalid_constexpr)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
- cxx_dialect < cxx23 ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = OPT_Winvalid_constexpr;
+ (cxx_dialect < cxx23
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning));
+ diagnostic.m_option_id = OPT_Winvalid_constexpr;
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
else
@@ -1184,6 +1187,10 @@ public:
/* Heap VAR_DECLs created during the evaluation of the outermost constant
expression. */
auto_vec<tree, 16> heap_vars;
+ /* Vector of caught exceptions, including exceptions still not active at
+ the start of a handler (those are immediately followed up by HANDLER_TYPE
+ until __cxa_begin_catch finishes). */
+ auto_vec<tree, 2> caught_exceptions;
/* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */
vec<tree> *cleanups;
/* If non-null, only allow modification of existing values of the variables
@@ -1191,10 +1198,13 @@ public:
hash_set<tree> *modifiable;
/* Number of heap VAR_DECL deallocations. */
unsigned heap_dealloc_count;
+ /* Number of uncaught exceptions. */
+ unsigned uncaught_exceptions;
+
/* Constructor. */
constexpr_global_ctx ()
: constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr),
- heap_dealloc_count (0) {}
+ heap_dealloc_count (0), uncaught_exceptions (0) {}
bool is_outside_lifetime (tree t)
{
@@ -1308,6 +1318,48 @@ struct constexpr_ctx {
mce_value manifestly_const_eval;
};
+/* Predicates for the meaning of *jump_target. */
+
+static bool
+returns (tree *jump_target)
+{
+ return *jump_target && TREE_CODE (*jump_target) == RETURN_EXPR;
+}
+
+static bool
+breaks (tree *jump_target)
+{
+ return (*jump_target
+ && ((TREE_CODE (*jump_target) == LABEL_DECL
+ && LABEL_DECL_BREAK (*jump_target))
+ || TREE_CODE (*jump_target) == BREAK_STMT
+ || TREE_CODE (*jump_target) == EXIT_EXPR));
+}
+
+static bool
+continues (tree *jump_target)
+{
+ return (*jump_target
+ && ((TREE_CODE (*jump_target) == LABEL_DECL
+ && LABEL_DECL_CONTINUE (*jump_target))
+ || TREE_CODE (*jump_target) == CONTINUE_STMT));
+}
+
+static bool
+switches (tree *jump_target)
+{
+ return *jump_target && TREE_CODE (*jump_target) == INTEGER_CST;
+}
+
+static bool
+throws (tree *jump_target)
+{
+ /* void_node is for use in potential_constant_expression_1, otherwise
+ it should an artificial VAR_DECL created by constant evaluation
+ of __cxa_allocate_exception (). */
+ return (*jump_target && (VAR_P (*jump_target) || *jump_target == void_node));
+}
+
/* True if the constexpr relaxations afforded by P2280R4 for unknown
references and objects are in effect. */
@@ -1543,13 +1595,672 @@ enum value_cat {
};
static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
- value_cat, bool *, bool *, tree * = NULL);
+ value_cat, bool *, bool *, tree *);
static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree,
- value_cat, bool *, bool *);
+ value_cat, bool *, bool *, tree *);
static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree,
- bool * = NULL);
+ bool *, tree *);
static tree find_heap_var_refs (tree *, int *, void *);
+/* For exception object EXC if it has class type and usable what () method
+ which returns cv char * return the xmalloced string literal which it returns
+ if possible, otherwise return NULL. */
+
+static char *
+exception_what_str (const constexpr_ctx *ctx, tree exc)
+{
+ tree type = strip_array_types (TREE_TYPE (exc));
+ if (!CLASS_TYPE_P (type))
+ return NULL;
+ tree std_exception = lookup_qualified_name (std_node, "exception",
+ LOOK_want::NORMAL, false);
+ if (TREE_CODE (std_exception) != TYPE_DECL)
+ return NULL;
+ if (!CLASS_TYPE_P (TREE_TYPE (std_exception)))
+ return NULL;
+ base_kind b_kind;
+ tree binfo = lookup_base (type, TREE_TYPE (std_exception), ba_check, &b_kind,
+ tf_none);
+ if (binfo == NULL_TREE || binfo == error_mark_node)
+ return NULL;
+ if (type != TREE_TYPE (exc))
+ exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL);
+ tree call
+ = finish_class_member_access_expr (exc, get_identifier ("what"), false,
+ tf_none);
+ if (call == error_mark_node)
+ return NULL;
+ releasing_vec what_args;
+ call = finish_call_expr (call, &what_args, false, false, tf_none);
+ if (call == error_mark_node)
+ return NULL;
+ if (TREE_CODE (TREE_TYPE (call)) != POINTER_TYPE
+ || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (call)))
+ || !COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (call)))
+ || !tree_int_cst_equal (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (call))),
+ TYPE_SIZE_UNIT (char_type_node))
+ || TYPE_PRECISION (TREE_TYPE (TREE_TYPE (call))) != BITS_PER_UNIT)
+ return NULL;
+ if (!potential_constant_expression (call))
+ return NULL;
+ bool non_constant_p = false, overflow_p = false;
+ tree jmp_target = NULL;
+ tree ptr = cxx_eval_constant_expression (ctx, call, vc_prvalue,
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ if (throws (&jmp_target) || non_constant_p)
+ return NULL;
+ if (reduced_constant_expression_p (ptr))
+ if (const char *msg = c_getstr (ptr))
+ return xstrdup (msg);
+ auto_vec <char, 32> v;
+ for (unsigned i = 0; i < INT_MAX; ++i)
+ {
+ tree t = call;
+ if (i)
+ t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, size_int (i));
+ t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+ non_constant_p = false;
+ overflow_p = false;
+ jmp_target = NULL;
+ tree t2 = cxx_eval_constant_expression (ctx, t, vc_prvalue,
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ if (throws (&jmp_target)
+ || non_constant_p
+ || !tree_fits_shwi_p (t2))
+ return NULL;
+ char c = tree_to_shwi (t2);
+ v.safe_push (c);
+ if (c == '\0')
+ break;
+ }
+ return xstrdup (v.address ());
+}
+
+/* Diagnose constant expression evaluation encountering call to
+ std::terminate due to exception EXC. */
+
+static void
+diagnose_std_terminate (location_t loc, const constexpr_ctx *ctx, tree exc)
+{
+ tree type = strip_array_types (TREE_TYPE (exc));
+ if (char *str = exception_what_str (ctx, exc))
+ {
+ error_at (loc, "%qs called after throwing an exception of type %qT; "
+ "%<what()%>: %qs", "std::terminate", type, str);
+ free (str);
+ }
+ else
+ {
+ if (type != TREE_TYPE (exc))
+ exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL);
+ bool non_constant_p = false, overflow_p = false;
+ tree jmp_target = NULL;
+ tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue,
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ gcc_assert (!throws (&jmp_target) && !non_constant_p);
+ if (reduced_constant_expression_p (val))
+ error_at (loc, "%qs called after throwing an exception %qE",
+ "std::terminate", val);
+ else
+ error_at (loc, "%qs called after throwing an exception of type %qT",
+ "std::terminate", type);
+ }
+}
+
+/* Diagnose constant expression evaluation encountering call to
+ uncaught exception EXC. */
+
+static void
+diagnose_uncaught_exception (location_t loc, const constexpr_ctx *ctx, tree exc)
+{
+ tree type = strip_array_types (TREE_TYPE (exc));
+ if (char *str = exception_what_str (ctx, exc))
+ {
+ error_at (loc, "uncaught exception of type %qT; %<what()%>: %qs", type, str);
+ free (str);
+ }
+ else
+ {
+ if (type != TREE_TYPE (exc))
+ exc = build4 (ARRAY_REF, type, exc, size_zero_node, NULL, NULL);
+ bool non_constant_p = false, overflow_p = false;
+ tree jmp_target = NULL;
+ tree val = cxx_eval_constant_expression (ctx, exc, vc_prvalue,
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ gcc_assert (!throws (&jmp_target) && !non_constant_p);
+ if (reduced_constant_expression_p (val))
+ error_at (loc, "uncaught exception %qE", val);
+ else
+ error_at (loc, "uncaught exception of type %qT", type);
+ }
+}
+
+/* Kinds of __cxa_* functions (and a few other EH related ones) we handle as
+ magic constexpr functions for C++26. */
+
+enum cxa_builtin {
+ CXA_NONE = 0,
+ CXA_ALLOCATE_EXCEPTION = 1,
+ CXA_FREE_EXCEPTION = 2,
+ CXA_THROW = 3,
+ CXA_BEGIN_CATCH = 4,
+ CXA_END_CATCH = 5,
+ CXA_RETHROW = 6,
+ CXA_GET_EXCEPTION_PTR = 7,
+ CXA_BAD_CAST = 8,
+ CXA_BAD_TYPEID = 9,
+ CXA_THROW_BAD_ARRAY_NEW_LENGTH = 10,
+ STD_UNCAUGHT_EXCEPTIONS = 11,
+ STD_CURRENT_EXCEPTION = 12,
+ STD_RETHROW_EXCEPTION = 13,
+ BUILTIN_EH_PTR_ADJUST_REF = 14
+};
+
+/* Return cxa_builtin if FNDECL is a __cxa_* function handled as
+ magic constexpr function for C++26. Return CXA_NONE otherwise. */
+
+static enum cxa_builtin
+cxx_cxa_builtin_fn_p (tree fndecl)
+{
+ if (cxx_dialect < cxx26)
+ return CXA_NONE;
+ if (DECL_LANGUAGE (fndecl) != lang_c)
+ {
+ if (!decl_in_std_namespace_p (fndecl))
+ return CXA_NONE;
+ if (id_equal (DECL_NAME (fndecl), "uncaught_exceptions"))
+ return STD_UNCAUGHT_EXCEPTIONS;
+ if (id_equal (DECL_NAME (fndecl), "current_exception"))
+ return STD_CURRENT_EXCEPTION;
+ if (id_equal (DECL_NAME (fndecl), "rethrow_exception"))
+ return STD_RETHROW_EXCEPTION;
+ return CXA_NONE;
+ }
+ if (!startswith (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "__cxa_"))
+ return CXA_NONE;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_allocate_exception"))
+ return CXA_ALLOCATE_EXCEPTION;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_free_exception"))
+ return CXA_FREE_EXCEPTION;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_throw"))
+ return CXA_THROW;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_begin_catch"))
+ return CXA_BEGIN_CATCH;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_end_catch"))
+ return CXA_END_CATCH;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_rethrow"))
+ return CXA_RETHROW;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_get_exception_ptr"))
+ return CXA_GET_EXCEPTION_PTR;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_bad_cast"))
+ return CXA_BAD_CAST;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_bad_typeid"))
+ return CXA_BAD_TYPEID;
+ if (id_equal (DECL_NAME (fndecl), "__cxa_throw_bad_array_new_length"))
+ return CXA_THROW_BAD_ARRAY_NEW_LENGTH;
+ return CXA_NONE;
+}
+
+/* Helper function for cxx_eval_cxa_builtin_fn.
+ Check if ARG is a valid first argument of __cxa_throw or
+ __cxa_free_exception or __builtin_eh_ptr_adjust_ref. Return NULL_TREE if
+ not, otherwise return the artificial __cxa_allocate_exception allocated
+ VAR_DECL. FREE_EXC is true for __cxa_free_exception, false otherwise. */
+
+static tree
+cxa_check_throw_arg (tree arg, bool free_exc)
+{
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) != ADDR_EXPR)
+ return NULL_TREE;
+ arg = TREE_OPERAND (arg, 0);
+ if (!VAR_P (arg)
+ || !DECL_ARTIFICIAL (arg)
+ || ((!free_exc || DECL_NAME (arg) != heap_uninit_identifier)
+ && DECL_NAME (arg) != heap_identifier)
+ || !DECL_LANG_SPECIFIC (arg))
+ return NULL_TREE;
+ return arg;
+}
+
+/* Helper function for cxx_eval_cxa_builtin_fn.
+ "Allocate" on the constexpr heap an exception object of TYPE
+ with REFCOUNT. */
+
+static tree
+cxa_allocate_exception (location_t loc, const constexpr_ctx *ctx, tree type,
+ tree refcount)
+{
+ tree var = build_decl (loc, VAR_DECL, heap_uninit_identifier, type);
+ DECL_ARTIFICIAL (var) = 1;
+ retrofit_lang_decl (var);
+ DECL_EXCEPTION_REFCOUNT (var) = refcount;
+ ctx->global->heap_vars.safe_push (var);
+ return var;
+}
+
+/* Evaluate various __cxa_* calls as magic constexpr builtins for
+ C++26 constexpr exception support (P3068R5). */
+
+static tree
+cxx_eval_cxa_builtin_fn (const constexpr_ctx *ctx, tree call,
+ enum cxa_builtin kind, tree fndecl,
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
+{
+ int nargs = call_expr_nargs (call);
+ location_t loc = cp_expr_loc_or_input_loc (call);
+ tree args[4], arg;
+ if (nargs > 4)
+ {
+ invalid_nargs:
+ if (!ctx->quiet)
+ error_at (loc, "call to %qD function with incorrect"
+ "number of arguments", fndecl);
+ *non_constant_p = true;
+ return call;
+ }
+ if ((kind == CXA_BEGIN_CATCH || kind == CXA_GET_EXCEPTION_PTR)
+ && nargs == 1
+ && (arg = CALL_EXPR_ARG (call, 0))
+ && TREE_CODE (arg) == CALL_EXPR
+ && call_expr_nargs (arg) == 1
+ && integer_zerop (CALL_EXPR_ARG (arg, 0)))
+ if (tree fun = get_function_named_in_call (arg))
+ if (fndecl_built_in_p (fun, BUILT_IN_EH_POINTER))
+ {
+ if (ctx->global->caught_exceptions.length () < 2)
+ {
+ no_caught_exceptions:
+ if (!ctx->quiet)
+ error_at (loc, "%qD called with no caught exceptions pending",
+ fndecl);
+ *non_constant_p = true;
+ return call;
+ }
+ /* Both __cxa_get_exception_ptr (__builtin_eh_pointer (0))
+ and __cxa_begin_catch (__builtin_eh_pointer (0)) calls expect
+ ctx->global->caught_exceptions vector to end with
+ __cxa_allocate_exception created artificial VAR_DECL (the
+ exception object) followed by handler type, pushed by TRY_BLOCK
+ evaluation. The only difference between the functions is that
+ __cxa_begin_catch pops the handler type from the vector and keeps
+ the VAR_DECL last and decreases uncaught_exceptions. The
+ VAR_DECL after __cxa_begin_catch serves as the current exception
+ and is then popped in __cxa_end_catch evaluation. */
+ tree handler_type = ctx->global->caught_exceptions.last ();
+ if (handler_type && VAR_P (handler_type))
+ goto no_caught_exceptions;
+ unsigned idx = ctx->global->caught_exceptions.length () - 2;
+ arg = ctx->global->caught_exceptions[idx];
+ gcc_assert (VAR_P (arg));
+ if (kind == CXA_BEGIN_CATCH)
+ {
+ ctx->global->caught_exceptions.pop ();
+ --ctx->global->uncaught_exceptions;
+ }
+ if (handler_type == NULL_TREE)
+ /* Used for catch (...). Just return void. */
+ return void_node;
+ else if (POINTER_TYPE_P (handler_type))
+ {
+ /* Used for catch of a pointer. */
+ if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
+ arg = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (arg)), arg,
+ size_zero_node, NULL_TREE, NULL_TREE);
+ arg = cp_convert (handler_type, arg,
+ ctx->quiet ? tf_none : tf_warning_or_error);
+ if (arg == error_mark_node)
+ {
+ *non_constant_p = true;
+ return call;
+ }
+ }
+ else
+ {
+ /* Used for catch of a non-pointer type. */
+ tree exc_type = strip_array_types (TREE_TYPE (arg));
+ tree exc_ptr_type = build_pointer_type (exc_type);
+ arg = build_fold_addr_expr_with_type (arg, exc_ptr_type);
+ if (CLASS_TYPE_P (handler_type))
+ {
+ tree ptr_type = build_pointer_type (handler_type);
+ arg = cp_convert (ptr_type, arg,
+ ctx->quiet ? tf_none
+ : tf_warning_or_error);
+ if (arg == error_mark_node)
+ {
+ *non_constant_p = true;
+ return call;
+ }
+ }
+ }
+ return cxx_eval_constant_expression (ctx, arg, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ }
+ for (int i = 0; i < nargs; ++i)
+ {
+ args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (call, i),
+ vc_prvalue, non_constant_p,
+ overflow_p, jump_target);
+ if (*non_constant_p)
+ return call;
+ if (*jump_target)
+ return NULL_TREE;
+ }
+ switch (kind)
+ {
+ case CXA_ALLOCATE_EXCEPTION:
+ if (nargs != 1)
+ goto invalid_nargs;
+ if (!tree_fits_uhwi_p (args[0]))
+ {
+ if (!ctx->quiet)
+ error_at (loc, "cannot allocate exception: size not constant");
+ *non_constant_p = true;
+ return call;
+ }
+ else
+ {
+ tree type = build_array_type_nelts (char_type_node,
+ tree_to_uhwi (args[0]));
+ tree var = cxa_allocate_exception (loc, ctx, type, size_zero_node);
+ ctx->global->put_value (var, NULL_TREE);
+ return fold_convert (ptr_type_node, build_address (var));
+ }
+ case CXA_FREE_EXCEPTION:
+ if (nargs != 1)
+ goto invalid_nargs;
+ arg = cxa_check_throw_arg (args[0], true);
+ if (arg == NULL_TREE)
+ {
+ invalid_ptr:
+ if (!ctx->quiet)
+ error_at (loc, "first argument to %qD function not result of "
+ "%<__cxa_allocate_exception%>", fndecl);
+ *non_constant_p = true;
+ return call;
+ }
+ DECL_NAME (arg) = heap_deleted_identifier;
+ ctx->global->destroy_value (arg);
+ ctx->global->heap_dealloc_count++;
+ return void_node;
+ case CXA_THROW:
+ if (nargs != 3)
+ goto invalid_nargs;
+ arg = cxa_check_throw_arg (args[0], false);
+ if (arg == NULL_TREE)
+ goto invalid_ptr;
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg),
+ size_one_node);
+ ++ctx->global->uncaught_exceptions;
+ *jump_target = arg;
+ return void_node;
+ case CXA_BEGIN_CATCH:
+ case CXA_GET_EXCEPTION_PTR:
+ goto invalid_nargs;
+ case CXA_END_CATCH:
+ if (nargs != 0)
+ goto invalid_nargs;
+ if (ctx->global->caught_exceptions.is_empty ())
+ {
+ no_active_exc:
+ if (!ctx->quiet)
+ error_at (loc, "%qD called with no caught exceptions active",
+ fndecl);
+ *non_constant_p = true;
+ return call;
+ }
+ else
+ {
+ arg = ctx->global->caught_exceptions.pop ();
+ if (arg == NULL_TREE || !VAR_P (arg))
+ goto no_active_exc;
+ free_except:
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (MINUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg),
+ size_one_node);
+ if (integer_zerop (DECL_EXCEPTION_REFCOUNT (arg)))
+ {
+ if (type_build_dtor_call (TREE_TYPE (arg)))
+ {
+ tree cleanup
+ = cxx_maybe_build_cleanup (arg, (ctx->quiet ? tf_none
+ : tf_warning_or_error));
+ if (cleanup == error_mark_node)
+ *non_constant_p = true;
+ tree jmp_target = NULL_TREE;
+ cxx_eval_constant_expression (ctx, cleanup, vc_discard,
+ non_constant_p, overflow_p,
+ &jmp_target);
+ if (throws (&jmp_target))
+ *jump_target = jmp_target;
+ }
+ DECL_NAME (arg) = heap_deleted_identifier;
+ ctx->global->destroy_value (arg);
+ ctx->global->heap_dealloc_count++;
+ }
+ }
+ return void_node;
+ case CXA_RETHROW:
+ if (nargs != 0)
+ goto invalid_nargs;
+ unsigned idx;
+ FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg)
+ if (arg == NULL_TREE || !VAR_P (arg))
+ --idx;
+ else
+ break;
+ if (arg == NULL_TREE)
+ {
+ if (!ctx->quiet)
+ error_at (loc, "%qD called with no caught exceptions active",
+ fndecl);
+ *non_constant_p = true;
+ return call;
+ }
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node);
+ ++ctx->global->uncaught_exceptions;
+ *jump_target = arg;
+ return void_node;
+ case CXA_BAD_CAST:
+ case CXA_BAD_TYPEID:
+ case CXA_THROW_BAD_ARRAY_NEW_LENGTH:
+ if (nargs != 0)
+ goto invalid_nargs;
+ else
+ {
+ tree name;
+ switch (kind)
+ {
+ case CXA_BAD_CAST:
+ name = get_identifier ("bad_cast");
+ break;
+ case CXA_BAD_TYPEID:
+ name = get_identifier ("bad_typeid");
+ break;
+ case CXA_THROW_BAD_ARRAY_NEW_LENGTH:
+ name = get_identifier ("bad_array_new_length");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ tree decl = lookup_qualified_name (std_node, name);
+ if (TREE_CODE (decl) != TYPE_DECL
+ || !CLASS_TYPE_P (TREE_TYPE (decl))
+ || !type_build_ctor_call (TREE_TYPE (decl)))
+ {
+ if (!ctx->quiet)
+ error_at (loc, "%qD called without %<std::%D%> being defined",
+ fndecl, name);
+ *non_constant_p = true;
+ return call;
+ }
+ tree type = TREE_TYPE (decl);
+ tree var = cxa_allocate_exception (loc, ctx, type, size_one_node);
+ tree ctor
+ = build_special_member_call (var, complete_ctor_identifier,
+ NULL, type, LOOKUP_NORMAL,
+ ctx->quiet ? tf_none
+ : tf_warning_or_error);
+ if (ctor == error_mark_node)
+ {
+ *non_constant_p = true;
+ return call;
+ }
+ if (TREE_CONSTANT (ctor))
+ ctx->global->put_value (var, ctor);
+ else
+ {
+ ctx->global->put_value (var, NULL_TREE);
+ cxx_eval_constant_expression (ctx, ctor, vc_discard,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*non_constant_p)
+ return call;
+ if (throws (jump_target))
+ return NULL_TREE;
+ }
+ ++ctx->global->uncaught_exceptions;
+ *jump_target = var;
+ }
+ return void_node;
+ case STD_UNCAUGHT_EXCEPTIONS:
+ if (nargs != 0)
+ goto invalid_nargs;
+ /* Similarly to __builtin_is_constant_evaluated (), we don't
+ want to give a definite answer during mce_unknown evaluation,
+ because that might prevent evaluation later on when some
+ exceptions might be uncaught. But unlike that, we don't
+ want to constant fold it even during cp_fold, because at runtime
+ std::uncaught_exceptions () might still be non-zero. */
+ if (ctx->manifestly_const_eval != mce_true)
+ {
+ *non_constant_p = true;
+ return call;
+ }
+ return build_int_cst (integer_type_node,
+ ctx->global->uncaught_exceptions);
+ case STD_CURRENT_EXCEPTION:
+ if (nargs != 0)
+ goto invalid_nargs;
+ else
+ {
+ tree name = get_identifier ("exception_ptr");
+ tree decl = lookup_qualified_name (std_node, name);
+ tree fld;
+ if (TREE_CODE (decl) != TYPE_DECL
+ || !CLASS_TYPE_P (TREE_TYPE (decl))
+ || !COMPLETE_TYPE_P (TREE_TYPE (decl))
+ || !(fld = next_aggregate_field (TYPE_FIELDS (TREE_TYPE (decl))))
+ || DECL_ARTIFICIAL (fld)
+ || TREE_CODE (TREE_TYPE (fld)) != POINTER_TYPE
+ || next_aggregate_field (DECL_CHAIN (fld))
+ || !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (decl)),
+ TYPE_SIZE (TREE_TYPE (fld))))
+ {
+ if (!ctx->quiet)
+ error_at (loc, "%qD called without supportable %qs",
+ fndecl, "std::exception_ptr");
+ *non_constant_p = true;
+ return call;
+ }
+ FOR_EACH_VEC_ELT_REVERSE (ctx->global->caught_exceptions, idx, arg)
+ if (arg == NULL_TREE || !VAR_P (arg))
+ --idx;
+ else
+ break;
+ /* Similarly to __builtin_is_constant_evaluated (), we don't
+ want to give a definite answer during mce_unknown evaluation,
+ because that might prevent evaluation later on when some
+ exceptions might be current. But unlike that, we don't
+ want to constant fold it to null even during cp_fold, because
+ at runtime std::current_exception () might still be non-null. */
+ if (ctx->manifestly_const_eval != mce_true && arg == NULL_TREE)
+ {
+ *non_constant_p = true;
+ return call;
+ }
+ if (arg == NULL_TREE)
+ arg = build_zero_cst (TREE_TYPE (fld));
+ else
+ {
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg),
+ size_one_node);
+ arg = fold_convert (ptr_type_node, build_address (arg));
+ }
+ return build_constructor_single (TREE_TYPE (decl), fld, arg);
+ }
+ case STD_RETHROW_EXCEPTION:
+ if (nargs != 1)
+ goto invalid_nargs;
+ if (TYPE_REF_P (TREE_TYPE (args[0])))
+ {
+ arg = args[0];
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ {
+ args[0]
+ = cxx_eval_constant_expression (ctx, TREE_OPERAND (arg, 0),
+ vc_prvalue, non_constant_p,
+ overflow_p, jump_target);
+ if (*non_constant_p)
+ return call;
+ if (*jump_target)
+ return NULL_TREE;
+ }
+ }
+ if (TREE_CODE (args[0]) != CONSTRUCTOR
+ || CONSTRUCTOR_NELTS (args[0]) != 1)
+ {
+ invalid_std_rethrow:
+ if (!ctx->quiet)
+ error_at (loc, "%qD called with unexpected %qs argument",
+ fndecl, "std::exception_ptr");
+ *non_constant_p = true;
+ return void_node;
+ }
+ arg = cxa_check_throw_arg (CONSTRUCTOR_ELT (args[0], 0)->value, false);
+ if (arg == NULL_TREE)
+ goto invalid_std_rethrow;
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg), size_one_node);
+ ++ctx->global->uncaught_exceptions;
+ *jump_target = arg;
+ return void_node;
+ case BUILTIN_EH_PTR_ADJUST_REF:
+ if (nargs != 2)
+ goto invalid_nargs;
+ arg = cxa_check_throw_arg (args[0], false);
+ if (arg == NULL_TREE)
+ goto invalid_ptr;
+ if (integer_onep (args[1]))
+ DECL_EXCEPTION_REFCOUNT (arg)
+ = size_binop (PLUS_EXPR, DECL_EXCEPTION_REFCOUNT (arg),
+ size_one_node);
+ else if (integer_minus_onep (args[1]))
+ goto free_except;
+ else
+ {
+ if (!ctx->quiet)
+ error_at (loc, "%qD called with second argument "
+ "other than 1 or -1", fndecl);
+ *non_constant_p = true;
+ }
+ return void_node;
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Attempt to evaluate T which represents a call to a builtin function.
We assume here that all builtin functions evaluate to scalar types
represented by _CST nodes. */
@@ -1557,7 +2268,8 @@ static tree find_heap_var_refs (tree *, int *, void *);
static tree
cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
const int nargs = call_expr_nargs (t);
tree *args = (tree *) alloca (nargs * sizeof (tree));
@@ -1603,6 +2315,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
return fold_builtin_source_location (t);
}
+ if (fndecl_built_in_p (fun, CP_BUILT_IN_EH_PTR_ADJUST_REF,
+ BUILT_IN_FRONTEND))
+ return cxx_eval_cxa_builtin_fn (ctx, t, BUILTIN_EH_PTR_ADJUST_REF,
+ fun, non_constant_p, overflow_p,
+ jump_target);
+
int strops = 0;
int strret = 0;
if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
@@ -1677,8 +2395,14 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
|| potential_constant_expression (arg))
{
bool dummy1 = false, dummy2 = false;
+ tree jmp_target = NULL_TREE;
arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
- &dummy1, &dummy2);
+ &dummy1, &dummy2, &jmp_target);
+ if (jmp_target)
+ {
+ *jump_target = jmp_target;
+ return NULL_TREE;
+ }
}
if (bi_const_p)
@@ -1767,7 +2491,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
}
return cxx_eval_constant_expression (&new_ctx, new_call, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
/* TEMP is the constant value of a temporary object of type TYPE. Adjust
@@ -1882,7 +2607,8 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data)
static tree
cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
tree orig_fun, bool *non_constant_p,
- bool *overflow_p, bool *non_constant_args)
+ bool *overflow_p, bool *non_constant_args,
+ tree *jump_target)
{
int nargs = call_expr_nargs (t);
tree parms = DECL_ARGUMENTS (fun);
@@ -1958,14 +2684,16 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
/* Undo convert_for_arg_passing work here. */
x = convert_from_reference (x);
arg = cxx_eval_constant_expression (ctx, x, vc_glvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
else
/* Normally we would strip a TARGET_EXPR in an initialization context
such as this, but here we do the elision differently: we keep the
TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */
arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
/* Check we aren't dereferencing a null pointer when calling a non-static
member function, which is undefined behaviour. */
if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun)
@@ -1983,6 +2711,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && ctx->quiet)
break;
+ if (*jump_target)
+ break;
/* Just discard ellipsis args after checking their constantitude. */
if (!parms)
continue;
@@ -2094,9 +2824,10 @@ fold_operand (tree e, const constexpr_ctx *ctx)
if (ctx)
{
bool new_non_constant_p = false, new_overflow_p = false;
+ tree jmp_target = NULL_TREE;
e = cxx_eval_constant_expression (ctx, e, vc_prvalue,
&new_non_constant_p,
- &new_overflow_p);
+ &new_overflow_p, &jmp_target);
}
else
e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true);
@@ -2155,10 +2886,15 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p,
if (TREE_CODE (bad) == CLEANUP_POINT_EXPR)
bad = TREE_OPERAND (bad, 0);
+ auto_diagnostic_nesting_level sentinel;
+
/* Actually explain the failure if this is a concept check or a
requires-expression. */
if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR)
diagnose_constraints (cloc, bad, NULL_TREE);
+ /* Similarly if this is a standard trait. */
+ else if (maybe_diagnose_standard_trait (cloc, bad))
+ ;
else if (COMPARISON_CLASS_P (bad)
&& ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0))))
{
@@ -2183,7 +2919,7 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg,
if (*non_constant_p)
return true;
- tree eval;
+ tree eval, jmp_target = NULL_TREE;
if (!evaluated)
{
if (!potential_rvalue_constant_expression (arg))
@@ -2196,12 +2932,15 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg,
modifiable_tracker ms (new_ctx.global);
eval = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
&new_non_constant_p,
- &new_overflow_p);
+ &new_overflow_p, &jmp_target);
}
else
eval = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
non_constant_p,
- overflow_p);
+ overflow_p, &jmp_target);
+ if (jmp_target)
+ return true;
+
if (!*non_constant_p && integer_zerop (eval))
{
if (!ctx->quiet)
@@ -2233,7 +2972,8 @@ cxx_eval_assert (const constexpr_ctx *ctx, tree arg, const char *msg,
static tree
cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
enum tree_code opcode = ERROR_MARK;
@@ -2266,13 +3006,15 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
case IFN_LAUNDER:
return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
case IFN_VEC_CONVERT:
{
tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (TREE_CODE (arg) == VECTOR_CST)
if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg))
return r;
@@ -2290,10 +3032,13 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
/* Evaluate constant arguments using OPCODE and return a complex
number containing the result and the overflow bit. */
tree arg0 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
tree arg1 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 1), lval,
- non_constant_p, overflow_p);
-
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
{
location_t loc = cp_expr_loc_or_input_loc (t);
@@ -2566,7 +3311,8 @@ get_component_with_type (tree path, tree type, tree stop)
static tree
cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
/* T will be something like
__dynamic_cast ((B*) b, &_ZTI1B, &_ZTI1D, 8)
@@ -2585,19 +3331,26 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
/* TYPE can only be either T* or T&. We can't know which of these it
is by looking at TYPE, but OBJ will be "(T*) x" in the first case,
- and something like "(T*)(T&)(T*) x" in the second case. */
- bool reference_p = false;
+ and something like "(T*)(T&)(T*) x" in the second case.
+ This is true for the reference cases in C++ < 26 or when exceptions
+ aren't enabled, in that case we should diagnose errors. For C++26
+ with exceptions we should silently evaluate to null pointer and
+ let the callers call __cxa_bad_cast () later to throw an exception. */
+ bool fail_for_non_constant_p = false;
while (CONVERT_EXPR_P (obj) || TREE_CODE (obj) == SAVE_EXPR)
{
- reference_p |= TYPE_REF_P (TREE_TYPE (obj));
+ if (cxx_dialect < cxx26 || !flag_exceptions)
+ fail_for_non_constant_p |= TYPE_REF_P (TREE_TYPE (obj));
obj = TREE_OPERAND (obj, 0);
}
/* Evaluate the object so that we know its dynamic type. */
obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
if (*non_constant_p)
return call;
+ if (*jump_target)
+ return NULL_TREE;
/* For dynamic_cast from classes with virtual bases we can get something
like (virt_base *)(&d + 16) as OBJ. Try to convert that into
@@ -2609,7 +3362,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
if (TREE_CODE (objo) == POINTER_PLUS_EXPR)
{
objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)),
- obj);
+ obj, NULL, jump_target);
if (objo)
obj = build_fold_addr_expr (objo);
}
@@ -2625,7 +3378,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
? TREE_OPERAND (obj, 1) : obj))
if (TREE_CODE (t) != FIELD_DECL || !DECL_FIELD_IS_BASE (t))
{
- if (reference_p)
+ if (fail_for_non_constant_p)
{
if (!ctx->quiet)
{
@@ -2647,9 +3400,12 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
constructor or destructor's class. */
tree vtable = build_vfield_ref (obj, objtype);
vtable = cxx_eval_constant_expression (ctx, vtable, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return call;
+ if (*jump_target)
+ return NULL_TREE;
/* With -fsanitize=vptr, we initialize all vtable pointers to null,
so it's possible that we got a null pointer now. */
if (integer_zerop (vtable))
@@ -2681,7 +3437,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
/* If not accessible, give an error. */
if (t == error_mark_node)
{
- if (reference_p)
+ if (fail_for_non_constant_p)
{
if (!ctx->quiet)
{
@@ -2714,7 +3470,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
obj = get_component_with_type (obj, mdtype, NULL_TREE);
if (obj == error_mark_node)
{
- if (reference_p)
+ if (fail_for_non_constant_p)
{
if (!ctx->quiet)
{
@@ -2736,7 +3492,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
tree binfo = lookup_base (mdtype, type, ba_check, &b_kind, tf_none);
if (!binfo || binfo == error_mark_node)
{
- if (reference_p)
+ if (fail_for_non_constant_p)
{
if (!ctx->quiet)
{
@@ -2832,7 +3588,7 @@ replace_decl (tree *tp, tree decl, tree replacement)
static tree
cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
tree function = THUNK_TARGET (thunk_fndecl);
@@ -2875,7 +3631,8 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl,
new_call, offset);
return cxx_eval_constant_expression (ctx, new_call, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
/* If OBJECT is of const class type, evaluate it to a CONSTRUCTOR and set
@@ -2885,7 +3642,7 @@ cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl,
static void
cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
bool readonly_p, bool *non_constant_p,
- bool *overflow_p)
+ bool *overflow_p, tree *jump_target)
{
if (CLASS_TYPE_P (TREE_TYPE (object))
&& CP_TYPE_CONST_P (TREE_TYPE (object)))
@@ -2893,8 +3650,11 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
/* Subobjects might not be stored in ctx->global->values but we
can get its CONSTRUCTOR by evaluating *this. */
tree e = cxx_eval_constant_expression (ctx, object, vc_prvalue,
- non_constant_p, overflow_p);
- if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p)
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!*non_constant_p
+ && !throws (jump_target)
+ && TREE_CODE (e) == CONSTRUCTOR)
TREE_READONLY (e) = readonly_p;
}
}
@@ -2906,20 +3666,25 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
static tree
cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
location_t loc = cp_expr_loc_or_input_loc (t);
tree fun = get_function_named_in_call (t);
if (fun == NULL_TREE)
return cxx_eval_internal_function (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (TREE_CODE (fun) != FUNCTION_DECL)
{
/* Might be a constexpr function pointer. */
fun = cxx_eval_constant_expression (ctx, fun, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
STRIP_NOPS (fun);
if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0);
@@ -2971,9 +3736,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
if (fndecl_built_in_p (fun))
return cxx_eval_builtin_function_call (ctx, t, fun,
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p,
+ jump_target);
if (DECL_THUNK_P (fun))
- return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p);
+ return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p,
+ jump_target);
+ bool non_constexpr_call = false;
if (!maybe_constexpr_fn (fun))
{
if (TREE_CODE (t) == CALL_EXPR
@@ -2988,7 +3756,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
tree arg = CALL_EXPR_ARG (t, i);
arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Deleting a non-constant pointer has a better error message
below. */
if (new_op_p || i != 0)
@@ -3103,7 +3874,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
tree arg = CALL_EXPR_ARG (t, i);
arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (i == 1)
arg1 = arg;
else
@@ -3113,16 +3887,31 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
return arg1;
}
else if (cxx_dynamic_cast_fn_p (fun))
- return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p);
+ return cxx_eval_dynamic_cast_fn (ctx, t, non_constant_p, overflow_p,
+ jump_target);
+ else if (enum cxa_builtin kind = cxx_cxa_builtin_fn_p (fun))
+ return cxx_eval_cxa_builtin_fn (ctx, t, kind, fun,
+ non_constant_p, overflow_p,
+ jump_target);
- if (!ctx->quiet)
+ /* Calls to non-constexpr functions can be diagnosed right away
+ before C++26, though in C++26 evaluation of the arguments might
+ throw and if caught it could be still constant expression.
+ So for C++26 this is diagnosed only after
+ cxx_bind_parameters_in_call. */
+ if (cxx_dialect >= cxx26)
+ non_constexpr_call = true;
+ else
{
- if (!lambda_static_thunk_p (fun))
- error_at (loc, "call to non-%<constexpr%> function %qD", fun);
- explain_invalid_constexpr_fn (fun);
+ if (!ctx->quiet)
+ {
+ if (!lambda_static_thunk_p (fun))
+ error_at (loc, "call to non-%<constexpr%> function %qD", fun);
+ explain_invalid_constexpr_fn (fun);
+ }
+ *non_constant_p = true;
+ return t;
}
- *non_constant_p = true;
- return t;
}
constexpr_ctx new_ctx = *ctx;
@@ -3158,7 +3947,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
constexpr_call new_call;
new_call.bindings
= cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p,
- overflow_p, &non_constant_args);
+ overflow_p, &non_constant_args,
+ jump_target);
/* We build up the bindings list before we know whether we already have this
call cached. If we don't end up saving these bindings, ggc_free them when
@@ -3172,8 +3962,21 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
void preserve () { bindings = NULL; }
} fb (new_call.bindings);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
+ if (non_constexpr_call)
+ {
+ if (!ctx->quiet)
+ {
+ if (!lambda_static_thunk_p (fun))
+ error_at (loc, "call to non-%<constexpr%> function %qD", fun);
+ explain_invalid_constexpr_fn (fun);
+ }
+ *non_constant_p = true;
+ return t;
+ }
/* We can't defer instantiating the function any longer. */
if (!DECL_INITIAL (fun)
@@ -3246,7 +4049,9 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
new_obj = TREE_VEC_ELT (new_call.bindings, 0);
bool empty_base = false;
new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj,
- &empty_base);
+ &empty_base, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* If we're initializing an empty class, don't set constness, because
cxx_fold_indirect_ref will return the wrong object to set constness
of. */
@@ -3395,7 +4200,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
semantics are no longer in effect; see [class.dtor]p5. */
if (new_obj && DECL_DESTRUCTOR_P (fun))
cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
/* If this is a constructor, we are beginning the lifetime of the
object we are initializing. */
@@ -3404,21 +4209,30 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
&& TREE_CODE (new_obj) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == UNION_TYPE)
{
+ tree ctor = build_constructor (TREE_TYPE (new_obj), NULL);
+ CONSTRUCTOR_NO_CLEARING (ctor) = true;
tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
- new_obj,
- build_constructor (TREE_TYPE (new_obj),
- NULL));
+ new_obj, ctor);
cxx_eval_constant_expression (ctx, activate,
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p,
+ jump_target);
ggc_free (activate);
+ if (*jump_target)
+ return NULL_TREE;
}
- tree jump_target = NULL_TREE;
+ tree jmp_target = NULL_TREE;
cxx_eval_constant_expression (&call_ctx, body,
vc_discard, non_constant_p, overflow_p,
- &jump_target);
+ &jmp_target);
- if (DECL_CONSTRUCTOR_P (fun))
+ if (!*non_constant_p && throws (&jmp_target))
+ {
+ result = NULL_TREE;
+ cacheable = false;
+ *jump_target = jmp_target;
+ }
+ else if (DECL_CONSTRUCTOR_P (fun))
/* This can be null for a subobject constructor call, in
which case what we care about is the initialization
side-effects rather than the value. We could get at the
@@ -3446,7 +4260,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
marking the CONSTRUCTOR TREE_READONLY. */
if (new_obj && DECL_CONSTRUCTOR_P (fun))
cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/true,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
/* Remove the parms/result from the values map. */
destroy_value_checked (ctx, res, non_constant_p);
@@ -3506,7 +4320,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
cacheable = false;
result = cxx_eval_constant_expression (ctx, result, lval,
non_constant_p,
- overflow_p);
+ overflow_p,
+ jump_target);
+ if (*jump_target)
+ {
+ cacheable = false;
+ result = NULL_TREE;
+ }
}
}
@@ -3864,12 +4684,16 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
static tree
cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
bool /*lval*/,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree r;
tree orig_arg = TREE_OPERAND (t, 0);
tree arg = cxx_eval_constant_expression (ctx, orig_arg, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (arg);
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -3893,7 +4717,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
tree lhs, tree rhs, bool *non_constant_p,
- bool *overflow_p)
+ bool *overflow_p, tree *jump_target)
{
STRIP_NOPS (lhs);
if (TREE_CODE (lhs) != ADDR_EXPR)
@@ -3915,9 +4739,12 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1));
tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0)));
nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return NULL_TREE;
+ if (*jump_target)
+ return NULL_TREE;
/* Don't fold an out-of-bound access. */
if (!tree_int_cst_le (t, nelts))
return NULL_TREE;
@@ -3937,7 +4764,8 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
t = cp_build_addr_expr (t, tf_warning_or_error);
t = cp_fold_convert (orig_type, t);
return cxx_eval_constant_expression (ctx, t, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
return NULL_TREE;
@@ -3981,22 +4809,29 @@ cxx_maybe_fold_addr_pointer_plus (tree t)
static tree
cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree r = NULL_TREE;
tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
lhs = cxx_eval_constant_expression (ctx, orig_lhs, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
/* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer
subtraction. */
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
rhs = cxx_eval_constant_expression (ctx, orig_rhs, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -4052,13 +4887,17 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
return t;
}
else if (code == POINTER_PLUS_EXPR)
- r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
- overflow_p);
+ {
+ r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ }
else if (code == SPACESHIP_EXPR)
{
r = genericize_spaceship (loc, type, lhs, rhs);
return cxx_eval_constant_expression (ctx, r, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
if (r == NULL_TREE)
@@ -4117,7 +4956,10 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
{
tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (val);
if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t))
{
@@ -4178,19 +5020,29 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (arg1);
tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (arg2);
tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (arg3);
location_t loc = EXPR_LOCATION (t);
tree type = TREE_TYPE (t);
@@ -4578,7 +5430,8 @@ diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array, tree
static tree
get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree nelts;
if (TREE_CODE (type) == ARRAY_TYPE)
@@ -4595,7 +5448,8 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
/* For VLAs, the number of elements won't be an integer constant. */
nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
return nelts;
}
@@ -4626,13 +5480,17 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
static tree
eval_and_check_array_index (const constexpr_ctx *ctx,
tree t, bool allow_one_past,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
location_t loc = cp_expr_loc_or_input_loc (t);
tree ary = TREE_OPERAND (t, 0);
t = TREE_OPERAND (t, 1);
tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (index);
if (!tree_fits_shwi_p (index)
@@ -4644,7 +5502,9 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
}
tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (nelts);
if (allow_one_past
? !tree_int_cst_le (index, nelts)
@@ -4664,14 +5524,18 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
static tree
cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree oldary = TREE_OPERAND (t, 0);
tree ary = cxx_eval_constant_expression (ctx, oldary,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
if (!lval
&& TREE_CODE (ary) == VIEW_CONVERT_EXPR
&& VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
@@ -4681,9 +5545,12 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
tree oldidx = TREE_OPERAND (t, 1);
tree index = eval_and_check_array_index (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
if (lval && ary == oldary && index == oldidx)
return t;
@@ -4801,7 +5668,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
ctx = &new_ctx;
}
t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
if (new_ctor && t != ctx->ctor)
free_constructor (ctx->ctor);
return t;
@@ -4813,7 +5680,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
unsigned HOST_WIDE_INT i;
tree field;
@@ -4822,9 +5690,12 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
tree orig_whole = TREE_OPERAND (t, 0);
tree whole = cxx_eval_constant_expression (ctx, orig_whole,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
if (INDIRECT_REF_P (whole)
&& integer_zerop (TREE_OPERAND (whole, 0)))
{
@@ -4930,10 +5801,23 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
}
/* If there's no explicit init for this field, it's value-initialized. */
+
+ if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
+ {
+ /* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR
+ and copy the flags. */
+ constructor_elt *e = get_or_insert_ctor_field (whole, part);
+ e->value = value = build_constructor (TREE_TYPE (part), NULL);
+ CONSTRUCTOR_ZERO_PADDING_BITS (value)
+ = CONSTRUCTOR_ZERO_PADDING_BITS (whole);
+ return value;
+ }
+
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
return cxx_eval_constant_expression (ctx, value,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
/* Subroutine of cxx_eval_constant_expression.
@@ -4943,7 +5827,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree orig_whole = TREE_OPERAND (t, 0);
tree retval, fldval, utype, mask;
@@ -4951,10 +5836,13 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
HOST_WIDE_INT istart, isize;
tree whole = cxx_eval_constant_expression (ctx, orig_whole,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
tree start, field, value;
unsigned HOST_WIDE_INT i;
+ if (*jump_target)
+ return NULL_TREE;
if (whole == orig_whole)
return t;
/* Don't VERIFY_CONSTANT here; we only want to check that we got a
@@ -5235,7 +6123,7 @@ clear_uchar_or_std_byte_in_mask (location_t loc, tree t, unsigned char *mask)
static tree
cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
- bool *overflow_p)
+ bool *overflow_p, tree *jump_target)
{
if (check_bit_cast_type (ctx, EXPR_LOCATION (t), TREE_TYPE (t),
TREE_TYPE (t))
@@ -5249,9 +6137,12 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
}
tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
+ if (*jump_target)
+ return NULL_TREE;
location_t loc = EXPR_LOCATION (t);
if (BITS_PER_UNIT != 8 || CHAR_BIT != 8)
@@ -5329,8 +6220,9 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
if (CHECKING_P)
{
tree e = cxx_eval_bare_aggregate (ctx, r, vc_prvalue,
- non_constant_p, overflow_p);
- gcc_checking_assert (e == r);
+ non_constant_p, overflow_p,
+ jump_target);
+ gcc_checking_assert (e == r && !*jump_target);
r = e;
}
}
@@ -5371,19 +6263,24 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
static tree
cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
tree bailout_value, tree continue_value,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree r;
tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value))
return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (r);
return r;
}
@@ -5540,7 +6437,8 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
static tree
cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
bool changed = false;
@@ -5593,7 +6491,10 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
get_or_insert_ctor_field (ctx->ctor, index);
tree elt = cxx_eval_constant_expression (&new_ctx, value,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Don't VERIFY_CONSTANT here. */
if (ctx->quiet && *non_constant_p)
break;
@@ -5683,7 +6584,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
bool value_init, value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree elttype = TREE_TYPE (atype);
verify_ctor_sanity (ctx, atype);
@@ -5694,7 +6596,10 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
if (init && TREE_CODE (init) == CONSTRUCTOR)
return cxx_eval_bare_aggregate (ctx, init, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
+
+ /* We already checked access when building the VEC_INIT_EXPR. */
+ deferring_access_check_sentinel acs (dk_deferred);
/* For the default constructor, build up a call to the default
constructor of the element type. We only need to handle class types
@@ -5731,7 +6636,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
}
tree nelts = get_array_or_vector_nelts (ctx, atype, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
unsigned HOST_WIDE_INT max = tree_to_uhwi (nelts);
for (i = 0; i < max; ++i)
{
@@ -5757,9 +6664,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
}
else
eltinit = cp_build_array_ref (input_location, init, idx, complain);
- eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init,
- lval,
- non_constant_p, overflow_p);
+ eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit,
+ value_init, lval, non_constant_p,
+ overflow_p, jump_target);
}
else if (pre_init)
{
@@ -5773,7 +6680,8 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
/* Clarify what object is being initialized (118285). */
eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit);
eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
reuse = i == 0;
}
else
@@ -5789,8 +6697,11 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
/* Clarify what object is being initialized (118285). */
eltinit = build2 (INIT_EXPR, elttype, new_ctx.object, eltinit);
eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
break;
if (no_slot)
@@ -5840,7 +6751,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
static tree
cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
tree atype = TREE_TYPE (t);
tree init = VEC_INIT_EXPR_INIT (t);
@@ -5872,10 +6783,10 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
}
init = expand_vec_init_expr (ctx->object, t, complain);
return cxx_eval_constant_expression (ctx, init, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
tree r = cxx_eval_vec_init_1 (ctx, atype, init, value_init,
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p, jump_target);
if (*non_constant_p)
return t;
else
@@ -5904,14 +6815,16 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
otherwise return NULL_TREE. */
static tree
-cxx_union_active_member (const constexpr_ctx *ctx, tree t)
+cxx_union_active_member (const constexpr_ctx *ctx, tree t, tree *jump_target)
{
constexpr_ctx new_ctx = *ctx;
new_ctx.quiet = true;
bool non_constant_p = false, overflow_p = false;
tree ctor = cxx_eval_constant_expression (&new_ctx, t, vc_prvalue,
&non_constant_p,
- &overflow_p);
+ &overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (TREE_CODE (ctor) == CONSTRUCTOR
&& CONSTRUCTOR_NELTS (ctor) == 1
&& CONSTRUCTOR_ELT (ctor, 0)->index
@@ -5924,7 +6837,8 @@ cxx_union_active_member (const constexpr_ctx *ctx, tree t)
static tree
cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
- tree op, unsigned HOST_WIDE_INT off, bool *empty_base)
+ tree op, unsigned HOST_WIDE_INT off, bool *empty_base,
+ tree *jump_target)
{
tree optype = TREE_TYPE (op);
unsigned HOST_WIDE_INT const_nunits;
@@ -5941,7 +6855,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
than pointer type. */
if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc,
strip_array_types (optype),
- op, off, empty_base))
+ op, off, empty_base,
+ jump_target))
return fold_convert (type, ret);
}
else if (TREE_CODE (optype) == COMPLEX_TYPE
@@ -5987,7 +6902,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
NULL_TREE, NULL_TREE);
return cxx_fold_indirect_ref_1 (ctx, loc, type, op, rem,
- empty_base);
+ empty_base, jump_target);
}
}
/* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
@@ -5996,7 +6911,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
{
if (TREE_CODE (optype) == UNION_TYPE)
/* For unions prefer the currently active member. */
- if (tree field = cxx_union_active_member (ctx, op))
+ if (tree field = cxx_union_active_member (ctx, op, jump_target))
{
unsigned HOST_WIDE_INT el_sz
= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
@@ -6005,7 +6920,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
tree cop = build3 (COMPONENT_REF, TREE_TYPE (field),
op, field, NULL_TREE);
if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop,
- off, empty_base))
+ off, empty_base,
+ jump_target))
return ret;
}
}
@@ -6050,7 +6966,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
op, field, NULL_TREE);
if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc, type, cop,
off - upos,
- empty_base))
+ empty_base,
+ jump_target))
return ret;
}
}
@@ -6070,7 +6987,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
static tree
cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
- tree op0, bool *empty_base /* = NULL*/)
+ tree op0, bool *empty_base, tree *jump_target)
{
tree sub = op0;
tree subtype;
@@ -6152,7 +7069,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
tree off = integer_zero_node;
canonicalize_obj_off (op, off);
return cxx_fold_indirect_ref_1 (ctx, loc, type, op,
- tree_to_uhwi (off), empty_base);
+ tree_to_uhwi (off), empty_base,
+ jump_target);
}
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
@@ -6167,7 +7085,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
tree obj = TREE_OPERAND (op00, 0);
canonicalize_obj_off (obj, off);
return cxx_fold_indirect_ref_1 (ctx, loc, type, obj,
- tree_to_uhwi (off), empty_base);
+ tree_to_uhwi (off), empty_base,
+ jump_target);
}
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
@@ -6177,7 +7096,10 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
tree type_domain;
tree min_val = size_zero_node;
tree newsub
- = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL);
+ = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (newsub)
sub = newsub;
else
@@ -6195,7 +7117,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
static tree
cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree orig_op0 = TREE_OPERAND (t, 0);
bool empty_base = false;
@@ -6213,13 +7136,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
/* First try to simplify it directly. */
tree r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t),
- orig_op0, &empty_base);
+ orig_op0, &empty_base, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (!r)
{
/* If that didn't work, evaluate the operand first. */
tree op0 = cxx_eval_constant_expression (ctx, orig_op0,
vc_prvalue, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
@@ -6233,7 +7160,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
}
r = cxx_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), op0,
- &empty_base);
+ &empty_base, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (r == NULL_TREE)
{
/* We couldn't fold to a constant value. Make sure it's not
@@ -6263,7 +7192,10 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
}
r = cxx_eval_constant_expression (ctx, r,
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
@@ -6373,7 +7305,8 @@ non_const_var_error (location_t loc, tree r, bool fundef_p)
static tree
cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
int i;
tree args[3];
@@ -6383,7 +7316,10 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
{
args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (args[i]);
}
@@ -6505,7 +7441,8 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p)
static tree
cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
constexpr_ctx new_ctx = *ctx;
@@ -6531,7 +7468,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (!SCALAR_TYPE_P (type))
new_ctx.ctor = new_ctx.object = NULL_TREE;
init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
}
@@ -6543,8 +7483,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
as a whole; otherwise, only evaluate the innermost piece to avoid
building up unnecessary *_REFs. */
target = cxx_eval_constant_expression (ctx, target, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
evaluated = true;
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
}
@@ -6570,7 +7513,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (probe) == ARRAY_REF)
{
elt = eval_and_check_array_index (ctx, probe, false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
}
@@ -6627,8 +7573,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
break;
}
probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
evaluated = true;
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
}
@@ -6798,13 +7747,24 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (*valp), first, NULL_TREE);
/* Check for implicit change of active member for a union. */
+
+ /* LWG3436, CWG2675, c++/121068: The array object model is confused. For
+ now allow initializing an array element to activate the array. */
+ auto only_array_refs = [](const releasing_vec &refs)
+ {
+ for (unsigned i = 1; i < refs->length(); i += 3)
+ if (TREE_CODE ((*refs)[i]) != INTEGER_CST)
+ return false;
+ return true;
+ };
+
if (code == UNION_TYPE
&& (CONSTRUCTOR_NELTS (*valp) == 0
|| CONSTRUCTOR_ELT (*valp, 0)->index != index)
/* An INIT_EXPR of the last member in an access chain is always OK,
but still check implicit change of members earlier on; see
cpp2a/constexpr-union6.C. */
- && !(TREE_CODE (t) == INIT_EXPR && refs->is_empty ()))
+ && !(TREE_CODE (t) == INIT_EXPR && only_array_refs (refs)))
{
bool has_active_member = CONSTRUCTOR_NELTS (*valp) != 0;
tree inner = strip_array_types (reftype);
@@ -6972,7 +7932,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (tree tinit = TARGET_EXPR_INITIAL (init))
init = tinit;
init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* The hash table might have moved since the get earlier, and the
initializer might have mutated the underlying CONSTRUCTORs, so we must
recompute VALP. */
@@ -7098,7 +8061,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
enum tree_code code = TREE_CODE (t);
tree type = TREE_TYPE (t);
@@ -7112,12 +8076,18 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
/* The operand as an lvalue. */
op = cxx_eval_constant_expression (ctx, op, vc_glvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* The operand as an rvalue. */
tree val
= cxx_eval_constant_expression (ctx, op, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
a local array in a constexpr function. */
bool ptr = INDIRECT_TYPE_P (TREE_TYPE (val));
@@ -7156,8 +8126,11 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
tree store = build2_loc (cp_expr_loc_or_loc (t, input_location),
MODIFY_EXPR, type, op, mod);
mod = cxx_eval_constant_expression (ctx, store, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
ggc_free (store);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
@@ -7171,42 +8144,6 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
return val;
}
-/* Predicates for the meaning of *jump_target. */
-
-static bool
-returns (tree *jump_target)
-{
- return *jump_target
- && TREE_CODE (*jump_target) == RETURN_EXPR;
-}
-
-static bool
-breaks (tree *jump_target)
-{
- return *jump_target
- && ((TREE_CODE (*jump_target) == LABEL_DECL
- && LABEL_DECL_BREAK (*jump_target))
- || TREE_CODE (*jump_target) == BREAK_STMT
- || TREE_CODE (*jump_target) == EXIT_EXPR);
-}
-
-static bool
-continues (tree *jump_target)
-{
- return *jump_target
- && ((TREE_CODE (*jump_target) == LABEL_DECL
- && LABEL_DECL_CONTINUE (*jump_target))
- || TREE_CODE (*jump_target) == CONTINUE_STMT);
-
-}
-
-static bool
-switches (tree *jump_target)
-{
- return *jump_target
- && TREE_CODE (*jump_target) == INTEGER_CST;
-}
-
/* Subroutine of cxx_eval_statement_list. Determine whether the statement
STMT matches *jump_target. If we're looking for a case label and we see
the default label, note it in ctx->css_state. */
@@ -7254,6 +8191,11 @@ label_matches (const constexpr_ctx *ctx, tree *jump_target, tree stmt)
breaks (jump_target) or continues (jump_target). */
break;
+ case VAR_DECL:
+ /* Uncaught exception. This is handled by TRY_BLOCK evaluation
+ and other places by testing throws (jump_target). */
+ break;
+
default:
gcc_unreachable ();
}
@@ -7268,15 +8210,9 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
- tree local_target;
/* In a statement-expression we want to return the last value.
For empty statement expression return void_node. */
tree r = void_node;
- if (!jump_target)
- {
- local_target = NULL_TREE;
- jump_target = &local_target;
- }
for (tree_stmt_iterator i = tsi_start (t); !tsi_end_p (i); ++i)
{
tree stmt = *i;
@@ -7304,18 +8240,11 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
jump_target);
if (*non_constant_p)
break;
- if (returns (jump_target) || breaks (jump_target))
+ if (returns (jump_target)
+ || breaks (jump_target)
+ || throws (jump_target))
break;
}
- if (*jump_target && jump_target == &local_target)
- {
- /* We aren't communicating the jump to our caller, so give up. We don't
- need to support evaluation of jumps out of statement-exprs. */
- if (!ctx->quiet)
- error_at (cp_expr_loc_or_input_loc (r),
- "statement is not a constant expression");
- *non_constant_p = true;
- }
return r;
}
@@ -7327,13 +8256,6 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
- tree local_target;
- if (!jump_target)
- {
- local_target = NULL_TREE;
- jump_target = &local_target;
- }
-
tree body, cond = NULL_TREE, expr = NULL_TREE;
tree cond_prep = NULL_TREE, cond_cleanup = NULL_TREE;
unsigned cond_cleanup_depth = 0;
@@ -7389,7 +8311,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
tree c;
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, c)
cxx_eval_constant_expression (ctx, c, vc_discard, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
if (cond_prep)
for (tree decl = BIND_EXPR_VARS (cond_prep);
@@ -7484,7 +8406,8 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
if (*non_constant_p
|| returns (jump_target)
|| breaks (jump_target)
- || continues (jump_target))
+ || continues (jump_target)
+ || throws (jump_target))
{
depth = 1;
break;
@@ -7531,6 +8454,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
&& !breaks (jump_target)
&& !continues (jump_target)
&& (!switches (jump_target) || count == 0)
+ && !throws (jump_target)
&& !*non_constant_p);
cleanup_cond ();
@@ -7549,7 +8473,10 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
tree cond
= TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t);
cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (cond);
if (TREE_CODE (cond) != INTEGER_CST)
{
@@ -7682,7 +8609,8 @@ maybe_warn_about_constant_value (location_t loc, tree decl)
static tree
build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type,
tree cookie_size, tree full_size, tree arg_size,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size));
gcc_assert (tree_fits_uhwi_p (full_size));
@@ -7718,13 +8646,17 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type,
if (integer_zerop (op0))
arg_size
= cxx_eval_constant_expression (ctx, op1, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
else if (integer_zerop (op1))
arg_size
= cxx_eval_constant_expression (ctx, op0, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
else
arg_size = NULL_TREE;
+ if (*jump_target)
+ return NULL_TREE;
}
else
arg_size = NULL_TREE;
@@ -7745,6 +8677,38 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type,
return build_new_constexpr_heap_type (elt_type, cookie_size, itype2);
}
+/* Handle the case when a cleanup of some expression throws. JMP_TARGET
+ indicates whether the cleanup threw or not, *JUMP_TARGET indicates whether
+ the expression which needed the cleanup threw. If both threw, diagnose
+ it and return NULL, otherwise return R. If only the cleanup threw, set
+ *JUMP_TARGET to the exception object from the cleanup. */
+
+static tree
+merge_jump_target (location_t loc, const constexpr_ctx *ctx, tree r,
+ bool *non_constant_p, tree *jump_target, tree jmp_target)
+{
+ if (!throws (&jmp_target))
+ return r;
+ if (throws (jump_target))
+ {
+ /* [except.throw]/9 - If the exception handling mechanism
+ handling an uncaught exception directly invokes a function
+ that exits via an exception, the function std::terminate is
+ invoked. */
+ if (!ctx->quiet)
+ {
+ auto_diagnostic_group d;
+ diagnose_std_terminate (loc, ctx, *jump_target);
+ inform (loc, "destructor exited with an exception");
+ }
+ *non_constant_p = true;
+ *jump_target = NULL_TREE;
+ return NULL_TREE;
+ }
+ *jump_target = jmp_target;
+ return r;
+}
+
/* Attempt to reduce the expression T to a constant value.
On failure, issue diagnostic and return error_mark_node. */
/* FIXME unify with c_fully_fold */
@@ -7754,9 +8718,9 @@ static tree
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
value_cat lval,
bool *non_constant_p, bool *overflow_p,
- tree *jump_target /* = NULL */)
+ tree *jump_target)
{
- if (jump_target && *jump_target)
+ if (*jump_target)
{
/* If we are jumping, ignore all statements/expressions except those
that could have LABEL_EXPR or CASE_LABEL_EXPR in their bodies. */
@@ -7880,7 +8844,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = convert_from_reference (r);
}
return cxx_eval_constant_expression (ctx, r, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
/* fall through */
case CONST_DECL:
@@ -7958,7 +8922,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = v;
if (TREE_ADDRESSABLE (TREE_TYPE (t)))
r = cxx_eval_constant_expression (ctx, r, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
}
else if (lval)
/* Defer in case this is only used for its type. */;
@@ -7991,7 +8958,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case CALL_EXPR:
case AGGR_INIT_EXPR:
r = cxx_eval_call_expression (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case DECL_EXPR:
@@ -8055,7 +9022,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (tree init = DECL_INITIAL (r))
{
init = cxx_eval_constant_expression (ctx, init, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Don't share a CONSTRUCTOR that might be changed. */
init = unshare_constructor (init);
/* Remember that a constant object's constructor has already
@@ -8125,9 +9095,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* Pass vc_prvalue because this indicates
initialization of a temporary. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
break;
+ if (*jump_target)
+ return NULL_TREE;
if (!is_complex)
{
r = unshare_constructor (r);
@@ -8135,8 +9108,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = adjust_temp_type (type, r);
ctx->global->put_value (slot, r);
}
- if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t))
- ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t));
+ if (TARGET_EXPR_CLEANUP (t)
+ && (!CLEANUP_EH_ONLY (t) || cxx_dialect >= cxx26))
+ {
+ ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t));
+ /* Mark CLEANUP_EH_ONLY cleanups by pushing NULL_TREE after
+ them. */
+ if (CLEANUP_EH_ONLY (t))
+ ctx->global->cleanups->safe_push (NULL_TREE);
+ }
if (ctx->save_exprs)
ctx->save_exprs->safe_push (slot);
if (lval)
@@ -8150,33 +9130,28 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case MODIFY_EXPR:
gcc_assert (jump_target == NULL || *jump_target == NULL_TREE);
r = cxx_eval_store_expression (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case SCOPE_REF:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case RETURN_EXPR:
if (TREE_OPERAND (t, 0) != NULL_TREE)
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
lval,
- non_constant_p, overflow_p);
- /* FALLTHRU */
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!throws (jump_target))
+ *jump_target = t;
+ break;
case BREAK_STMT:
case CONTINUE_STMT:
- if (jump_target)
- *jump_target = t;
- else
- {
- /* Can happen with ({ return true; }) && false; passed to
- maybe_constant_value. There is nothing to jump over in this
- case, and the bug will be diagnosed later. */
- gcc_assert (ctx->quiet);
- *non_constant_p = true;
- }
+ *jump_target = t;
break;
case SAVE_EXPR:
@@ -8185,9 +9160,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = v;
else
{
- r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue,
- non_constant_p, overflow_p);
- if (*non_constant_p)
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+ vc_prvalue, non_constant_p,
+ overflow_p, jump_target);
+ if (*non_constant_p || *jump_target)
break;
ctx->global->put_value (t, r);
if (ctx->save_exprs)
@@ -8195,16 +9171,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
break;
- case TRY_CATCH_EXPR:
- if (TREE_OPERAND (t, 0) == NULL_TREE)
- {
- r = void_node;
- break;
- }
- /* FALLTHRU */
case NON_LVALUE_EXPR:
- case TRY_BLOCK:
- case MUST_NOT_THROW_EXPR:
case EXPR_STMT:
case EH_SPEC_BLOCK:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
@@ -8213,6 +9180,42 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
jump_target);
break;
+ case TRY_BLOCK:
+ r = cxx_eval_constant_expression (ctx, TRY_STMTS (t), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!*non_constant_p && throws (jump_target))
+ if (tree h = TRY_HANDLERS (t))
+ {
+ tree type = strip_array_types (TREE_TYPE (*jump_target));
+ if (TREE_CODE (h) == STATEMENT_LIST)
+ {
+ for (tree stmt : tsi_range (h))
+ if (TREE_CODE (stmt) == HANDLER
+ && handler_match_for_exception_type (stmt, type))
+ {
+ h = stmt;
+ break;
+ }
+ if (TREE_CODE (h) == STATEMENT_LIST)
+ h = NULL_TREE;
+ }
+ else if (TREE_CODE (h) != HANDLER
+ || !handler_match_for_exception_type (h, type))
+ h = NULL_TREE;
+ if (h)
+ {
+ gcc_assert (VAR_P (*jump_target));
+ ctx->global->caught_exceptions.safe_push (*jump_target);
+ ctx->global->caught_exceptions.safe_push (HANDLER_TYPE (h));
+ *jump_target = NULL_TREE;
+ r = cxx_eval_constant_expression (ctx, HANDLER_BODY (h),
+ vc_discard, non_constant_p,
+ overflow_p, jump_target);
+ }
+ }
+ break;
+
case CLEANUP_POINT_EXPR:
{
auto_vec<tree, 2> cleanups;
@@ -8230,47 +9233,132 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
ctx->global->cleanups = prev_cleanups;
unsigned int i;
- tree cleanup;
+ tree cleanup, jmp_target = NULL_TREE;
+ bool eh = throws (jump_target);
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
- cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard,
- non_constant_p, overflow_p);
+ if (cleanup == NULL_TREE)
+ {
+ /* NULL_TREE cleanup is a marker that before it is
+ CLEANUP_EH_ONLY cleanup. Skip the cleanup before it
+ if the body didn't throw. */
+ if (!eh)
+ --i;
+ }
+ else
+ cxx_eval_constant_expression (&new_ctx, cleanup, vc_discard,
+ non_constant_p, overflow_p,
+ &jmp_target);
/* Forget SAVE_EXPRs and TARGET_EXPRs created by this
full-expression. */
for (tree save_expr : save_exprs)
destroy_value_checked (ctx, save_expr, non_constant_p);
+ if (throws (&jmp_target))
+ *jump_target = jmp_target;
}
break;
+ case MUST_NOT_THROW_EXPR:
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+ lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (throws (jump_target))
+ {
+ /* [except.handle]/7 - If the search for a handler exits the
+ function body of a function with a non-throwing exception
+ specification, the function std::terminate is invoked. */
+ if (!ctx->quiet)
+ {
+ auto_diagnostic_group d;
+ diagnose_std_terminate (loc, ctx, *jump_target);
+ if (MUST_NOT_THROW_NOEXCEPT_P (t)
+ && ctx->call
+ && ctx->call->fundef)
+ inform (loc, "uncaught exception exited from %<noexcept%> "
+ "function %qD",
+ ctx->call->fundef->decl);
+ else if (MUST_NOT_THROW_THROW_P (t))
+ inform (loc, "destructor exited with an exception after "
+ "initializing the exception object");
+ else if (MUST_NOT_THROW_CATCH_P (t))
+ inform (loc, "constructor exited with another exception while "
+ "entering handler");
+ }
+ *non_constant_p = true;
+ *jump_target = NULL_TREE;
+ r = NULL_TREE;
+ }
+ break;
+
+ case TRY_CATCH_EXPR:
+ if (TREE_OPERAND (t, 0) == NULL_TREE)
+ {
+ r = void_node;
+ break;
+ }
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!*non_constant_p && throws (jump_target))
+ {
+ tree jmp_target = NULL_TREE;
+ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard,
+ non_constant_p, overflow_p,
+ &jmp_target);
+ r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target,
+ jmp_target);
+ }
+ break;
+
case TRY_FINALLY_EXPR:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
non_constant_p, overflow_p,
jump_target);
if (!*non_constant_p)
- /* Also evaluate the cleanup. */
- cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard,
- non_constant_p, overflow_p);
+ {
+ tree jmp_target = NULL_TREE;
+ /* Also evaluate the cleanup. */
+ if (TREE_CODE (TREE_OPERAND (t, 1)) == EH_ELSE_EXPR
+ && throws (jump_target))
+ cxx_eval_constant_expression (ctx,
+ TREE_OPERAND (TREE_OPERAND (t, 1),
+ 1), vc_discard,
+ non_constant_p, overflow_p,
+ &jmp_target);
+ else
+ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard,
+ non_constant_p, overflow_p,
+ &jmp_target);
+ r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target,
+ jmp_target);
+ }
break;
case EH_ELSE_EXPR:
/* Evaluate any cleanup that applies to non-EH exits. */
cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_discard,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
- /* We do not have constexpr exceptions yet, so skip the EH path. */
+ /* The EH path is handled in TRY_FINALLY_EXPR handling above. */
break;
case CLEANUP_STMT:
r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
non_constant_p, overflow_p,
jump_target);
- if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
+ if ((!CLEANUP_EH_ONLY (t) || throws (jump_target)) && !*non_constant_p)
{
iloc_sentinel ils (loc);
+ tree jmp_target = NULL_TREE;
/* Also evaluate the cleanup. */
cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), vc_discard,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ &jmp_target);
+ r = merge_jump_target (loc, ctx, r, non_constant_p, jump_target,
+ jmp_target);
}
break;
@@ -8280,14 +9368,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case MEM_REF:
case INDIRECT_REF:
r = cxx_eval_indirect_ref (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case ADDR_EXPR:
{
tree oldop = TREE_OPERAND (t, 0);
tree op = cxx_eval_constant_expression (ctx, oldop, vc_glvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
@@ -8307,7 +9399,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (lval)
{
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (r == error_mark_node)
;
else if (r == TREE_OPERAND (t, 0) || lval == vc_discard)
@@ -8328,7 +9423,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case FIXED_CONVERT_EXPR:
case VEC_DUPLICATE_EXPR:
r = cxx_eval_unary_expression (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case SIZEOF_EXPR:
@@ -8366,6 +9462,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
cxx_eval_constant_expression (ctx, op0, vc_discard,
non_constant_p, overflow_p,
jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
op1 = TREE_OPERAND (t, 1);
@@ -8418,7 +9516,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case RANGE_EXPR:
case COMPLEX_EXPR:
r = cxx_eval_binary_expression (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
/* fold can introduce non-IF versions of these; still treat them as
@@ -8427,19 +9526,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case TRUTH_ANDIF_EXPR:
r = cxx_eval_logical_expression (ctx, t, boolean_false_node,
boolean_true_node,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case TRUTH_OR_EXPR:
case TRUTH_ORIF_EXPR:
r = cxx_eval_logical_expression (ctx, t, boolean_true_node,
boolean_false_node,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case ARRAY_REF:
r = cxx_eval_array_reference (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case COMPONENT_REF:
@@ -8454,17 +9556,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return t;
}
r = cxx_eval_component_reference (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case BIT_FIELD_REF:
r = cxx_eval_bit_field_ref (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case COND_EXPR:
case IF_STMT:
- if (jump_target && *jump_target)
+ if (*jump_target)
{
tree orig_jump = *jump_target;
tree arg = ((TREE_CODE (t) != IF_STMT || TREE_OPERAND (t, 1))
@@ -8502,7 +9606,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
break;
case VEC_COND_EXPR:
r = cxx_eval_vector_conditional_expression (ctx, t, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
break;
case CONSTRUCTOR:
@@ -8514,7 +9618,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return t;
}
r = cxx_eval_bare_aggregate (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case VEC_INIT_EXPR:
@@ -8524,12 +9628,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
or xvalue of the same type, meaning direct-initialization from the
corresponding member. */
r = cxx_eval_vec_init (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case VEC_PERM_EXPR:
r = cxx_eval_trinary_expression (ctx, t, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case PAREN_EXPR:
@@ -8537,7 +9642,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in
constant expressions since it's unaffected by -fassociative-math. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
break;
case NOP_EXPR:
@@ -8561,7 +9667,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
? vc_discard
: tcode == VIEW_CONVERT_EXPR
? lval : vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
tree type = TREE_TYPE (t);
@@ -8618,7 +9727,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{
if (integer_zerop (sop))
return build_int_cst (type, 0);
- r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop);
+ r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop,
+ NULL, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (r)
{
r = build1 (ADDR_EXPR, type, r);
@@ -8745,10 +9857,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (cxx_replaceable_global_alloc_fn (fun)
&& IDENTIFIER_NEW_OP_P (DECL_NAME (fun)))
arg_size = CALL_EXPR_ARG (oldop, 0);
- TREE_TYPE (var)
+ tree new_type
= build_new_constexpr_heap_type (ctx, elt_type, cookie_size,
var_size, arg_size,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ TREE_TYPE (var) = new_type;
TREE_TYPE (TREE_OPERAND (op, 0))
= build_pointer_type (TREE_TYPE (var));
}
@@ -8787,7 +9903,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree op = cxx_eval_constant_expression (ctx, oldop,
lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
if (*non_constant_p)
return t;
r = fold_convert (TREE_TYPE (t), op);
@@ -8824,14 +9943,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
return cxx_eval_increment_expression (ctx, t,
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p,
+ jump_target);
+ case THROW_EXPR:
+ if (cxx_dialect >= cxx26)
+ return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ /* FALLTHROUGH */
case LAMBDA_EXPR:
case NEW_EXPR:
case VEC_NEW_EXPR:
case DELETE_EXPR:
case VEC_DELETE_EXPR:
- case THROW_EXPR:
case MODOP_EXPR:
/* GCC internal stuff. */
case VA_ARG_EXPR:
@@ -8845,7 +9970,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case OBJ_TYPE_REF:
/* Virtual function lookup. We don't need to do anything fancy. */
return cxx_eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t),
- lval, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p,
+ jump_target);
case PLACEHOLDER_EXPR:
/* Use of the value or address of the current object. */
@@ -8855,7 +9981,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return ctor;
else
return cxx_eval_constant_expression (ctx, ctor, lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
}
/* A placeholder without a referent. We can get here when
checking whether NSDMIs are noexcept, or in massage_init_elt;
@@ -8868,7 +9995,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{
tree cond = TREE_OPERAND (t, 0);
cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
VERIFY_CONSTANT (cond);
if (integer_nonzerop (cond))
*jump_target = t;
@@ -8980,7 +10110,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p);
+ r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p, jump_target);
break;
case OMP_PARALLEL:
@@ -9202,11 +10332,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
{
if (cxx_dialect < cxx20)
return t;
- if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+ /* We could have a COMPOUND_EXPR here coming from
+ keep_unused_object_arg. */
+ tree x = extract_call_expr (t);
+ if (x == NULL_TREE || x == error_mark_node)
return t;
/* Calls to immediate functions returning void need to be
evaluated. */
- tree fndecl = cp_get_callee_fndecl_nofold (t);
+ tree fndecl = cp_get_callee_fndecl_nofold (x);
if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
return t;
else
@@ -9299,8 +10432,34 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (manifestly_const_eval == mce_true)
instantiate_constexpr_fns (r);
+ tree jmp_target = NULL_TREE;
r = cxx_eval_constant_expression (&ctx, r, vc_prvalue,
- &non_constant_p, &overflow_p);
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ if (throws (&jmp_target) && !non_constant_p)
+ {
+ if (!ctx.quiet)
+ diagnose_uncaught_exception (input_location, &ctx, jmp_target);
+ non_constant_p = true;
+ jmp_target = NULL_TREE;
+ r = t;
+ }
+ else if (!non_constant_p && jmp_target)
+ {
+ non_constant_p = true;
+ if (!ctx.quiet)
+ {
+ if (breaks (&jmp_target))
+ error ("%<break%> outside of a loop or %<switch%>");
+ else if (continues (&jmp_target))
+ error ("%<continue%> outside of a loop");
+ else if (returns (&jmp_target))
+ error ("%<return%> in a statement expression");
+ else
+ gcc_unreachable ();
+ }
+ r = t;
+ }
/* If we got a non-simple TARGET_EXPR, the initializer was a sequence
of statements, and the result ought to be stored in ctx.ctor. */
@@ -9309,15 +10468,31 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
unsigned int i;
tree cleanup;
+ jmp_target = NULL_TREE;
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
- cxx_eval_constant_expression (&ctx, cleanup, vc_discard,
- &non_constant_p, &overflow_p);
+ if (cleanup == NULL_TREE)
+ /* NULL_TREE cleanup is a marker that before it is
+ CLEANUP_EH_ONLY cleanup. Skip the cleanup before it. */
+ --i;
+ else
+ cxx_eval_constant_expression (&ctx, cleanup, vc_discard,
+ &non_constant_p, &overflow_p,
+ &jmp_target);
+ if (throws (&jmp_target) && !non_constant_p)
+ {
+ if (!ctx.quiet)
+ diagnose_uncaught_exception (input_location, &ctx, jmp_target);
+ non_constant_p = true;
+ r = t;
+ }
/* Mutable logic is a bit tricky: we want to allow initialization of
constexpr variables with mutable members, but we can't copy those
members to another constexpr variable. */
- if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r))
+ if (!non_constant_p
+ && TREE_CODE (r) == CONSTRUCTOR
+ && CONSTRUCTOR_MUTABLE_POISON (r))
{
if (!allow_non_constant)
error ("%qE is not a constant expression because it refers to "
@@ -9335,8 +10510,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
{
if (!allow_non_constant && !non_constant_p)
{
- error ("%qE is not a constant expression because it refers to "
- "a result of %<operator new%>", t);
+ if (DECL_LANG_SPECIFIC (heap_var))
+ error ("%qE is not a constant expression because it refers to "
+ "exception object allocated with "
+ "%<__cxa_allocate_exception%>", t);
+ else
+ error ("%qE is not a constant expression because it refers to "
+ "a result of %<operator new%>", t);
inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
}
r = t;
@@ -9917,6 +11097,24 @@ cxx_constant_init (tree t, tree decl)
return maybe_constant_init_1 (t, decl, false, mce_true);
}
+/* Return true if CALL_EXPR T might throw during constant evaluation. */
+
+static bool
+callee_might_throw (tree t)
+{
+ if (cxx_dialect < cxx26 || !flag_exceptions)
+ return false;
+ tree callee = cp_get_callee (t);
+ if (callee == NULL_TREE)
+ return false;
+ tree callee_fn = cp_get_fndecl_from_callee (callee, false);
+ return (!flag_enforce_eh_specs
+ || type_dependent_expression_p (callee)
+ || !POINTER_TYPE_P (TREE_TYPE (callee))
+ || (!type_noexcept_p (TREE_TYPE (TREE_TYPE (callee)))
+ && (callee_fn == NULL_TREE || !TREE_NOTHROW (callee_fn))));
+}
+
#if 0
/* FIXME see ADDR_EXPR section in potential_constant_expression_1. */
/* Return true if the object referred to by REF has automatic or thread
@@ -9949,11 +11147,13 @@ struct check_for_return_continue_data {
hash_set<tree> *pset;
tree continue_stmt;
tree break_stmt;
+ bool could_throw;
};
/* Helper function for potential_constant_expression_1 SWITCH_STMT handling,
called through cp_walk_tree. Return the first RETURN_EXPR found, or note
- the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. */
+ the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found.
+ For C++26 also note presence of possibly throwing calls. */
static tree
check_for_return_continue (tree *tp, int *walk_subtrees, void *data)
{
@@ -10038,6 +11238,13 @@ check_for_return_continue (tree *tp, int *walk_subtrees, void *data)
case CONSTRUCTOR:
break;
+ case AGGR_INIT_EXPR:
+ case CALL_EXPR:
+ /* In C++26 a function could throw. */
+ if (callee_might_throw (t))
+ d->could_throw = true;
+ break;
+
default:
if (!EXPR_P (t))
*walk_subtrees = 0;
@@ -10243,8 +11450,27 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
|| TREE_CODE (t) != CALL_EXPR
|| current_function_decl == NULL_TREE
|| !is_std_construct_at (current_function_decl))
- && !cxx_dynamic_cast_fn_p (fun))
+ && !cxx_dynamic_cast_fn_p (fun)
+ && !cxx_cxa_builtin_fn_p (fun))
{
+ /* In C++26 evaluation of the function arguments might
+ throw and in that case it is irrelevant whether
+ fun is constexpr or not. */
+ if (cxx_dialect >= cxx26)
+ for (; i < nargs; ++i)
+ {
+ tree x = get_nth_callarg (t, i);
+ bool rv = processing_template_decl ? any : rval;
+ bool sub_now = false;
+ if (!potential_constant_expression_1 (x, rv, strict,
+ sub_now,
+ fundef_p,
+ flags,
+ jump_target))
+ return false;
+ if (throws (jump_target))
+ return true;
+ }
if ((flags & tf_error)
&& constexpr_error (loc, fundef_p,
"call to non-%<constexpr%> "
@@ -10289,7 +11515,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
sub_now, fundef_p, flags,
jump_target))
return false;
+ if (throws (jump_target))
+ return true;
}
+ /* In C++26 a function could throw. */
+ if (*jump_target == NULL_TREE && callee_might_throw (t))
+ *jump_target = void_node;
return true;
}
@@ -10512,11 +11743,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
a return. */
hash_set<tree> pset;
check_for_return_continue_data data = { &pset, NULL_TREE,
- NULL_TREE };
+ NULL_TREE, false };
if (tree ret_expr
= cp_walk_tree (&FOR_BODY (t), check_for_return_continue,
&data, &pset))
*jump_target = ret_expr;
+ if (data.could_throw)
+ *jump_target = void_node;
return true;
}
}
@@ -10556,11 +11789,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
a return. */
hash_set<tree> pset;
check_for_return_continue_data data = { &pset, NULL_TREE,
- NULL_TREE };
+ NULL_TREE, false };
if (tree ret_expr
= cp_walk_tree (&WHILE_BODY (t), check_for_return_continue,
&data, &pset))
*jump_target = ret_expr;
+ if (data.could_throw)
+ *jump_target = void_node;
return true;
}
if (!RECUR (WHILE_BODY (t), any))
@@ -10584,7 +11819,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
{
hash_set<tree> pset;
check_for_return_continue_data data = { &pset, NULL_TREE,
- NULL_TREE };
+ NULL_TREE, false };
if (tree ret_expr
= cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue,
&data, &pset))
@@ -10593,6 +11828,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
else if (data.continue_stmt)
/* The switch can't return, but might continue. */
*jump_target = data.continue_stmt;
+ if (data.could_throw)
+ *jump_target = void_node;
}
return true;
@@ -10622,7 +11859,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case DYNAMIC_CAST_EXPR:
case PSEUDO_DTOR_EXPR:
- case THROW_EXPR:
case OMP_PARALLEL:
case OMP_TASK:
case OMP_FOR:
@@ -10678,6 +11914,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
constant. */
return true;
+ case THROW_EXPR:
+ if (cxx_dialect < cxx26)
+ goto fail;
+ return RECUR (TREE_OPERAND (t, 0), rval);
+
case ASM_EXPR:
if (flags & tf_error)
inline_asm_in_constexpr_error (loc, fundef_p);
@@ -10806,6 +12047,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CLEANUP_POINT_EXPR:
case MUST_NOT_THROW_EXPR:
case TRY_CATCH_EXPR:
+ /* Even for C++26 handle TRY_BLOCK conservatively, if we detect the
+ body could throw, even with catch (...) among handlers we'd need
+ to analyze them in detail if they couldn't rethrow it. More
+ importantly though, throws (jump_target) is just conservative,
+ and there could be e.g.
+ try
+ {
+ possibly_throwing_fn (args);
+ break;
+ }
+ catch (...)
+ {
+ }
+ or continue or return instead of break. So, clearing *jump_target
+ because we see catch (...) handler might mean we missed break
+ etc. */
case TRY_BLOCK:
case EH_SPEC_BLOCK:
case EXPR_STMT:
@@ -11047,9 +12304,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
want_rval, strict, now, fundef_p,
tf_none, &this_jump_target))
{
- if (returns (&this_jump_target))
+ if (returns (&this_jump_target) || throws (&this_jump_target))
*jump_target = this_jump_target;
- else if (!returns (jump_target))
+ else if (!returns (jump_target) && !throws (jump_target))
{
if (breaks (&this_jump_target)
|| continues (&this_jump_target))
@@ -11061,7 +12318,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
couldn't return, break or continue. */
hash_set<tree> pset;
check_for_return_continue_data data = { &pset, NULL_TREE,
- NULL_TREE };
+ NULL_TREE,
+ false };
if (tree ret_expr
= cp_walk_tree (&TREE_OPERAND (t, 2),
check_for_return_continue, &data,
@@ -11074,6 +12332,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
else if (data.break_stmt)
*jump_target = data.break_stmt;
}
+ if (data.could_throw)
+ *jump_target = void_node;
}
}
return true;
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c8eef24..cbdfafc 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2490,10 +2490,11 @@ satisfy_atom (tree t, tree args, sat_info info)
result = force_rvalue (result, info.complain);
if (result == error_mark_node)
return cache.save (inst_cache.save (error_mark_node));
+ tree substituted = result;
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
{
if (info.noisy ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (error_mark_node));
}
@@ -2511,7 +2512,7 @@ satisfy_atom (tree t, tree args, sat_info info)
}
result = satisfaction_value (result);
if (result == boolean_false_node && info.diagnose_unsatisfaction_p ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (result));
}
@@ -3063,11 +3064,9 @@ get_constraint_error_location (tree t)
/* Emit a diagnostic for a failed trait. */
-static void
-diagnose_trait_expr (tree expr, tree args)
+void
+diagnose_trait_expr (location_t loc, tree expr, tree args)
{
- location_t loc = cp_expr_location (expr);
-
/* Build a "fake" version of the instantiated trait, so we can
get the instantiated types from result. */
++processing_template_decl;
@@ -3076,209 +3075,245 @@ diagnose_trait_expr (tree expr, tree args)
tree t1 = TRAIT_EXPR_TYPE1 (expr);
tree t2 = TRAIT_EXPR_TYPE2 (expr);
- if (t2 && TREE_CODE (t2) == TREE_VEC)
- {
- /* Convert the TREE_VEC of arguments into a TREE_LIST, since we can't
- directly print a TREE_VEC but we can a TREE_LIST via the E format
- specifier. */
- tree list = NULL_TREE;
- for (tree t : tree_vec_range (t2))
- list = tree_cons (NULL_TREE, t, list);
- t2 = nreverse (list);
- }
+
+ /* For traits intrinsically about the properties of user-defined types,
+ decl_loc will point to the declaration of that type. */
+ location_t decl_loc = location_of (t1);
+ if (decl_loc == input_location)
+ decl_loc = loc;
+
switch (TRAIT_EXPR_KIND (expr))
{
case CPTK_HAS_NOTHROW_ASSIGN:
- inform (loc, " %qT is not nothrow copy assignable", t1);
+ inform (decl_loc, "%qT is not nothrow copy assignable", t1);
break;
case CPTK_HAS_NOTHROW_CONSTRUCTOR:
- inform (loc, " %qT is not nothrow default constructible", t1);
+ inform (decl_loc, "%qT is not nothrow default constructible", t1);
break;
case CPTK_HAS_NOTHROW_COPY:
- inform (loc, " %qT is not nothrow copy constructible", t1);
+ inform (decl_loc, "%qT is not nothrow copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_ASSIGN:
- inform (loc, " %qT is not trivially copy assignable", t1);
+ inform (decl_loc, "%qT is not trivially copy assignable", t1);
break;
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
- inform (loc, " %qT is not trivially default constructible", t1);
+ inform (decl_loc, "%qT is not trivially default constructible", t1);
break;
case CPTK_HAS_TRIVIAL_COPY:
- inform (loc, " %qT is not trivially copy constructible", t1);
+ inform (decl_loc, "%qT is not trivially copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (decl_loc, "%qT is not trivially destructible", t1);
break;
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
- inform (loc, " %qT does not have unique object representations", t1);
+ inform (decl_loc, "%qT does not have unique object representations", t1);
break;
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
- inform (loc, " %qT does not have a virtual destructor", t1);
+ {
+ location_t dtor_loc = decl_loc;
+ if (NON_UNION_CLASS_TYPE_P (t1))
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t1))
+ dtor_loc = DECL_SOURCE_LOCATION (dtor);
+ inform (dtor_loc, "%qT does not have a virtual destructor", t1);
+ }
break;
case CPTK_IS_ABSTRACT:
- inform (loc, " %qT is not an abstract class", t1);
+ inform (decl_loc, "%qT is not an abstract class", t1);
break;
case CPTK_IS_AGGREGATE:
- inform (loc, " %qT is not an aggregate", t1);
+ inform (decl_loc, "%qT is not an aggregate", t1);
break;
case CPTK_IS_ARRAY:
- inform (loc, " %qT is not an array", t1);
+ inform (loc, "%qT is not an array", t1);
break;
case CPTK_IS_ASSIGNABLE:
- inform (loc, " %qT is not assignable from %qT", t1, t2);
+ inform (loc, "%qT is not assignable from %qT, because", t1, t2);
+ is_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_BASE_OF:
- inform (loc, " %qT is not a base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a base of %qT", t1, t2);
break;
case CPTK_IS_BOUNDED_ARRAY:
- inform (loc, " %qT is not a bounded array", t1);
+ inform (loc, "%qT is not a bounded array", t1);
break;
case CPTK_IS_CLASS:
- inform (loc, " %qT is not a class", t1);
+ inform (decl_loc, "%qT is not a class", t1);
break;
case CPTK_IS_CONST:
- inform (loc, " %qT is not a const type", t1);
+ inform (loc, "%qT is not a const type", t1);
break;
case CPTK_IS_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not default constructible, because", t1);
else
- inform (loc, " %qT is not constructible from %qE", t1, t2);
+ inform (loc, "%qT is not constructible from %qT, because", t1, t2);
+ is_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_CONVERTIBLE:
- inform (loc, " %qT is not convertible from %qE", t2, t1);
+ /* The errors produced here all seem to mention "convertible" in the
+ diagnostic, so an extra inform here appears redundant. */
+ is_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_DESTRUCTIBLE:
- inform (loc, " %qT is not destructible", t1);
+ inform (loc, "%qT is not destructible, because", t1);
+ is_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_EMPTY:
- inform (loc, " %qT is not an empty class", t1);
+ inform (decl_loc, "%qT is not an empty class", t1);
break;
case CPTK_IS_ENUM:
- inform (loc, " %qT is not an enum", t1);
+ inform (decl_loc, "%qT is not an enum", t1);
break;
case CPTK_IS_FINAL:
- inform (loc, " %qT is not a final class", t1);
+ inform (decl_loc, "%qT is not a final class", t1);
break;
case CPTK_IS_FUNCTION:
- inform (loc, " %qT is not a function", t1);
+ inform (loc, "%qT is not a function", t1);
break;
case CPTK_IS_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not invocable", t1);
- else
- inform (loc, " %qT is not invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not invocable, because", t1);
+ else
+ inform (loc, "%qT is not invocable by %qT, because", t1, t2);
+ build_invoke (t1, t2, tf_error);
+ }
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
- inform (loc, " %qT is not layout compatible with %qT", t1, t2);
+ inform (loc, "%qT is not layout compatible with %qT", t1, t2);
break;
case CPTK_IS_LITERAL_TYPE:
- inform (loc, " %qT is not a literal type", t1);
+ inform (decl_loc, "%qT is not a literal type", t1);
break;
case CPTK_IS_MEMBER_FUNCTION_POINTER:
- inform (loc, " %qT is not a member function pointer", t1);
+ inform (loc, "%qT is not a member function pointer", t1);
break;
case CPTK_IS_MEMBER_OBJECT_POINTER:
- inform (loc, " %qT is not a member object pointer", t1);
+ inform (loc, "%qT is not a member object pointer", t1);
break;
case CPTK_IS_MEMBER_POINTER:
- inform (loc, " %qT is not a member pointer", t1);
+ inform (loc, "%qT is not a member pointer", t1);
break;
case CPTK_IS_NOTHROW_ASSIGNABLE:
- inform (loc, " %qT is not nothrow assignable from %qT", t1, t2);
+ inform (loc, "%qT is not nothrow assignable from %qT, because", t1, t2);
+ is_nothrow_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not nothrow default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow default constructible, because", t1);
else
- inform (loc, " %qT is not nothrow constructible from %qE", t1, t2);
+ inform (loc, "%qT is not nothrow constructible from %qT, because",
+ t1, t2);
+ is_nothrow_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONVERTIBLE:
- inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
+ inform (loc, "%qT is not nothrow convertible from %qT, because", t1, t2);
+ is_nothrow_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_DESTRUCTIBLE:
- inform (loc, " %qT is not nothrow destructible", t1);
+ inform (loc, "%qT is not nothrow destructible, because", t1);
+ is_nothrow_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not nothrow invocable", t1);
- else
- inform (loc, " %qT is not nothrow invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow invocable, because", t1);
+ else
+ inform (loc, "%qT is not nothrow invocable by %qT, because", t1, t2);
+ tree call = build_invoke (t1, t2, tf_error);
+ if (call != error_mark_node)
+ explain_not_noexcept (call);
+ }
+ break;
+ case CPTK_IS_NOTHROW_RELOCATABLE:
+ inform (loc, "%qT is not nothrow relocatable", t1);
break;
case CPTK_IS_OBJECT:
- inform (loc, " %qT is not an object type", t1);
+ inform (loc, "%qT is not an object type", t1);
break;
case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
- inform (loc, " %qT is not pointer-interconvertible base of %qT",
+ inform (decl_loc, "%qT is not a pointer-interconvertible base of %qT",
t1, t2);
break;
case CPTK_IS_POD:
- inform (loc, " %qT is not a POD type", t1);
+ inform (loc, "%qT is not a POD type", t1);
break;
case CPTK_IS_POINTER:
- inform (loc, " %qT is not a pointer", t1);
+ inform (loc, "%qT is not a pointer", t1);
break;
case CPTK_IS_POLYMORPHIC:
- inform (loc, " %qT is not a polymorphic type", t1);
+ inform (decl_loc, "%qT is not a polymorphic type", t1);
break;
case CPTK_IS_REFERENCE:
- inform (loc, " %qT is not a reference", t1);
+ inform (loc, "%qT is not a reference", t1);
+ break;
+ case CPTK_IS_REPLACEABLE:
+ inform (loc, "%qT is not replaceable", t1);
break;
case CPTK_IS_SAME:
- inform (loc, " %qT is not the same as %qT", t1, t2);
+ inform (loc, "%q#T is not the same as %q#T", t1, t2);
break;
case CPTK_IS_SCOPED_ENUM:
- inform (loc, " %qT is not a scoped enum", t1);
+ inform (decl_loc, "%qT is not a scoped enum", t1);
break;
case CPTK_IS_STD_LAYOUT:
- inform (loc, " %qT is not an standard layout type", t1);
+ inform (decl_loc, "%qT is not a standard layout type", t1);
break;
case CPTK_IS_TRIVIAL:
- inform (loc, " %qT is not a trivial type", t1);
+ inform (decl_loc, "%qT is not a trivial type", t1);
break;
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
- inform (loc, " %qT is not trivially assignable from %qT", t1, t2);
+ inform (loc, "%qT is not trivially assignable from %qT, because", t1, t2);
+ is_trivially_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not trivially default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not trivially default constructible, because", t1);
else
- inform (loc, " %qT is not trivially constructible from %qE", t1, t2);
+ inform (loc, "%qT is not trivially constructible from %qT, because",
+ t1, t2);
+ is_trivially_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_COPYABLE:
- inform (loc, " %qT is not trivially copyable", t1);
+ inform (decl_loc, "%qT is not trivially copyable", t1);
break;
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (loc, "%qT is not trivially destructible, because", t1);
+ is_trivially_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
+ break;
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
+ inform (loc, "%qT is not trivially relocatable", t1);
break;
case CPTK_IS_UNBOUNDED_ARRAY:
- inform (loc, " %qT is not an unbounded array", t1);
+ inform (loc, "%qT is not an unbounded array", t1);
break;
case CPTK_IS_UNION:
- inform (loc, " %qT is not a union", t1);
+ inform (decl_loc, "%qT is not a union", t1);
break;
case CPTK_IS_VIRTUAL_BASE_OF:
- inform (loc, " %qT is not a virtual base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a virtual base of %qT", t1, t2);
+ if (CLASS_TYPE_P (t2))
+ inform (location_of (t2), "%qT declared here", t2);
break;
case CPTK_IS_VOLATILE:
- inform (loc, " %qT is not a volatile type", t1);
+ inform (loc, "%qT is not a volatile type", t1);
break;
case CPTK_RANK:
- inform (loc, " %qT cannot yield a rank", t1);
+ inform (loc, "%qT cannot yield a rank", t1);
break;
case CPTK_TYPE_ORDER:
- inform (loc, " %qT and %qT cannot be ordered", t1, t2);
+ inform (loc, "%qT and %qT cannot be ordered", t1, t2);
break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (direct-initialization)", t1, t2);
break;
case CPTK_REF_CONVERTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (copy-initialization)", t1, t2);
break;
case CPTK_IS_DEDUCIBLE:
- inform (loc, " %qD is not deducible from %qT", t1, t2);
+ inform (loc, "%qD is not deducible from %qT", t1, t2);
break;
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
case CPTK_##CODE:
@@ -3291,10 +3326,50 @@ diagnose_trait_expr (tree expr, tree args)
}
}
+/* Attempt to detect if this is a standard type trait, defined in terms
+ of a compiler builtin (above). If so, this will allow us to provide
+ more helpful diagnostics. */
+
+bool
+maybe_diagnose_standard_trait (location_t loc, tree expr)
+{
+ gcc_assert (TREE_CODE (expr) != TRAIT_EXPR);
+ expr = tree_strip_nop_conversions (expr);
+
+ /* TODO: in some cases it would be possible to provide more helpful
+ diagnostics for negations of traits, e.g. '!is_same_v<T1, T2>'. */
+
+ tree args = NULL_TREE;
+ if (VAR_P (expr) && DECL_LANG_SPECIFIC (expr) && DECL_USE_TEMPLATE (expr))
+ {
+ tree tinfo = DECL_TEMPLATE_INFO (expr);
+ if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) && TI_PARTIAL_INFO (tinfo))
+ tinfo = TI_PARTIAL_INFO (tinfo);
+ else if (DECL_TEMPLATE_SPECIALIZATION (expr))
+ /* In an explicit specialisation we no longer know what the original
+ initializer looked like. */
+ tinfo = NULL_TREE;
+
+ if (tinfo)
+ {
+ expr = DECL_INITIAL (DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)));
+ args = TI_ARGS (tinfo);
+ }
+ }
+
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ {
+ diagnose_trait_expr (loc, expr, args);
+ return true;
+ }
+
+ return false;
+}
+
/* Diagnose a substitution failure in the atomic constraint T using ARGS. */
static void
-diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
+diagnose_atomic_constraint (tree t, tree args, tree substituted, sat_info info)
{
/* If the constraint is already ill-formed, we've previously diagnosed
the reason. We should still say why the constraints aren't satisfied. */
@@ -3315,25 +3390,26 @@ diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
/* Generate better diagnostics for certain kinds of expressions. */
tree expr = ATOMIC_CONSTR_EXPR (t);
STRIP_ANY_LOCATION_WRAPPER (expr);
- switch (TREE_CODE (expr))
+
+ if (TREE_CODE (expr) == REQUIRES_EXPR)
{
- case TRAIT_EXPR:
- diagnose_trait_expr (expr, args);
- break;
- case REQUIRES_EXPR:
gcc_checking_assert (info.diagnose_unsatisfaction_p ());
/* Clear in_decl before replaying the substitution to avoid emitting
seemingly unhelpful "in declaration ..." notes that follow some
substitution failure error messages. */
info.in_decl = NULL_TREE;
tsubst_requires_expr (expr, args, info);
- break;
- default:
- if (!same_type_p (TREE_TYPE (result), boolean_type_node))
- error_at (loc, "constraint %qE has type %qT, not %<bool%>",
- t, TREE_TYPE (result));
+ }
+ else if (!same_type_p (TREE_TYPE (substituted), boolean_type_node))
+ error_at (loc, "constraint %qE has type %qT, not %<bool%>",
+ t, TREE_TYPE (substituted));
+ else
+ {
+ inform (loc, "the expression %qE evaluated to %<false%>", t);
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ diagnose_trait_expr (loc, expr, args);
else
- inform (loc, "the expression %qE evaluated to %<false%>", t);
+ maybe_diagnose_standard_trait (loc, substituted);
}
}
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 52cc186..690e510 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -5050,6 +5050,8 @@ cp_coroutine_transform::build_ramp_function ()
check the returned pointer and call the func if it's null.
Otherwise, no check, and we fail for noexcept/fno-exceptions cases. */
+ tree grooaf_if_stmt = NULL_TREE;
+ tree alloc_ok_scope = NULL_TREE;
if (grooaf)
{
/* [dcl.fct.def.coroutine] / 10 (part 3)
@@ -5057,20 +5059,11 @@ cp_coroutine_transform::build_ramp_function ()
control to the caller of the coroutine and the return value is
obtained by a call to T::get_return_object_on_allocation_failure(),
where T is the promise type. */
- tree if_stmt = begin_if_stmt ();
tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node);
- cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
- finish_if_stmt_cond (cond, if_stmt);
- r = NULL_TREE;
- if (void_ramp_p)
- /* Execute the get-return-object-on-alloc-fail call... */
- finish_expr_stmt (grooaf);
- else
- /* Get the fallback return object. */
- r = grooaf;
- finish_return_stmt (r);
- finish_then_clause (if_stmt);
- finish_if_stmt (if_stmt);
+ cond = build2 (NE_EXPR, boolean_type_node, coro_fp, cond);
+ grooaf_if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (cond, grooaf_if_stmt);
+ alloc_ok_scope = begin_compound_stmt (BCS_NORMAL);
}
/* Dereference the frame pointer, to use in member access code. */
@@ -5295,7 +5288,6 @@ cp_coroutine_transform::build_ramp_function ()
a temp which is then used to intialize the return object, including
NVRO. */
- /* Temporary var to hold the g_r_o across the function body. */
coro_gro
= coro_build_and_push_artificial_var (loc, "_Coro_gro", gro_type,
orig_fn_decl, NULL_TREE);
@@ -5328,9 +5320,28 @@ cp_coroutine_transform::build_ramp_function ()
/* The ramp is done, we just need the return statement, which we build from
the return object we constructed before we called the actor. */
+ /* This is our 'normal' exit. */
r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro);
finish_return_stmt (r);
+ if (grooaf)
+ {
+ finish_compound_stmt (alloc_ok_scope);
+ finish_then_clause (grooaf_if_stmt);
+
+ begin_else_clause (grooaf_if_stmt);
+ /* We come here if the frame allocation failed. */
+ r = NULL_TREE;
+ if (void_ramp_p)
+ /* Execute the get-return-object-on-alloc-fail call... */
+ finish_expr_stmt (grooaf);
+ else
+ /* Get the fallback return object. */
+ r = grooaf;
+ finish_return_stmt (r);
+ finish_if_stmt (grooaf_if_stmt);
+ }
+
finish_compound_stmt (ramp_fnbody);
return true;
}
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index ce69bd6..4ff8f36a 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -690,6 +690,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
&& (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
op1 = build_fold_addr_expr (op1);
+ suppress_warning (op1, OPT_Wunused_result);
gimplify_and_add (op1, pre_p);
}
gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
@@ -889,6 +890,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;
}
@@ -3022,7 +3029,7 @@ cp_fold (tree x, fold_flags_t flags)
case CLEANUP_POINT_EXPR:
/* Strip CLEANUP_POINT_EXPR if the expression doesn't have side
effects. */
- r = cp_fold_rvalue (TREE_OPERAND (x, 0), flags);
+ r = cp_fold (TREE_OPERAND (x, 0), flags);
if (!TREE_SIDE_EFFECTS (r))
x = r;
break;
@@ -3211,7 +3218,16 @@ cp_fold (tree x, fold_flags_t flags)
loc = EXPR_LOCATION (x);
op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops, flags);
- op1 = cp_fold_rvalue (TREE_OPERAND (x, 1), flags);
+ bool clear_decl_read;
+ clear_decl_read = false;
+ if (code == MODIFY_EXPR
+ && (VAR_P (op0) || TREE_CODE (op0) == PARM_DECL)
+ && !DECL_READ_P (op0))
+ clear_decl_read = true;
+ op1 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 1),
+ code != COMPOUND_EXPR, flags);
+ if (clear_decl_read)
+ DECL_READ_P (op0) = 0;
/* decltype(nullptr) has only one value, so optimize away all comparisons
with that type right away, keeping them in the IL causes troubles for
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e71b28c..9fedfd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -87,12 +87,14 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
DEFTRAIT_EXPR (IS_NOTHROW_DESTRUCTIBLE, "__is_nothrow_destructible", 1)
DEFTRAIT_EXPR (IS_NOTHROW_INVOCABLE, "__is_nothrow_invocable", -1)
+DEFTRAIT_EXPR (IS_NOTHROW_RELOCATABLE, "__builtin_is_nothrow_relocatable", 1)
DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
+DEFTRAIT_EXPR (IS_REPLACEABLE, "__builtin_is_replaceable", 1)
DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
@@ -101,6 +103,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
DEFTRAIT_EXPR (IS_TRIVIALLY_DESTRUCTIBLE, "__is_trivially_destructible", 1)
+DEFTRAIT_EXPR (IS_TRIVIALLY_RELOCATABLE, "__builtin_is_trivially_relocatable", 1)
DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
DEFTRAIT_EXPR (IS_VIRTUAL_BASE_OF, "__builtin_is_virtual_base_of", 2)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3b92d9a..fb8e0d8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -452,6 +452,9 @@ 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)
+ CONSTEVAL_BLOCK_P (in STATIC_ASSERT)
+ LAMBDA_EXPR_CONSTEVAL_BLOCK_P (in LAMBDA_EXPR)
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -472,6 +475,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 +497,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)
@@ -1430,6 +1435,10 @@ struct GTY (()) tree_deferred_noexcept {
#define STATIC_ASSERT_SOURCE_LOCATION(NODE) \
(((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location)
+/* True if this static assert represents a C++26 consteval block. */
+#define CONSTEVAL_BLOCK_P(NODE) \
+ TREE_LANG_FLAG_0 (STATIC_ASSERT_CHECK (NODE))
+
struct GTY (()) tree_static_assert {
struct tree_base base;
tree condition;
@@ -1544,6 +1553,10 @@ enum cp_lambda_default_capture_mode_type {
#define LAMBDA_EXPR_THIS_CAPTURE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture)
+/* True iff this lambda was created for a consteval block. */
+#define LAMBDA_EXPR_CONSTEVAL_BLOCK_P(NODE) \
+ TREE_LANG_FLAG_0 (LAMBDA_EXPR_CHECK (NODE))
+
/* True iff uses of a const variable capture were optimized away. */
#define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
@@ -2497,15 +2510,22 @@ struct GTY(()) lang_type {
bool erroneous : 1;
bool non_pod_aggregate : 1;
bool non_aggregate_pod : 1;
+ bool trivially_relocatable : 1;
+ bool trivially_relocatable_computed : 1;
+
+ bool replaceable : 1;
+ bool replaceable_computed : 1;
/* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If
- so, make sure to copy it in instantiate_class_template! */
+ so, make sure to copy it in instantiate_class_template!
+
+ Also make sure new flags here are streamed in module.cc. */
/* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or
remove a flag. */
- unsigned dummy : 2;
+ unsigned dummy : 30;
tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2516,11 +2536,11 @@ struct GTY(()) lang_type {
vec<tree, va_gc> *pure_virtuals;
tree friend_classes;
vec<tree, va_gc> * GTY((reorder ("resort_type_member_vec"))) members;
+ /* CLASSTYPE_KEY_METHOD for TYPE_POLYMORPHIC_P types, CLASSTYPE_LAMBDA_EXPR
+ otherwise. */
tree key_method;
tree decl_list;
tree befriending_classes;
- /* FIXME reuse another field? */
- tree lambda_expr;
union maybe_objc_info {
/* If not c_dialect_objc, this part is not even allocated. */
char GTY((tag ("0"))) non_objc;
@@ -2643,7 +2663,13 @@ struct GTY(()) lang_type {
/* The member function with which the vtable will be emitted:
the first noninline non-pure-virtual member function. NULL_TREE
if there is no key function or if this is a class template */
-#define CLASSTYPE_KEY_METHOD(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->key_method)
+#define CLASSTYPE_KEY_METHOD(NODE) \
+ (TYPE_POLYMORPHIC_P (NODE) \
+ ? LANG_TYPE_CLASS_CHECK (NODE)->key_method \
+ : NULL_TREE)
+#define SET_CLASSTYPE_KEY_METHOD(NODE, VALUE) \
+ (gcc_checking_assert (TYPE_POLYMORPHIC_P (NODE)), \
+ LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE))
/* Vector of members. During definition, it is unordered and only
member functions are present. After completion it is sorted and
@@ -2775,7 +2801,12 @@ struct GTY(()) lang_type {
/* The associated LAMBDA_EXPR that made this class. */
#define CLASSTYPE_LAMBDA_EXPR(NODE) \
- (LANG_TYPE_CLASS_CHECK (NODE)->lambda_expr)
+ (TYPE_POLYMORPHIC_P (NODE) \
+ ? NULL_TREE \
+ : LANG_TYPE_CLASS_CHECK (NODE)->key_method)
+#define SET_CLASSTYPE_LAMBDA_EXPR(NODE, VALUE) \
+ (gcc_checking_assert (!TYPE_POLYMORPHIC_P (NODE)), \
+ LANG_TYPE_CLASS_CHECK (NODE)->key_method = (VALUE))
/* The extra mangling scope for this closure type. */
#define LAMBDA_TYPE_EXTRA_SCOPE(NODE) \
(LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR (NODE)))
@@ -2841,6 +2872,29 @@ struct GTY(()) lang_type {
above (c++/120012). This could also be a hash_set. */
#define CLASSTYPE_NON_AGGREGATE_POD(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->non_aggregate_pod)
+
+/* If CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, true if this class is
+ trivially relocatable.
+ If !CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED, true if this class
+ is marked with trivially_relocatable_if_eligible conditional keyword. */
+#define CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable)
+
+/* True if whether this class is trivially relocatable or not
+ has been computed already. */
+#define CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->trivially_relocatable_computed)
+
+/* If CLASSTYPE_REPLACEABLE_COMPUTED, true if this class is replaceable.
+ If !CLASSTYPE_REPLACEABLE_COMPUTED, true if this class is marked with
+ replaceable_if_eligible conditional keyword. */
+#define CLASSTYPE_REPLACEABLE_BIT(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->replaceable)
+
+/* True if whether this class is replaceable or not has been computed
+ already. */
+#define CLASSTYPE_REPLACEABLE_COMPUTED(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->replaceable_computed)
/* Additional macros for inheritance information. */
@@ -3016,6 +3070,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 +4526,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 +4585,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 +5226,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)
@@ -6471,7 +6548,9 @@ enum virt_specifier
{
VIRT_SPEC_UNSPECIFIED = 0x0,
VIRT_SPEC_FINAL = 0x1,
- VIRT_SPEC_OVERRIDE = 0x2
+ VIRT_SPEC_OVERRIDE = 0x2,
+ VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE = 0x4,
+ VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE = 0x8
};
/* A type-qualifier, or bitmask therefore, using the VIRT_SPEC
@@ -6813,6 +6892,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 +7073,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);
@@ -7163,7 +7244,7 @@ extern void determine_local_discriminator (tree, tree = NULL_TREE);
extern bool member_like_constrained_friend_p (tree);
extern bool fns_correspond (tree, tree);
extern int decls_match (tree, tree, bool = true);
-extern bool maybe_version_functions (tree, tree, bool);
+extern bool maybe_version_functions (tree, tree);
extern bool validate_constexpr_redeclaration (tree, tree);
extern bool merge_default_template_args (tree, tree, bool);
extern tree duplicate_decls (tree, tree,
@@ -7386,7 +7467,7 @@ extern void maybe_warn_variadic_templates (void);
extern void maybe_warn_cpp0x (cpp0x_warn_str str,
location_t = input_location);
extern bool pedwarn_cxx98 (location_t,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
extern location_t location_of (tree);
extern void qualified_name_lookup_error (tree, tree, tree,
@@ -7412,6 +7493,7 @@ extern int nothrow_libfn_p (const_tree);
extern void check_handlers (tree);
extern tree finish_noexcept_expr (tree, tsubst_flags_t);
extern bool expr_noexcept_p (tree, tsubst_flags_t);
+extern void explain_not_noexcept (tree);
extern void perform_deferred_noexcept_checks (void);
extern bool nothrow_spec_p (const_tree);
extern bool type_noexcept_p (const_tree);
@@ -7533,11 +7615,14 @@ extern void finish_thunk (tree);
extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree);
extern tree forward_parm (tree);
-extern bool is_trivially_xible (enum tree_code, tree, tree);
-extern bool is_nothrow_xible (enum tree_code, tree, tree);
-extern bool is_xible (enum tree_code, tree, tree);
-extern bool is_convertible (tree, tree);
-extern bool is_nothrow_convertible (tree, tree);
+extern bool is_trivially_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_nothrow_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_convertible (tree, tree, bool = false);
+extern bool is_nothrow_convertible (tree, tree, bool = false);
extern bool ref_xes_from_temporary (tree, tree, bool);
extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error);
extern bool maybe_explain_implicit_delete (tree);
@@ -8168,7 +8253,7 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool,
bool, bool);
extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
- bool, bool);
+ bool, bool, bool = false);
extern tree finish_decltype_type (tree, bool, tsubst_flags_t);
extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
@@ -8193,7 +8278,7 @@ extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree, int);
extern void maybe_generic_this_capture (tree, tree);
extern tree maybe_resolve_dummy (tree, bool);
-extern tree current_nonlambda_function (void);
+extern tree current_nonlambda_function (bool = false);
extern tree nonlambda_method_basetype (void);
extern tree current_nonlambda_scope (bool = false);
extern tree current_lambda_expr (void);
@@ -8243,6 +8328,8 @@ extern bool pod_type_p (const_tree);
extern bool layout_pod_type_p (const_tree);
extern bool std_layout_type_p (const_tree);
extern bool trivial_type_p (const_tree);
+extern bool trivially_relocatable_type_p (tree);
+extern bool replaceable_type_p (tree);
extern bool trivially_copyable_p (const_tree);
extern bool type_has_unique_obj_representations (const_tree);
extern bool scalarish_type_p (const_tree);
@@ -8388,9 +8475,9 @@ extern void cxx_print_xnode (FILE *, tree, int);
extern void cxx_print_decl (FILE *, tree, int);
extern void cxx_print_type (FILE *, tree, int);
extern void cxx_print_identifier (FILE *, tree, int);
-extern void cxx_print_error_function (diagnostic_text_output_format &,
+extern void cxx_print_error_function (diagnostics::text_sink &,
const char *,
- const diagnostic_info *);
+ const diagnostics::diagnostic_info *);
/* in typeck.cc */
/* Says how we should behave when comparing two arrays one of which
@@ -8577,7 +8664,7 @@ extern void maybe_warn_pessimizing_move (tree, tree, bool);
/* in typeck2.cc */
extern void require_complete_eh_spec_types (tree, tree);
extern bool cxx_incomplete_type_diagnostic (location_t, const_tree,
- const_tree, diagnostic_t);
+ const_tree, enum diagnostics::kind);
inline location_t
loc_or_input_loc (location_t loc)
{
@@ -8625,7 +8712,7 @@ cp_expr_loc_or_input_loc (const_tree t)
inline bool
cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
- diagnostic_t diag_kind)
+ enum diagnostics::kind diag_kind)
{
return cxx_incomplete_type_diagnostic (cp_expr_loc_or_input_loc (value),
value, type, diag_kind);
@@ -8636,7 +8723,7 @@ extern void cxx_incomplete_type_error (location_t, const_tree,
inline void
cxx_incomplete_type_error (const_tree value, const_tree type)
{
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
}
extern void cxx_incomplete_type_inform (const_tree);
@@ -8707,7 +8794,7 @@ extern alias_set_type cxx_get_alias_set (tree);
extern bool cxx_warn_unused_global_decl (const_tree);
extern size_t cp_tree_size (enum tree_code);
extern bool cp_var_mod_type_p (tree, tree);
-extern void cxx_initialize_diagnostics (diagnostic_context *);
+extern void cxx_initialize_diagnostics (diagnostics::context *);
extern int cxx_types_compatible_p (tree, tree);
extern bool cxx_block_may_fallthru (const_tree);
@@ -8852,6 +8939,8 @@ extern bool constraints_equivalent_p (tree, tree);
extern bool atomic_constraints_identical_p (tree, tree);
extern hashval_t iterative_hash_constraint (tree, hashval_t);
extern hashval_t hash_atomic_constraint (tree);
+extern void diagnose_trait_expr (location_t, tree, tree);
+extern bool maybe_diagnose_standard_trait (location_t, tree);
extern void diagnose_constraints (location_t, tree, tree);
extern void note_failed_type_completion (tree, tsubst_flags_t);
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index f663a6d..55be12d 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1186,13 +1186,6 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
expr = maybe_undo_parenthesized_ref (expr);
- expr = mark_discarded_use (expr);
- if (implicit == ICV_CAST)
- /* An explicit cast to void avoids all -Wunused-but-set* warnings. */
- mark_exp_read (expr);
-
- if (!TREE_TYPE (expr))
- return expr;
if (invalid_nonstatic_memfn_p (loc, expr, complain))
return error_mark_node;
if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
@@ -1209,6 +1202,12 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
if (VOID_TYPE_P (TREE_TYPE (expr)))
return expr;
+
+ expr = mark_discarded_use (expr);
+ if (implicit == ICV_CAST)
+ /* An explicit cast to void avoids all -Wunused-but-set* warnings. */
+ mark_exp_read (expr);
+
switch (TREE_CODE (expr))
{
case COND_EXPR:
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 0e6afbe..cb3ebff 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -110,7 +110,7 @@ static void initialize_local_var (tree, tree, bool);
static void expand_static_init (tree, tree);
static location_t smallest_type_location (const cp_decl_specifier_seq*);
static bool identify_goto (tree, location_t, const location_t *,
- diagnostic_t, bool);
+ enum diagnostics::kind, bool);
/* The following symbols are subsumed in the cp_global_trees array, and
listed here individually for documentation purposes.
@@ -747,11 +747,11 @@ poplevel (int keep, int reverse, int functionbody)
{
if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl))
warning_at (DECL_SOURCE_LOCATION (decl),
- OPT_Wunused_but_set_variable, "structured "
+ OPT_Wunused_but_set_variable_, "structured "
"binding declaration set but not used");
else
warning_at (DECL_SOURCE_LOCATION (decl),
- OPT_Wunused_but_set_variable,
+ OPT_Wunused_but_set_variable_,
"variable %qD set but not used", decl);
unused_but_set_errorcount = errorcount;
}
@@ -1214,9 +1214,7 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
&& targetm.target_option.function_versions (newdecl, olddecl))
{
if (record_versions)
- maybe_version_functions (newdecl, olddecl,
- (!DECL_FUNCTION_VERSIONED (newdecl)
- || !DECL_FUNCTION_VERSIONED (olddecl)));
+ maybe_version_functions (newdecl, olddecl);
return 0;
}
}
@@ -1283,11 +1281,11 @@ maybe_mark_function_versioned (tree decl)
}
/* NEWDECL and OLDDECL have identical signatures. If they are
- different versions adjust them and return true.
- If RECORD is set to true, record function versions. */
+ different versions adjust them, record function versions, and return
+ true. */
bool
-maybe_version_functions (tree newdecl, tree olddecl, bool record)
+maybe_version_functions (tree newdecl, tree olddecl)
{
if (!targetm.target_option.function_versions (newdecl, olddecl))
return false;
@@ -1310,16 +1308,13 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record)
maybe_mark_function_versioned (newdecl);
}
- if (record)
- {
- /* Add the new version to the function version structure. */
- cgraph_node *fn_node = cgraph_node::get_create (olddecl);
- cgraph_function_version_info *fn_v = fn_node->function_version ();
- if (!fn_v)
- fn_v = fn_node->insert_new_function_version ();
+ /* Add the new version to the function version structure. */
+ cgraph_node *fn_node = cgraph_node::get_create (olddecl);
+ cgraph_function_version_info *fn_v = fn_node->function_version ();
+ if (!fn_v)
+ fn_v = fn_node->insert_new_function_version ();
- cgraph_node::add_function_version (fn_v, newdecl);
- }
+ cgraph_node::add_function_version (fn_v, newdecl);
return true;
}
@@ -3742,10 +3737,10 @@ decl_jump_unsafe (tree decl)
static bool
identify_goto (tree decl, location_t loc, const location_t *locus,
- diagnostic_t diag_kind, bool computed)
+ enum diagnostics::kind diag_kind, bool computed)
{
if (computed)
- diag_kind = DK_WARNING;
+ diag_kind = diagnostics::kind::warning;
bool complained
= emit_diagnostic (diag_kind, loc, 0,
decl ? G_("jump to label %qD")
@@ -3781,7 +3776,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (exited_omp)
{
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
if (complained)
inform (input_location, " exits OpenMP structured block");
@@ -3803,7 +3799,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (!identified)
{
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
}
@@ -3871,7 +3868,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (inf)
{
if (identified < 2)
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
if (complained)
@@ -3882,7 +3880,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (!vec_safe_is_empty (computed))
{
if (!identified)
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
if (complained)
@@ -3954,14 +3953,14 @@ check_goto_1 (named_label_entry *ent, bool computed)
|| ent->in_omp_scope || ent->in_stmt_expr
|| !vec_safe_is_empty (ent->bad_decls))
{
- diagnostic_t diag_kind = DK_PERMERROR;
+ enum diagnostics::kind diag_kind = diagnostics::kind::permerror;
if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if
|| ent->in_consteval_if || ent->in_transaction_scope
|| ent->in_omp_scope || ent->in_stmt_expr)
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
&input_location, diag_kind, computed);
- identified = 1 + (diag_kind == DK_ERROR);
+ identified = 1 + (diag_kind == diagnostics::kind::error);
}
FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
@@ -3974,7 +3973,9 @@ check_goto_1 (named_label_entry *ent, bool computed)
if (identified == 1)
{
complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location,
+ diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -4018,7 +4019,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained = identify_goto (decl,
DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR,
+ &input_location,
+ diagnostics::kind::error,
computed);
identified = 2;
}
@@ -4042,7 +4044,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained
= identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location, diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -4058,7 +4061,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained
= identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location, diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -5082,6 +5086,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. */
@@ -11268,12 +11284,12 @@ grokfndecl (tree ctype,
t && t != void_list_node; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t))
{
- diagnostic_t diag_kind = DK_PERMERROR;
+ enum diagnostics::kind diag_kind = diagnostics::kind::permerror;
/* For templates, mark the default argument as erroneous and give a
hard error. */
if (processing_template_decl)
{
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
TREE_PURPOSE (t) = error_mark_node;
}
if (!has_errored)
@@ -11281,7 +11297,7 @@ grokfndecl (tree ctype,
has_errored = true;
emit_diagnostic (diag_kind,
DECL_SOURCE_LOCATION (decl),
- /*diagnostic_option_id=*/0,
+ /*diagnostics::option_id=*/0,
"friend declaration of %qD specifies default "
"arguments and isn%'t a definition", decl);
}
@@ -17277,7 +17293,7 @@ xref_tag (enum tag_types tag_code, tree name,
if (IDENTIFIER_LAMBDA_P (name))
/* Mark it as a lambda type right now. Our caller will
correct the value. */
- CLASSTYPE_LAMBDA_EXPR (t) = error_mark_node;
+ SET_CLASSTYPE_LAMBDA_EXPR (t, error_mark_node);
t = pushtag (name, t, how);
}
else
@@ -17390,7 +17406,8 @@ xref_basetypes (tree ref, tree base_list)
compatibility. */
if (processing_template_decl
&& CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype))
- cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN);
+ cxx_incomplete_type_diagnostic (NULL_TREE, basetype,
+ diagnostics::kind::pedwarn);
if (!dependent_type_p (basetype)
&& !complete_type_or_else (basetype, NULL))
/* An incomplete type. Remove it from the list. */
@@ -19484,14 +19501,14 @@ finish_function (bool inline_p)
&& !DECL_READ_P (decl)
&& DECL_NAME (decl)
&& !DECL_ARTIFICIAL (decl)
- && !warning_suppressed_p (decl,OPT_Wunused_but_set_parameter)
+ && !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter_)
&& !DECL_IN_SYSTEM_HEADER (decl)
&& TREE_TYPE (decl) != error_mark_node
&& !TYPE_REF_P (TREE_TYPE (decl))
&& (!CLASS_TYPE_P (TREE_TYPE (decl))
|| !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
warning_at (DECL_SOURCE_LOCATION (decl),
- OPT_Wunused_but_set_parameter,
+ OPT_Wunused_but_set_parameter_,
"parameter %qD set but not used", decl);
unused_but_set_errorcount = errorcount;
}
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index eb2ff33..c427163 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "cp-tree.h"
#include "stringpool.h"
#include "tree-diagnostic.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
#include "langhooks-def.h"
#include "intl.h"
#include "cxx-pretty-print.h"
@@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "cp-name-hint.h"
#include "attribs.h"
#include "pretty-print-format-impl.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
#define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
@@ -96,17 +96,17 @@ static void dump_scope (cxx_pretty_printer *, tree, int);
static void dump_template_parms (cxx_pretty_printer *, tree, int, int);
static int get_non_default_template_args_count (tree, int);
static const char *function_category (tree);
-static void maybe_print_constexpr_context (diagnostic_text_output_format &);
-static void maybe_print_instantiation_context (diagnostic_text_output_format &);
-static void print_instantiation_full_context (diagnostic_text_output_format &);
-static void print_instantiation_partial_context (diagnostic_text_output_format &,
+static void maybe_print_constexpr_context (diagnostics::text_sink &);
+static void maybe_print_instantiation_context (diagnostics::text_sink &);
+static void print_instantiation_full_context (diagnostics::text_sink &);
+static void print_instantiation_partial_context (diagnostics::text_sink &,
struct tinst_level *,
location_t);
-static void maybe_print_constraint_context (diagnostic_text_output_format &);
-static void cp_diagnostic_text_starter (diagnostic_text_output_format &,
- const diagnostic_info *);
-static void cp_print_error_function (diagnostic_text_output_format &,
- const diagnostic_info *);
+static void maybe_print_constraint_context (diagnostics::text_sink &);
+static void cp_diagnostic_text_starter (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *);
+static void cp_print_error_function (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *);
static bool cp_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, pp_token_list &);
@@ -242,7 +242,7 @@ get_current_template ()
erroneous_templates_t *erroneous_templates;
-/* Callback function diagnostic_context::m_adjust_diagnostic_info.
+/* Callback function diagnostics::context::m_adjust_diagnostic_info.
Errors issued when parsing a template are automatically treated like
permerrors associated with the -Wtemplate-body flag and can be
@@ -250,16 +250,16 @@ erroneous_templates_t *erroneous_templates;
issue an error if we later need to instantiate the template. */
static void
-cp_adjust_diagnostic_info (diagnostic_context *context,
- diagnostic_info *diagnostic)
+cp_adjust_diagnostic_info (diagnostics::context *context,
+ diagnostics::diagnostic_info *diagnostic)
{
- if (diagnostic->kind == DK_ERROR)
+ if (diagnostic->m_kind == diagnostics::kind::error)
if (tree tmpl = get_current_template ())
{
- diagnostic->option_id = OPT_Wtemplate_body;
+ diagnostic->m_option_id = OPT_Wtemplate_body;
if (context->m_permissive)
- diagnostic->kind = DK_WARNING;
+ diagnostic->m_kind = diagnostics::kind::warning;
bool existed;
location_t &error_loc
@@ -269,7 +269,7 @@ cp_adjust_diagnostic_info (diagnostic_context *context,
/* Remember that this template had a parse-time error so
that we'll ensure a hard error has been issued upon
its instantiation. */
- error_loc = diagnostic->richloc->get_loc ();
+ error_loc = diagnostic->m_richloc->get_loc ();
}
}
@@ -298,14 +298,14 @@ cp_seen_error ()
capacities. */
void
-cxx_initialize_diagnostics (diagnostic_context *context)
+cxx_initialize_diagnostics (diagnostics::context *context)
{
cxx_pretty_printer *pp = new cxx_pretty_printer ();
pp->set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ());
context->set_pretty_printer (std::unique_ptr<pretty_printer> (pp));
c_common_diagnostics_set_defaults (context);
- diagnostic_text_starter (context) = cp_diagnostic_text_starter;
+ diagnostics::text_starter (context) = cp_diagnostic_text_starter;
/* diagnostic_finalizer is already c_diagnostic_text_finalizer. */
context->set_format_decoder (cp_printer);
context->set_adjust_diagnostic_info_callback (cp_adjust_diagnostic_info);
@@ -704,6 +704,20 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
}
break;
+ case TREE_VEC:
+ {
+ /* A list of types used for a trait. */
+ bool need_comma = false;
+ for (tree arg : tree_vec_range (t))
+ {
+ if (need_comma)
+ pp_separate_with_comma (pp);
+ dump_type (pp, arg, flags);
+ need_comma = true;
+ }
+ }
+ break;
+
case TREE_LIST:
/* A list of function parms. */
dump_parameters (pp, t, flags);
@@ -3747,9 +3761,9 @@ eh_spec_to_string (tree p, int /*v*/)
/* Langhook for print_error_function. */
void
-cxx_print_error_function (diagnostic_text_output_format &text_output,
+cxx_print_error_function (diagnostics::text_sink &text_output,
const char *file,
- const diagnostic_info *diagnostic)
+ const diagnostics::diagnostic_info *diagnostic)
{
char *prefix;
if (file)
@@ -3763,8 +3777,8 @@ cxx_print_error_function (diagnostic_text_output_format &text_output,
}
static void
-cp_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+cp_diagnostic_text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
pp_set_prefix (text_output.get_printer (),
text_output.build_indent_prefix (true));
@@ -3780,8 +3794,8 @@ cp_diagnostic_text_starter (diagnostic_text_output_format &text_output,
/* Print current function onto BUFFER, in the process of reporting
a diagnostic message. Called from cp_diagnostic_starter. */
static void
-cp_print_error_function (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+cp_print_error_function (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
/* If we are in an instantiation context, current_function_decl is likely
to be wrong, so just rely on print_instantiation_full_context. */
@@ -3790,7 +3804,7 @@ cp_print_error_function (diagnostic_text_output_format &text_output,
/* The above is true for constraint satisfaction also. */
if (current_failed_constraint)
return;
- diagnostic_context *const context = &text_output.get_context ();
+ diagnostics::context *const context = &text_output.get_context ();
if (diagnostic_last_function_changed (context, diagnostic))
{
pretty_printer *const pp = text_output.get_printer ();
@@ -3928,7 +3942,7 @@ function_category (tree fn)
/* Report the full context of a current template instantiation,
onto BUFFER. */
static void
-print_instantiation_full_context (diagnostic_text_output_format &text_output)
+print_instantiation_full_context (diagnostics::text_sink &text_output)
{
struct tinst_level *p = current_instantiation ();
location_t location = input_location;
@@ -3956,7 +3970,7 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output)
}
static void
-print_location (diagnostic_text_output_format &text_output,
+print_location (diagnostics::text_sink &text_output,
location_t loc)
{
expanded_location xloc = expand_location (loc);
@@ -3970,7 +3984,7 @@ print_location (diagnostic_text_output_format &text_output,
}
/* A RAII class for use when emitting a line of contextual information
- via pp_verbatim to a diagnostic_text_output_format to add before/after
+ via pp_verbatim to a diagnostics::text_sink to add before/after
behaviors to the pp_verbatim calls.
If the text output has show_nesting_p (), then the ctor prints
@@ -3985,7 +3999,7 @@ print_location (diagnostic_text_output_format &text_output,
class auto_context_line
{
public:
- auto_context_line (diagnostic_text_output_format &text_output,
+ auto_context_line (diagnostics::text_sink &text_output,
location_t loc,
bool show_locus = false)
: m_text_output (text_output),
@@ -4016,7 +4030,7 @@ public:
diagnostic_show_locus (&m_text_output.get_context (),
m_text_output.get_source_printing_options (),
&rich_loc,
- DK_NOTE, pp);
+ diagnostics::kind::note, pp);
pp_set_prefix (pp, saved_prefix);
}
}
@@ -4028,12 +4042,12 @@ public:
diagnostic_show_locus (&m_text_output.get_context (),
m_text_output.get_source_printing_options (),
&rich_loc,
- DK_NOTE, pp);
+ diagnostics::kind::note, pp);
pp_set_prefix (pp, saved_prefix);
}
}
private:
- diagnostic_text_output_format &m_text_output;
+ diagnostics::text_sink &m_text_output;
location_t m_loc;
bool m_show_locus;
};
@@ -4042,7 +4056,7 @@ private:
prints a single line of instantiation context. */
static void
-print_instantiation_partial_context_line (diagnostic_text_output_format &text_output,
+print_instantiation_partial_context_line (diagnostics::text_sink &text_output,
struct tinst_level *t,
location_t loc, bool recursive_p)
{
@@ -4080,7 +4094,7 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou
/* Same as print_instantiation_full_context but less verbose. */
static void
-print_instantiation_partial_context (diagnostic_text_output_format &text_output,
+print_instantiation_partial_context (diagnostics::text_sink &text_output,
struct tinst_level *t0, location_t loc)
{
struct tinst_level *t;
@@ -4151,7 +4165,7 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output,
/* Called from cp_thing to print the template context for an error. */
static void
-maybe_print_instantiation_context (diagnostic_text_output_format &text_output)
+maybe_print_instantiation_context (diagnostics::text_sink &text_output)
{
if (!problematic_instantiation_changed () || current_instantiation () == 0)
return;
@@ -4163,7 +4177,7 @@ maybe_print_instantiation_context (diagnostic_text_output_format &text_output)
/* Report what constexpr call(s) we're trying to expand, if any. */
void
-maybe_print_constexpr_context (diagnostic_text_output_format &text_output)
+maybe_print_constexpr_context (diagnostics::text_sink &text_output)
{
vec<tree> call_stack = cx_error_context ();
unsigned ix;
@@ -4183,7 +4197,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output)
static void
-print_constrained_decl_info (diagnostic_text_output_format &text_output,
+print_constrained_decl_info (diagnostics::text_sink &text_output,
tree decl)
{
auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl));
@@ -4192,7 +4206,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output,
}
static void
-print_concept_check_info (diagnostic_text_output_format &text_output,
+print_concept_check_info (diagnostics::text_sink &text_output,
tree expr, tree map, tree args)
{
gcc_assert (concept_check_p (expr));
@@ -4217,7 +4231,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output,
context, if any. */
static tree
-print_constraint_context_head (diagnostic_text_output_format &text_output,
+print_constraint_context_head (diagnostics::text_sink &text_output,
tree cxt, tree args)
{
tree src = TREE_VALUE (cxt);
@@ -4241,7 +4255,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output,
}
static void
-print_requires_expression_info (diagnostic_text_output_format &text_output,
+print_requires_expression_info (diagnostics::text_sink &text_output,
tree constr, tree args)
{
@@ -4271,7 +4285,7 @@ print_requires_expression_info (diagnostic_text_output_format &text_output,
}
void
-maybe_print_single_constraint_context (diagnostic_text_output_format &text_output,
+maybe_print_single_constraint_context (diagnostics::text_sink &text_output,
tree failed)
{
if (!failed)
@@ -4302,7 +4316,7 @@ maybe_print_single_constraint_context (diagnostic_text_output_format &text_outpu
}
void
-maybe_print_constraint_context (diagnostic_text_output_format &text_output)
+maybe_print_constraint_context (diagnostics::text_sink &text_output)
{
if (!current_failed_constraint)
return;
@@ -4915,18 +4929,20 @@ maybe_warn_variadic_templates (void)
C++0x. */
bool
pedwarn_cxx98 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (line_table, location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
- (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = option_id;
+ (cxx_dialect == cxx98
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning));
+ diagnostic.m_option_id = option_id;
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
return ret;
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index a9d8e2f..204769f 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -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;
@@ -1202,6 +1218,20 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain)
return true;
}
+/* If EXPR is not noexcept, explain why. */
+
+void
+explain_not_noexcept (tree expr)
+{
+ tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
+ if (!fn)
+ /* The call was noexcept, nothing to do. */;
+ else if (DECL_P (fn))
+ inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn);
+ else
+ inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn));
+}
+
/* Return true iff SPEC is throw() or noexcept(true). */
bool
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index 2157cfb..32dc3ee 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -102,6 +102,9 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
if (reject_builtin && reject_gcc_builtin (expr, loc))
return error_mark_node;
+ if (TREE_TYPE (expr) && VOID_TYPE_P (TREE_TYPE (expr)))
+ read_p = false;
+
if (read_p)
mark_exp_read (expr);
@@ -211,7 +214,7 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
}
return expr;
}
- gcc_fallthrough();
+ gcc_fallthrough ();
CASE_CONVERT:
recurse_op[0] = true;
break;
@@ -352,6 +355,9 @@ mark_exp_read (tree exp)
if (exp == NULL)
return;
+ if (TREE_TYPE (exp) && VOID_TYPE_P (TREE_TYPE (exp)))
+ return;
+
switch (TREE_CODE (exp))
{
case VAR_DECL:
@@ -361,16 +367,20 @@ mark_exp_read (tree exp)
case PARM_DECL:
DECL_READ_P (exp) = 1;
break;
+ CASE_CONVERT:
case ARRAY_REF:
case COMPONENT_REF:
case MODIFY_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
- CASE_CONVERT:
case ADDR_EXPR:
case INDIRECT_REF:
case FLOAT_EXPR:
case VIEW_CONVERT_EXPR:
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
mark_exp_read (TREE_OPERAND (exp, 0));
break;
case COMPOUND_EXPR:
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 0a389fb..09fb4f3 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4181,7 +4181,8 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type,
"possible problem detected in invocation of "
"operator %<delete []%>"))
{
- cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
+ cxx_incomplete_type_diagnostic (base, type,
+ diagnostics::kind::warning);
inform (loc, "neither the destructor nor the "
"class-specific operator %<delete []%> will be called, "
"even if they are declared when the class is defined");
@@ -5286,7 +5287,8 @@ build_delete (location_t loc, tree otype, tree addr,
"possible problem detected in invocation of "
"%<operator delete%>"))
{
- cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+ cxx_incomplete_type_diagnostic (addr, type,
+ diagnostics::kind::warning);
inform (loc,
"neither the destructor nor the class-specific "
"%<operator delete%> will be called, even if "
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 182cffa..c798967 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -150,7 +150,7 @@ begin_lambda_type (tree lambda)
/* Cross-reference the expression and the type. */
LAMBDA_EXPR_CLOSURE (lambda) = type;
- CLASSTYPE_LAMBDA_EXPR (type) = lambda;
+ SET_CLASSTYPE_LAMBDA_EXPR (type, lambda);
/* In C++17, assume the closure is literal; we'll clear the flag later if
necessary. */
@@ -1038,13 +1038,19 @@ maybe_generic_this_capture (tree object, tree fns)
}
}
-/* Returns the innermost non-lambda function. */
+/* Returns the innermost non-lambda function. If ONLY_SKIP_CONSTEVAL_BLOCK_P,
+ we only skip lambda functions that represent consteval blocks. */
tree
-current_nonlambda_function (void)
+current_nonlambda_function (bool only_skip_consteval_block_p/*=false*/)
{
tree fn = current_function_decl;
- while (fn && LAMBDA_FUNCTION_P (fn))
+ tree lam;
+ while (fn && LAMBDA_FUNCTION_P (fn)
+ && (!only_skip_consteval_block_p
+ /* Only keep going if FN represents a consteval block. */
+ || ((lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fn)))
+ && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))))
fn = decl_function_context (fn);
return fn;
}
@@ -1143,7 +1149,9 @@ maybe_add_lambda_conv_op (tree type)
tree lam = CLASSTYPE_LAMBDA_EXPR (type);
if (LAMBDA_EXPR_CAPTURE_LIST (lam) != NULL_TREE
- || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE)
+ || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE
+ /* CWG2561 ...and no explicit object parameter. */
+ || DECL_XOBJ_MEMBER_FUNCTION_P (callop))
return;
if (processing_template_decl)
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index a4089c5..397e496 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1187,15 +1187,15 @@ early_check_defaulted_comparison (tree fn)
if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR)
&& !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node))
{
- diagnostic_t kind = DK_UNSPECIFIED;
+ enum diagnostics::kind kind = diagnostics::kind::unspecified;
int opt = 0;
if (is_auto (TREE_TYPE (fn)))
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
else
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
emit_diagnostic (kind, loc, opt,
"defaulted %qD must return %<bool%>", fn);
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
ok = false;
}
@@ -1928,8 +1928,8 @@ is_stub_object (tree expr)
/* Build a std::declval<TYPE>() expression and return it. */
-tree
-build_trait_object (tree type)
+static tree
+build_trait_object (tree type, tsubst_flags_t complain)
{
/* TYPE can't be a function with cv-/ref-qualifiers: std::declval is
defined as
@@ -1942,13 +1942,18 @@ build_trait_object (tree type)
if (FUNC_OR_METHOD_TYPE_P (type)
&& (type_memfn_quals (type) != TYPE_UNQUALIFIED
|| type_memfn_rqual (type) != REF_QUAL_NONE))
- return error_mark_node;
+ {
+ if (complain & tf_error)
+ error ("object cannot have qualified function type %qT", type);
+ return error_mark_node;
+ }
return build_stub_object (type);
}
/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...). If the
- given is not invocable, returns error_mark_node. */
+ given is not invocable, returns error_mark_node, unless COMPLAIN includes
+ tf_error. */
tree
build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
@@ -2036,22 +2041,26 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
const_tree name = DECL_NAME (datum_decl);
if (name && (id_equal (name, "reference_wrapper")))
{
- /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>,
+ /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>,
i.e., decltype(datum.get()). */
datum_type =
TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0);
+ datum_type = cp_build_reference_type (datum_type, false);
datum_is_refwrap = true;
}
}
}
- tree datum_expr = build_trait_object (datum_type);
+ tree datum_expr = build_trait_object (datum_type, complain);
if (!ptrmem_is_same_or_base_of_datum && !datum_is_refwrap)
/* 1.3 & 1.6: Try to dereference datum_expr. */
datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr,
RO_UNARY_STAR, NULL_TREE, complain);
- tree fn_expr = build_trait_object (fn_type);
+ if (error_operand_p (datum_expr))
+ return error_mark_node;
+
+ tree fn_expr = build_trait_object (fn_type, complain);
ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain);
if (error_operand_p (ptrmem_expr))
@@ -2068,7 +2077,9 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
{
tree arg_type = TREE_VEC_ELT (arg_types, i);
- tree arg = build_trait_object (arg_type);
+ tree arg = build_trait_object (arg_type, complain);
+ if (error_operand_p (arg))
+ return error_mark_node;
vec_safe_push (args, arg);
}
@@ -2077,8 +2088,8 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
invoke_expr = build_offset_ref_call_from_tree (ptrmem_expr, &args,
complain);
else /* 1.7. */
- invoke_expr = finish_call_expr (build_trait_object (fn_type), &args, false,
- false, complain);
+ invoke_expr = finish_call_expr (build_trait_object (fn_type, complain),
+ &args, false, false, complain);
return invoke_expr;
}
@@ -2227,12 +2238,20 @@ check_nontriv (tree *tp, int *, void *)
/* Return declval<T>() = declval<U>() treated as an unevaluated operand. */
static tree
-assignable_expr (tree to, tree from)
+assignable_expr (tree to, tree from, bool explain)
{
cp_unevaluated cp_uneval_guard;
- to = build_trait_object (to);
- from = build_trait_object (from);
- tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
+ to = build_trait_object (to, complain);
+ if (to == error_mark_node)
+ return error_mark_node;
+
+ from = build_trait_object (from, complain);
+ if (from == error_mark_node)
+ return error_mark_node;
+
+ tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, complain);
return r;
}
@@ -2244,10 +2263,11 @@ assignable_expr (tree to, tree from)
Return something equivalent in well-formedness and triviality. */
static tree
-constructible_expr (tree to, tree from)
+constructible_expr (tree to, tree from, bool explain)
{
tree expr;
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
@@ -2259,14 +2279,14 @@ constructible_expr (tree to, tree from)
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
if (len == 0)
- expr = build_value_init (ctype, tf_none);
+ expr = build_value_init (ctype, complain);
else
{
vec_alloc (args, len);
for (tree arg : tree_vec_range (from))
args->quick_push (build_stub_object (arg));
expr = build_special_member_call (ob, complete_ctor_identifier, &args,
- ctype, LOOKUP_NORMAL, tf_none);
+ ctype, LOOKUP_NORMAL, complain);
}
if (expr == error_mark_node)
return error_mark_node;
@@ -2276,7 +2296,7 @@ constructible_expr (tree to, tree from)
{
tree dtor = build_special_member_call (ob, complete_dtor_identifier,
NULL, ctype, LOOKUP_NORMAL,
- tf_none);
+ complain);
if (dtor == error_mark_node)
return error_mark_node;
if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype))
@@ -2286,12 +2306,15 @@ constructible_expr (tree to, tree from)
else
{
if (len == 0)
- return build_value_init (strip_array_types (to), tf_none);
+ return build_value_init (strip_array_types (to), complain);
if (len > 1)
{
if (cxx_dialect < cxx20)
- /* Too many initializers. */
- return error_mark_node;
+ {
+ if (explain)
+ error ("too many initializers for non-class type %qT", to);
+ return error_mark_node;
+ }
/* In C++20 this is well-formed:
using T = int[2];
@@ -2312,9 +2335,11 @@ constructible_expr (tree to, tree from)
}
else
from = build_stub_object (TREE_VEC_ELT (from, 0));
+
+ tree orig_from = from;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
/* If t(e) didn't work, maybe t{e} will. */
if (expr == NULL_TREE
&& len == 1
@@ -2326,7 +2351,24 @@ constructible_expr (tree to, tree from)
CONSTRUCTOR_IS_PAREN_INIT (from) = true;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
+ }
+
+ if (expr == NULL_TREE && explain)
+ {
+ if (len > 1)
+ error ("too many initializers for non-class type %qT", to);
+ else
+ {
+ /* Redo the implicit conversion for diagnostics. */
+ int count = errorcount + warningcount;
+ perform_implicit_conversion_flags (to, orig_from, complain,
+ LOOKUP_NORMAL);
+ if (count == errorcount + warningcount)
+ /* The message may have been suppressed due to -w + -fpermissive,
+ emit a generic response instead. */
+ error ("the conversion is invalid");
+ }
}
}
return expr;
@@ -2340,20 +2382,25 @@ constructible_expr (tree to, tree from)
valid or error_mark_node if not. */
static tree
-destructible_expr (tree to)
+destructible_expr (tree to, bool explain)
{
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
if (TYPE_REF_P (to))
return void_node;
if (!COMPLETE_TYPE_P (complete_type (to)))
- return error_mark_node;
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
to = strip_array_types (to);
if (CLASS_TYPE_P (to))
{
- to = build_trait_object (to);
+ to = build_trait_object (to, complain);
return build_delete (input_location, TREE_TYPE (to), to,
- sfk_complete_destructor, flags, 0, tf_none);
+ sfk_complete_destructor, flags, 0, complain);
}
/* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
shall be a scalar type.... */
@@ -2365,70 +2412,95 @@ destructible_expr (tree to)
/* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN is
+ set, emit a diagnostic explaining why the operation failed. */
static tree
-is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
+is_xible_helper (enum tree_code code, tree to, tree from, bool explain)
{
to = complete_type (to);
deferring_access_check_sentinel acs (dk_no_deferred);
- if (VOID_TYPE_P (to)
- || (from && FUNC_OR_METHOD_TYPE_P (from)
- && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
- return error_mark_node;
+
+ if (VOID_TYPE_P (to))
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
+ if (from
+ && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))
+ {
+ if (explain)
+ error ("%qT is a qualified function type", from);
+ return error_mark_node;
+ }
+
tree expr;
if (code == MODIFY_EXPR)
- expr = assignable_expr (to, from);
+ expr = assignable_expr (to, from, explain);
else if (code == BIT_NOT_EXPR)
- expr = destructible_expr (to);
- else if (trivial && TREE_VEC_LENGTH (from) > 1
- && cxx_dialect < cxx20)
- return error_mark_node; // only 0- and 1-argument ctors can be trivial
- // before C++20 aggregate paren init
+ expr = destructible_expr (to, explain);
else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
- return error_mark_node; // can't construct an array of unknown bound
+ {
+ if (explain)
+ error ("cannot construct an array of unknown bound");
+ return error_mark_node;
+ }
else
- expr = constructible_expr (to, from);
+ expr = constructible_expr (to, from, explain);
return expr;
}
/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+is_trivially_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/true);
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
+
tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
+ if (explain && nt)
+ inform (location_of (nt), "%qE is non-trivial", nt);
return !nt;
}
/* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_nothrow_xible (enum tree_code code, tree to, tree from)
+is_nothrow_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
++cp_noexcept_operand;
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
--cp_noexcept_operand;
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
+ return is_noexcept;
}
/* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_xible (enum tree_code code, tree to, tree from)
+is_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2453,7 +2525,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
return false;
/* We don't check is_constructible<T, U>: if T isn't constructible
from U, we won't be able to create a conversion. */
- tree val = build_trait_object (from);
+ tree val = build_trait_object (from, tf_none);
if (val == error_mark_node)
return false;
if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE)
@@ -2462,25 +2534,36 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
}
/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit
- conversion from FROM to TO and return the result. */
+ conversion from FROM to TO and return the result. If EXPLAIN, emit a
+ diagnostic about why the conversion failed. */
static tree
-is_convertible_helper (tree from, tree to)
+is_convertible_helper (tree from, tree to, bool explain)
{
if (VOID_TYPE_P (from) && VOID_TYPE_P (to))
return integer_one_node;
cp_unevaluated u;
- tree expr = build_trait_object (from);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
/* std::is_{,nothrow_}convertible test whether the imaginary function
definition
To test() { return std::declval<From>(); }
is well-formed. A function can't return a function. */
- if (FUNC_OR_METHOD_TYPE_P (to) || expr == error_mark_node)
+ if (FUNC_OR_METHOD_TYPE_P (to))
+ {
+ if (explain)
+ error ("%qT is a function type", to);
+ return error_mark_node;
+ }
+
+ tree expr = build_trait_object (from, complain);
+ if (expr == error_mark_node)
return error_mark_node;
+
deferring_access_check_sentinel acs (dk_no_deferred);
- return perform_implicit_conversion (to, expr, tf_none);
+ return perform_implicit_conversion (to, expr, complain);
}
/* Return true if FROM can be converted to TO using implicit conversions,
@@ -2489,9 +2572,9 @@ is_convertible_helper (tree from, tree to)
to either type" restriction. */
bool
-is_convertible (tree from, tree to)
+is_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2500,12 +2583,16 @@ is_convertible (tree from, tree to)
/* Like is_convertible, but the conversion is also noexcept. */
bool
-is_nothrow_convertible (tree from, tree to)
+is_nothrow_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
+ return is_noexcept;
}
/* Categorize various special_function_kinds. */
@@ -3586,21 +3673,24 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
the program is ill-formed" */
|| !TYPE_REF_P (parmtype)));
/* Decide if we want to emit a pedwarn, error, or a warning. */
- diagnostic_t diag_kind;
+ enum diagnostics::kind diag_kind;
int opt;
if (illformed_p)
{
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
opt = 0;
}
else
{
- diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN;
+ diag_kind = (cxx_dialect >= cxx20
+ ? diagnostics::kind::warning
+ : diagnostics::kind::pedwarn);
opt = OPT_Wdefaulted_function_deleted;
}
/* Don't warn for template instantiations. */
- if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING)
+ if (DECL_TEMPLATE_INSTANTIATION (fn)
+ && diag_kind == diagnostics::kind::warning)
return;
const char *wmsg;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 6b5a60a..9412f78 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3883,9 +3883,9 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr);
bool read_macro_maps (line_map_uint_t);
- void write_diagnostic_classification (elf_out *, diagnostic_context *,
+ void write_diagnostic_classification (elf_out *, diagnostics::context *,
unsigned *);
- bool read_diagnostic_classification (diagnostic_context *);
+ bool read_diagnostic_classification (diagnostics::context *);
private:
void write_define (bytes_out &, const cpp_macro *);
@@ -4822,7 +4822,8 @@ noisy_p ()
return false;
pp_needs_newline (global_dc->get_reference_printer ()) = true;
- diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL);
+ diagnostic_set_last_function (global_dc,
+ (diagnostics::diagnostic_info *) nullptr);
return true;
}
@@ -6157,7 +6158,7 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
WB (lang->declared_class);
WB (lang->diamond_shaped);
WB (lang->repeated_base);
- gcc_assert (!lang->being_defined);
+ gcc_checking_assert (!lang->being_defined);
// lang->debug_requested
WB (lang->fields_readonly);
WB (lang->ptrmemfunc_flag);
@@ -6183,6 +6184,14 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
WB (lang->has_constexpr_ctor);
WB (lang->unique_obj_representations);
WB (lang->unique_obj_representations_set);
+ gcc_checking_assert (!lang->erroneous);
+ WB (lang->non_pod_aggregate);
+ WB (lang->non_aggregate_pod);
+ WB (lang->trivially_relocatable);
+ WB (lang->trivially_relocatable_computed);
+
+ WB (lang->replaceable);
+ WB (lang->replaceable_computed);
#undef WB
}
@@ -6227,8 +6236,8 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
RB (lang->declared_class);
RB (lang->diamond_shaped);
RB (lang->repeated_base);
- gcc_assert (!lang->being_defined);
- gcc_assert (!lang->debug_requested);
+ gcc_checking_assert (!lang->being_defined);
+ gcc_checking_assert (!lang->debug_requested);
RB (lang->fields_readonly);
RB (lang->ptrmemfunc_flag);
@@ -6253,6 +6262,14 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
RB (lang->has_constexpr_ctor);
RB (lang->unique_obj_representations);
RB (lang->unique_obj_representations_set);
+ gcc_checking_assert (!lang->erroneous);
+ RB (lang->non_pod_aggregate);
+ RB (lang->non_aggregate_pod);
+ RB (lang->trivially_relocatable);
+ RB (lang->trivially_relocatable_computed);
+
+ RB (lang->replaceable);
+ RB (lang->replaceable_computed);
#undef RB
return !get_overrun ();
}
@@ -6543,8 +6560,14 @@ trees_out::core_vals (tree t)
}
WT (t->function_decl.personality);
- WT (t->function_decl.function_specific_target);
- WT (t->function_decl.function_specific_optimization);
+ /* Rather than streaming target/optimize nodes, we should reconstruct
+ them on stream-in from any attributes applied to the function. */
+ if (streaming_p () && t->function_decl.function_specific_target)
+ warning_at (DECL_SOURCE_LOCATION (t), 0,
+ "%<target%> attribute currently unsupported in modules");
+ if (streaming_p () && t->function_decl.function_specific_optimization)
+ warning_at (DECL_SOURCE_LOCATION (t), 0,
+ "%<optimize%> attribute currently unsupported in modules");
WT (t->function_decl.vindex);
if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
@@ -6634,11 +6657,12 @@ trees_out::core_vals (tree t)
case TARGET_OPTION_NODE:
// FIXME: Our representation for these two nodes is a cache of
// the resulting set of options. Not a record of the options
- // that got changed by a particular attribute or pragma. Should
- // we record that, or should we record the diff from the command
- // line options? The latter seems the right behaviour, but is
- // (a) harder, and I guess could introduce strangeness if the
- // importer has set some incompatible set of optimization flags?
+ // that got changed by a particular attribute or pragma. Instead
+ // of recording that, we probably should just rebuild the options
+ // on stream-in from the function attributes. This could introduce
+ // strangeness if the importer has some incompatible set of flags
+ // but we currently assume users "know what they're doing" in such
+ // a case anyway.
gcc_unreachable ();
break;
@@ -6785,6 +6809,13 @@ trees_out::core_vals (tree t)
if (streaming_p ())
WU (((lang_tree_node *)t)->trait_expression.kind);
break;
+
+ case TU_LOCAL_ENTITY:
+ WT (((lang_tree_node *)t)->tu_local_entity.name);
+ if (state)
+ state->write_location
+ (*this, ((lang_tree_node *)t)->tu_local_entity.loc);
+ break;
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
@@ -7090,8 +7121,10 @@ trees_in::core_vals (tree t)
}
RT (t->function_decl.personality);
- RT (t->function_decl.function_specific_target);
- RT (t->function_decl.function_specific_optimization);
+ /* These properties are not streamed, and should be reconstructed
+ from any function attributes. */
+ // t->function_decl.function_specific_target);
+ // t->function_decl.function_specific_optimization);
RT (t->function_decl.vindex);
if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
@@ -7197,7 +7230,7 @@ trees_in::core_vals (tree t)
case OPTIMIZATION_NODE:
case TARGET_OPTION_NODE:
- /* Not yet implemented, see trees_out::core_vals. */
+ /* Not implemented, see trees_out::core_vals. */
gcc_unreachable ();
break;
@@ -7328,6 +7361,11 @@ trees_in::core_vals (tree t)
RT (((lang_tree_node *)t)->trait_expression.type2);
RUC (cp_trait_kind, ((lang_tree_node *)t)->trait_expression.kind);
break;
+
+ case TU_LOCAL_ENTITY:
+ RT (((lang_tree_node *)t)->tu_local_entity.name);
+ ((lang_tree_node *)t)->tu_local_entity.loc
+ = state->read_location (*this);
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
@@ -10268,7 +10306,8 @@ trees_in::tree_node (bool is_use)
&& dump ("Read %stypedef %C:%N",
DECL_IMPLICIT_TYPEDEF_P (res) ? "implicit " : "",
TREE_CODE (res), res);
- res = TREE_TYPE (res);
+ if (TREE_CODE (res) != TU_LOCAL_ENTITY)
+ res = TREE_TYPE (res);
}
break;
@@ -11124,8 +11163,7 @@ trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn)
{
tree existing_parm = existing ? DECL_ARGUMENTS (existing) : NULL_TREE;
tree parms = DECL_ARGUMENTS (fn);
- unsigned ix = 0;
- for (tree parm = parms; parm; parm = DECL_CHAIN (parm), ix++)
+ for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
{
if (existing_parm)
{
@@ -11135,6 +11173,20 @@ trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn)
names of the parms from us. */
DECL_NAME (existing_parm) = DECL_NAME (parm);
DECL_SOURCE_LOCATION (existing_parm) = DECL_SOURCE_LOCATION (parm);
+
+ /* And some other flags important for codegen are only set
+ by the definition. */
+ TREE_ADDRESSABLE (existing_parm) = TREE_ADDRESSABLE (parm);
+ DECL_BY_REFERENCE (existing_parm) = DECL_BY_REFERENCE (parm);
+ DECL_NONLOCAL (existing_parm) = DECL_NONLOCAL (parm);
+ DECL_ARG_TYPE (existing_parm) = DECL_ARG_TYPE (parm);
+
+ /* Invisiref parms had their types adjusted by cp_genericize. */
+ if (DECL_BY_REFERENCE (parm))
+ {
+ TREE_TYPE (existing_parm) = TREE_TYPE (parm);
+ relayout_decl (existing_parm);
+ }
}
back_refs[~tag] = existing_parm;
@@ -13393,13 +13445,19 @@ trees_in::read_class_def (tree defn, tree maybe_template)
if (TYPE_LANG_SPECIFIC (type))
{
- CLASSTYPE_LAMBDA_EXPR (type) = lambda;
+ if (!TYPE_POLYMORPHIC_P (type))
+ SET_CLASSTYPE_LAMBDA_EXPR (type, lambda);
+ else
+ gcc_checking_assert (lambda == NULL_TREE);
CLASSTYPE_MEMBER_VEC (type) = member_vec;
CLASSTYPE_PURE_VIRTUALS (type) = pure_virts;
CLASSTYPE_VCALL_INDICES (type) = vcall_indices;
- CLASSTYPE_KEY_METHOD (type) = key_method;
+ if (TYPE_POLYMORPHIC_P (type))
+ SET_CLASSTYPE_KEY_METHOD (type, key_method);
+ else
+ gcc_checking_assert (key_method == NULL_TREE);
CLASSTYPE_VBASECLASSES (type) = vbase_vec;
@@ -18320,22 +18378,23 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
/* Return the prefix to use for dumping a #pragma diagnostic change to DK. */
static const char *
-dk_string (diagnostic_t dk)
+dk_string (enum diagnostics::kind dk)
{
- gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND);
- if (dk == DK_IGNORED)
- /* diagnostic.def has an empty string for ignored. */
+ gcc_assert (dk > diagnostics::kind::unspecified
+ && dk < diagnostics::kind::last_diagnostic_kind);
+ if (dk == diagnostics::kind::ignored)
+ /* diagnostics/kinds.def has an empty string for ignored. */
return "ignored: ";
else
- return get_diagnostic_kind_text (dk);
+ return diagnostics::get_text_for_kind (dk);
}
/* Dump one #pragma GCC diagnostic entry. */
static bool
-dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
+dump_dc_change (unsigned index, unsigned opt, enum diagnostics::kind dk)
{
- if (dk == DK_POP)
+ if (dk == diagnostics::kind::pop)
return dump (" Index %u: pop from %d", index, opt);
else
return dump (" Index %u: %s%s", index, dk_string (dk),
@@ -18346,7 +18405,7 @@ dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
void
module_state::write_diagnostic_classification (elf_out *to,
- diagnostic_context *dc,
+ diagnostics::context *dc,
unsigned *crc_p)
{
auto &changes = dc->get_classification_history ();
@@ -18362,9 +18421,10 @@ module_state::write_diagnostic_classification (elf_out *to,
unsigned len = changes.length ();
/* We don't want to write out any entries that came from one of our imports.
- But then we need to adjust the total, and change DK_POP targets to match
- the index in our actual output. So remember how many lines we had skipped
- at each step, where -1 means this line itself is skipped. */
+ But then we need to adjust the total, and change diagnostics::kind::pop
+ targets to match the index in our actual output. So remember how many
+ lines we had skipped at each step, where -1 means this line itself
+ is skipped. */
int skips = 0;
auto_vec<int> skips_at (len);
skips_at.safe_grow (len);
@@ -18397,10 +18457,10 @@ module_state::write_diagnostic_classification (elf_out *to,
if (sec.streaming_p ())
{
unsigned opt = c.option;
- if (c.kind == DK_POP)
+ if (c.kind == diagnostics::kind::pop)
opt -= skips_at[opt];
sec.u (opt);
- sec.u (c.kind);
+ sec.u (static_cast<unsigned> (c.kind));
dump () && dump_dc_change (i - skips_at[i], opt, c.kind);
}
}
@@ -18415,7 +18475,7 @@ module_state::write_diagnostic_classification (elf_out *to,
/* Read any #pragma GCC diagnostic info from the .dgc section. */
bool
-module_state::read_diagnostic_classification (diagnostic_context *dc)
+module_state::read_diagnostic_classification (diagnostics::context *dc)
{
bytes_in sec;
@@ -18435,8 +18495,8 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
{
location_t loc = read_location (sec);
int opt = sec.u ();
- diagnostic_t kind = (diagnostic_t) sec.u ();
- if (kind == DK_POP)
+ enum diagnostics::kind kind = (enum diagnostics::kind) sec.u ();
+ if (kind == diagnostics::kind::pop)
/* For a pop, opt is the 'changes' index to return to. */
opt += offset;
changes.quick_push ({ loc, opt, kind });
@@ -18451,7 +18511,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
gcc_checking_assert (i >= offset);
const auto &c = changes[i];
- if (c.kind != DK_POP)
+ if (c.kind != diagnostics::kind::pop)
break;
else if (c.option == offset)
{
@@ -18468,7 +18528,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
/* It didn't, so add a pop at its last location to avoid affecting later
imports. */
location_t last_loc = ordinary_locs.first + ordinary_locs.second - 1;
- changes.quick_push ({ last_loc, offset, DK_POP });
+ changes.quick_push ({ last_loc, offset, diagnostics::kind::pop });
dump () && dump (" Adding final pop from index %d", offset);
}
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 9aa7c16..f5b36c9 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -7195,7 +7195,7 @@ suggest_alternatives_for_1 (location_t location, tree name,
/* Look for exact matches for builtin defines that would have been
defined if the user had passed a command-line option (e.g. -fopenmp
for "_OPENMP"). */
- diagnostic_option_id option_id
+ diagnostics::option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
return name_hint
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8148495..860f3f0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2519,7 +2519,7 @@ static cp_expr cp_parser_id_expression
static cp_expr cp_parser_unqualified_id
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
- (cp_parser *, bool, bool, bool, bool, bool = false);
+ (cp_parser *, bool, bool, bool, bool, bool = false, bool = false);
static tree cp_parser_nested_name_specifier
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_qualifying_entity
@@ -2576,11 +2576,11 @@ static cp_expr cp_parser_constant_expression
static cp_expr cp_parser_builtin_offsetof
(cp_parser *);
static cp_expr cp_parser_lambda_expression
- (cp_parser *);
+ (cp_parser *, bool = false);
static void cp_parser_lambda_introducer
(cp_parser *, tree);
static bool cp_parser_lambda_declarator_opt
- (cp_parser *, tree);
+ (cp_parser *, tree, bool = false);
static void cp_parser_lambda_body
(cp_parser *, tree);
@@ -2921,7 +2921,7 @@ static size_t cp_parser_skip_std_attribute_spec_seq
static size_t cp_parser_skip_attributes_opt
(cp_parser *, size_t);
static bool cp_parser_extension_opt
- (cp_parser *, int *);
+ (cp_parser *, int *, int *);
static void cp_parser_label_declaration
(cp_parser *);
@@ -3091,8 +3091,8 @@ static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, required_token);
static bool cp_parser_token_starts_function_definition_p
(cp_token *);
-static bool cp_parser_next_token_starts_class_definition_p
- (cp_parser *);
+static bool cp_parser_nth_token_starts_class_definition_p
+ (cp_parser *, size_t);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
static bool cp_parser_nth_token_starts_template_argument_list_p
@@ -5266,7 +5266,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
&& (id_equal (suffix_id, "i")
|| id_equal (suffix_id, "if")
|| id_equal (suffix_id, "il")));
- diagnostic_t kind = DK_ERROR;
+ enum diagnostics::kind kind = diagnostics::kind::error;
int opt = 0;
if (i14 && ext)
@@ -5276,7 +5276,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
if (cxlit == error_mark_node)
{
/* No <complex>, so pedwarn and use GNU semantics. */
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
opt = OPT_Wpedantic;
}
}
@@ -5303,7 +5303,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
"to enable more built-in suffixes");
}
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
value = error_mark_node;
else
{
@@ -6647,7 +6647,8 @@ cp_parser_primary_expression (cp_parser *parser,
member template. */
static void
-missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING)
+missing_template_diag (location_t loc,
+ enum diagnostics::kind diag_kind = diagnostics::kind::warning)
{
if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword))
return;
@@ -7242,18 +7243,22 @@ check_template_keyword_in_nested_name_spec (tree name)
nested-name-specifier template [opt] simple-template-id ::
PARSER->SCOPE should be set appropriately before this function is
- called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in
- effect. TYPE_P is TRUE if we non-type bindings should be ignored
- in name lookups.
+ called. TYPENAME_KEYWORD_P is true if the `typename' keyword is in
+ effect. TYPE_P is true if we non-type bindings should be ignored
+ in name lookups. TEMPLATE_KEYWORD_P is true if the `template' keyword
+ was seen. GLOBAL_P is true if `::' has already been parsed.
+ TODO: This function doesn't handle the C++14 change to make `::'
+ a nested-name-specifier by itself. If it did, GLOBAL_P could probably
+ go.
Sets PARSER->SCOPE to the class (TYPE) or namespace
(NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
it unchanged if there is no nested-name-specifier. Returns the new
scope iff there is a nested-name-specifier, or NULL_TREE otherwise.
- If CHECK_DEPENDENCY_P is FALSE, names are looked up in dependent scopes.
+ If CHECK_DEPENDENCY_P is false, names are looked up in dependent scopes.
- If IS_DECLARATION is TRUE, the nested-name-specifier is known to be
+ If IS_DECLARATION is true, the nested-name-specifier is known to be
part of a declaration and/or decl-specifier. */
static tree
@@ -7262,7 +7267,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool check_dependency_p,
bool type_p,
bool is_declaration,
- bool template_keyword_p /* = false */)
+ bool template_keyword_p /* = false */,
+ bool global_p /* = false */)
{
bool success = false;
cp_token_position start = 0;
@@ -7310,8 +7316,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
/* Spot cases that cannot be the beginning of a
nested-name-specifier. On the second and subsequent times
- through the loop, we look for the `template' keyword. */
- if (success && token->keyword == RID_TEMPLATE)
+ (or the first, if '::' has already been parsed) through the
+ loop, we look for the `template' keyword. */
+ if ((success || global_p) && token->keyword == RID_TEMPLATE)
;
/* A template-id can start a nested-name-specifier. */
else if (token->type == CPP_TEMPLATE_ID)
@@ -7359,8 +7366,11 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
cp_parser_parse_tentatively (parser);
/* Look for the optional `template' keyword, if this isn't the
- first time through the loop. */
- if (success)
+ first time through the loop, or if we've already parsed '::';
+ this is then the
+ nested-name-specifier template [opt] simple-template-id ::
+ production. */
+ if (success || global_p)
{
template_keyword_p = cp_parser_optional_template_keyword (parser);
/* DR1710: "In a qualified-id used as the name in
@@ -8845,8 +8855,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
{
/* In a template, be permissive by treating an object expression
of incomplete type as dependent (after a pedwarn). */
- diagnostic_t kind = (processing_template_decl
- && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR);
+ enum diagnostics::kind kind = ((processing_template_decl
+ && MAYBE_CLASS_TYPE_P (*scope))
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::error);
switch (TREE_CODE (*postfix_expression))
{
@@ -8858,27 +8870,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
case IMPLICIT_CONV_EXPR:
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
case OVERLOAD:
/* Don't emit any diagnostic for OVERLOADs. */
- kind = DK_IGNORED;
+ kind = diagnostics::kind::ignored;
break;
default:
/* Avoid clobbering e.g. DECLs. */
if (!EXPR_P (*postfix_expression))
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
}
- if (kind == DK_IGNORED)
+ if (kind == diagnostics::kind::ignored)
return false;
location_t exploc = location_of (*postfix_expression);
cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind);
if (!MAYBE_CLASS_TYPE_P (*scope))
return true;
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
*scope = *postfix_expression = error_mark_node;
else if (processing_template_decl)
{
@@ -9492,21 +9504,23 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
case RID_EXTENSION:
{
/* The saved value of the PEDANTIC flag. */
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
tree expr;
/* Save away the PEDANTIC flag. */
- cp_parser_extension_opt (parser, &saved_pedantic);
+ cp_parser_extension_opt (parser, &saved_pedantic,
+ &saved_long_long);
/* Also suppress -Wconditionally-supported. */
diagnostic_push_diagnostics (global_dc, input_location);
diagnostic_classify_diagnostic
(global_dc, OPT_Wconditionally_supported,
- DK_IGNORED, input_location);
+ diagnostics::kind::ignored, input_location);
/* Parse the cast-expression. */
expr = cp_parser_simple_cast_expression (parser);
/* Restore the PEDANTIC flag. */
diagnostic_pop_diagnostics (global_dc, input_location);
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return expr;
}
@@ -11730,10 +11744,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* trait)
lambda-introducer < template-parameter-list > requires-clause [opt]
lambda-declarator [opt] compound-statement
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda.
+
Returns a representation of the expression. */
static cp_expr
-cp_parser_lambda_expression (cp_parser* parser)
+cp_parser_lambda_expression (cp_parser* parser,
+ bool consteval_block_p/*=false*/)
{
tree lambda_expr = build_lambda_expr ();
tree type;
@@ -11742,6 +11760,7 @@ cp_parser_lambda_expression (cp_parser* parser)
cp_token_position start = 0;
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
+ LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lambda_expr) = consteval_block_p;
if (cxx_dialect >= cxx20)
{
@@ -11785,9 +11804,12 @@ cp_parser_lambda_expression (cp_parser* parser)
it now. */
push_deferring_access_checks (dk_no_deferred);
- cp_parser_lambda_introducer (parser, lambda_expr);
- if (cp_parser_error_occurred (parser))
- return error_mark_node;
+ if (!consteval_block_p)
+ {
+ cp_parser_lambda_introducer (parser, lambda_expr);
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
+ }
{
/* OK, this is a bit tricksy. cp_parser_requires_expression sets
@@ -11829,6 +11851,7 @@ cp_parser_lambda_expression (cp_parser* parser)
bool auto_is_implicit_function_template_parm_p
= parser->auto_is_implicit_function_template_parm_p;
bool saved_omp_array_section_p = parser->omp_array_section_p;
+ bool saved_in_targ = parser->in_template_argument_list_p;
parser->num_template_parameter_lists = 0;
parser->in_statement = 0;
@@ -11838,6 +11861,7 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->implicit_template_scope = 0;
parser->auto_is_implicit_function_template_parm_p = false;
parser->omp_array_section_p = false;
+ parser->in_template_argument_list_p = false;
/* Inside the lambda, outside unevaluated context do not apply. */
cp_evaluated ev;
@@ -11857,7 +11881,8 @@ cp_parser_lambda_expression (cp_parser* parser)
if (cp_parser_start_tentative_firewall (parser))
start = token;
- ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
+ ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr,
+ consteval_block_p);
if (ok && cp_parser_error_occurred (parser))
ok = false;
@@ -11892,6 +11917,7 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->auto_is_implicit_function_template_parm_p
= auto_is_implicit_function_template_parm_p;
parser->omp_array_section_p = saved_omp_array_section_p;
+ parser->in_template_argument_list_p = saved_in_targ;
}
/* This lambda shouldn't have any proxies left at this point. */
@@ -12239,10 +12265,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
decl-specifier-seq [opt] noexcept-specifier [opt]
attribute-specifier-seq [opt] trailing-return-type [opt]
- LAMBDA_EXPR is the current representation of the lambda expression. */
+ LAMBDA_EXPR is the current representation of the lambda expression.
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda. */
static bool
-cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
+cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr,
+ bool consteval_block_p/*=false*/)
{
/* 5.1.1.4 of the standard says:
If a lambda-expression does not include a lambda-declarator, it is as if
@@ -12345,6 +12374,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
+ /* [dcl.pre] For a consteval-block-declaration D, the expression E
+ corresponding to D is:
+ [] -> void static consteval compound-statement ()
+ Make it so. */
+ if (consteval_block_p)
+ {
+ return_type = void_type_node;
+ lambda_specs.storage_class = sc_static;
+ set_and_check_decl_spec_loc (&lambda_specs, ds_consteval,
+ cp_lexer_peek_token (parser->lexer));
+ }
+
if (omitted_parms_loc && lambda_specs.any_specifiers_p)
{
pedwarn (omitted_parms_loc, OPT_Wc__23_extensions,
@@ -16032,15 +16073,16 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
static void
cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_declaration (parser, prefix_attrs);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16282,6 +16324,56 @@ cp_parser_toplevel_declaration (cp_parser* parser)
cp_parser_declaration (parser, NULL_TREE);
}
+/* Build an empty string for static_assert. */
+
+static tree
+build_empty_string ()
+{
+ tree message = build_string (1, "");
+ TREE_TYPE (message) = char_array_type_node;
+ fix_string_type (message);
+ return message;
+}
+
+/* Return true iff the next tokens start a C++26 consteval block. */
+
+static bool
+cp_parser_next_tokens_are_consteval_block_p (cp_parser *parser)
+{
+ return (cxx_dialect >= cxx26
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE));
+}
+
+/* Parse a consteval-block-declaration.
+
+ consteval-block-declaration:
+ consteval compound-statement
+
+ If MEMBER_P, this consteval block is a member declaration. */
+
+static void
+cp_parser_consteval_block (cp_parser *parser, bool member_p)
+{
+ const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ /* Consume the 'consteval'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* We know the next token is '{'. Let cp_parser_lambda_body handle it. */
+ cp_expr lam = cp_parser_lambda_expression (parser,
+ /*consteval_block_p=*/true);
+ if (!cp_parser_error_occurred (parser))
+ {
+ releasing_vec args;
+ tree call = finish_call_expr (lam, &args,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false,
+ tf_warning_or_error);
+ finish_static_assert (call, build_empty_string (), loc, member_p,
+ /*show_expr_p=*/false, /*consteval_block_p=*/true);
+ }
+}
+
/* Parse a block-declaration.
block-declaration:
@@ -16289,18 +16381,18 @@ cp_parser_toplevel_declaration (cp_parser* parser)
asm-definition
namespace-alias-definition
using-declaration
+ using-enum-declaration
using-directive
+ static_assert-declaration
+ consteval-block-declaration
+ alias-declaration
+ opaque-enum-declaration
GNU Extension:
block-declaration:
__extension__ block-declaration
- C++0x Extension:
-
- block-declaration:
- static_assert-declaration
-
If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */
@@ -16308,15 +16400,16 @@ static void
cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_block_declaration (parser, statement_p);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16377,6 +16470,8 @@ cp_parser_block_declaration (cp_parser *parser,
/* If the next token is `static_assert' we have a static assertion. */
else if (token1->keyword == RID_STATIC_ASSERT)
cp_parser_static_assert (parser, /*member_p=*/false);
+ else if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ cp_parser_consteval_block (parser, /*member_p=*/false);
else
{
size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1);
@@ -17680,9 +17775,7 @@ cp_parser_static_assert (cp_parser *parser, bool member_p)
"only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
- message = build_string (1, "");
- TREE_TYPE (message) = char_array_type_node;
- fix_string_type (message);
+ message = build_empty_string ();
}
else
{
@@ -21167,7 +21260,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/true,
/*type_p=*/false,
- /*is_declaration=*/false)
+ /*is_declaration=*/false,
+ /*template_keyword_p=*/false,
+ global_p)
!= NULL_TREE);
/* If we have seen a nested-name-specifier, and the next token
is `template', then we are using the template-id production. */
@@ -22017,7 +22112,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
bool template_p =
(template_parm_lists_apply
- && (cp_parser_next_token_starts_class_definition_p (parser)
+ && (cp_parser_nth_token_starts_class_definition_p (parser, 1)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
/* An unqualified name was used to reference this type, so
there were no qualifying templates. */
@@ -28054,6 +28149,98 @@ cp_parser_class_specifier (cp_parser* parser)
return type;
}
+/* Parse an (optional) class-property-specifier-seq.
+
+ class-property-specifier-seq:
+ class-property-specifier class-property-specifier-seq [opt]
+
+ class-property-specifier:
+ final
+ trivially_relocatable_if_eligible (C++26)
+ replaceable_if_eligible (C++26)
+
+ Returns a bitmask representing the class-property-specifiers. */
+
+static cp_virt_specifiers
+cp_parser_class_property_specifier_seq_opt (cp_parser *parser)
+{
+ cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+
+ while (true)
+ {
+ cp_token *token;
+ cp_virt_specifiers virt_specifier;
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a class-property-specifier. */
+ if (token->type != CPP_NAME)
+ break;
+ if (id_equal (token->u.value, "final"))
+ {
+ /* For C++98, quietly ignore final in e.g.
+ struct S final = 24; */
+ if (cxx_dialect == cxx98
+ && virt_specifiers == VIRT_SPEC_UNSPECIFIED
+ && !cp_parser_nth_token_starts_class_definition_p (parser, 2)
+ && !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+ break;
+ maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS);
+ virt_specifier = VIRT_SPEC_FINAL;
+ }
+ else if (id_equal (token->u.value, "__final"))
+ virt_specifier = VIRT_SPEC_FINAL;
+ else if (id_equal (token->u.value, "trivially_relocatable_if_eligible"))
+ {
+ if (cxx_dialect < cxx26)
+ {
+ /* Warn about the C++26 conditional keyword (but don't parse
+ it). */
+ warning_at (token->location, OPT_Wc__26_compat,
+ "identifier %qE is a conditional keyword in C++26",
+ token->u.value);
+ break;
+ }
+ virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE;
+ }
+ else if (id_equal (token->u.value,
+ "__trivially_relocatable_if_eligible"))
+ virt_specifier = VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE;
+ else if (id_equal (token->u.value, "replaceable_if_eligible"))
+ {
+ if (cxx_dialect < cxx26)
+ {
+ /* Warn about the C++26 conditional keyword (but don't parse
+ it). */
+ warning_at (token->location, OPT_Wc__26_compat,
+ "identifier %qE is a conditional keyword in C++26",
+ token->u.value);
+ break;
+ }
+ virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE;
+ }
+ else if (id_equal (token->u.value,
+ "__replaceable_if_eligible"))
+ virt_specifier = VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE;
+ else
+ break;
+
+ if (virt_specifiers & virt_specifier)
+ {
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_remove ();
+ error_at (&richloc, "duplicate %qD specifier", token->u.value);
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ virt_specifiers |= virt_specifier;
+ }
+ }
+ return virt_specifiers;
+}
+
/* Parse a class-head.
class-head:
@@ -28244,18 +28431,16 @@ cp_parser_class_head (cp_parser* parser,
pop_deferring_access_checks ();
if (id)
- {
- cp_parser_check_for_invalid_template_id (parser, id,
- class_key,
- type_start_token->location);
- }
- virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ cp_parser_check_for_invalid_template_id (parser, id,
+ class_key,
+ type_start_token->location);
+ virt_specifiers = cp_parser_class_property_specifier_seq_opt (parser);
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
class-specifier. We have to detect this situation before calling
xref_tag, since that has irreversible side-effects. */
- if (!cp_parser_next_token_starts_class_definition_p (parser))
+ if (!cp_parser_nth_token_starts_class_definition_p (parser, 1))
{
cp_parser_error (parser, "expected %<{%> or %<:%>");
type = error_mark_node;
@@ -28265,13 +28450,6 @@ cp_parser_class_head (cp_parser* parser,
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
- if (virt_specifiers & VIRT_SPEC_OVERRIDE)
- {
- cp_parser_error (parser,
- "cannot specify %<override%> for a class");
- type = error_mark_node;
- goto out;
- }
/* Issue the error about the overly-qualified name now. */
if (qualified_p)
{
@@ -28599,6 +28777,16 @@ cp_parser_class_head (cp_parser* parser,
DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
if (type && (virt_specifiers & VIRT_SPEC_FINAL))
CLASSTYPE_FINAL (type) = 1;
+ if (type && (virt_specifiers & VIRT_SPEC_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE))
+ {
+ gcc_assert (!CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (type));
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (type) = 1;
+ }
+ if (type && (virt_specifiers & VIRT_SPEC_REPLACEABLE_IF_ELIGIBLE))
+ {
+ gcc_assert (!CLASSTYPE_REPLACEABLE_COMPUTED (type));
+ CLASSTYPE_REPLACEABLE_BIT (type) = 1;
+ }
out:
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
return type;
@@ -28717,12 +28905,20 @@ cp_parser_member_specification_opt (cp_parser* parser)
/* Parse a member-declaration.
member-declaration:
- decl-specifier-seq [opt] member-declarator-list [opt] ;
- function-definition ; [opt]
- :: [opt] nested-name-specifier template [opt] unqualified-id ;
+ attribute-specifier-seq [opt] decl-specifier-seq [opt]
+ member-declarator-list [opt] ;
+ function-definition
+ friend-type-declaration
using-declaration
+ using-enum-declaration
+ static_assert-declaration
+ consteval-block-declaration
template-declaration
+ explicit-specialization
+ deduction-guide
alias-declaration
+ opaque-enum-declaration
+ empty-declaration
member-declarator-list:
member-declarator
@@ -28741,12 +28937,7 @@ cp_parser_member_specification_opt (cp_parser* parser)
member-declarator:
declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [opt]
- identifier [opt] attributes [opt] : constant-expression
-
- C++0x Extensions:
-
- member-declaration:
- static_assert-declaration */
+ identifier [opt] attributes [opt] : constant-expression */
static void
cp_parser_member_declaration (cp_parser* parser)
@@ -28759,16 +28950,17 @@ cp_parser_member_declaration (cp_parser* parser)
cp_token *token = NULL;
cp_token *decl_spec_token_start = NULL;
cp_token *initializer_token_start = NULL;
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Recurse. */
cp_parser_member_declaration (parser);
/* Restore the old value of the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -28845,6 +29037,12 @@ cp_parser_member_declaration (cp_parser* parser)
return;
}
+ if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ {
+ cp_parser_consteval_block (parser, /*member_p=*/true);
+ return;
+ }
+
parser->colon_corrects_to_scope_p = false;
cp_omp_declare_simd_data odsd;
@@ -31910,13 +32108,16 @@ cp_parser_skip_attributes_opt (cp_parser *parser, size_t n)
present, and FALSE otherwise. *SAVED_PEDANTIC is set to the
current value of the PEDANTIC flag, regardless of whether or not
the `__extension__' keyword is present. The caller is responsible
- for restoring the value of the PEDANTIC flag. */
+ for restoring the value of the PEDANTIC flag. Similarly *SAVED_LONG_LONG
+ for warn_long_long flag. */
static bool
-cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
+cp_parser_extension_opt (cp_parser *parser, int *saved_pedantic,
+ int *saved_long_long)
{
/* Save the old value of the PEDANTIC flag. */
*saved_pedantic = pedantic;
+ *saved_long_long = warn_long_long;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION))
{
@@ -31925,6 +32126,8 @@ cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
/* We're not being pedantic while the `__extension__' keyword is
in effect. */
pedantic = 0;
+ /* And we don't want -Wlong-long warning. */
+ warn_long_long = 0;
return true;
}
@@ -33599,7 +33802,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags,
&& cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID)
{
auto_diagnostic_group d;
- if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING,
+ if (emit_diagnostic ((cxx_dialect >= cxx20
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
input_location, OPT_Wtemplate_id_cdtor,
"template-id not allowed for constructor in C++20"))
inform (input_location, "remove the %qs", "< >");
@@ -35640,15 +35845,15 @@ cp_parser_token_starts_function_definition_p (cp_token* token)
|| token->keyword == RID_RETURN);
}
-/* Returns TRUE iff the next token is the ":" or "{" beginning a class
+/* Returns TRUE iff the Nth token is the ":" or "{" beginning a class
definition. */
static bool
-cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
+cp_parser_nth_token_starts_class_definition_p (cp_parser *parser, size_t n)
{
cp_token *token;
- token = cp_lexer_peek_token (parser->lexer);
+ token = cp_lexer_peek_nth_token (parser->lexer, n);
return (token->type == CPP_OPEN_BRACE
|| (token->type == CPP_COLON
&& !parser->colon_doesnt_start_class_def_p));
@@ -52941,11 +53146,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok,
if (msg == NULL)
msg = _("<message unknown at compile time>");
}
+ const enum diagnostics::kind diag_kind = (severity_fatal
+ ? diagnostics::kind::error
+ : diagnostics::kind::warning);
if (msg)
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered: %s", msg);
else
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered");
return false;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 40ce987..acfeb81 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6952,14 +6952,22 @@ convert_nontype_argument_function (tree type, tree expr,
{
auto_diagnostic_group d;
location_t loc = cp_expr_loc_or_input_loc (expr);
- error_at (loc, "%qE is not a valid template argument for type %qT",
- expr, type);
- if (TYPE_PTR_P (type))
- inform (loc, "it must be the address of a function "
- "with external linkage");
+ tree c;
+ if (cxx_dialect >= cxx17
+ && (c = cxx_constant_value (fn),
+ c == error_mark_node))
+ ;
else
- inform (loc, "it must be the name of a function with "
- "external linkage");
+ {
+ error_at (loc, "%qE is not a valid template argument for "
+ "type %qT", expr, type);
+ if (TYPE_PTR_P (type))
+ inform (loc, "it must be the address of a function "
+ "with external linkage");
+ else
+ inform (loc, "it must be the name of a function with "
+ "external linkage");
+ }
}
return NULL_TREE;
}
@@ -7402,22 +7410,22 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
/* Null pointer values are OK in C++11. */;
else
{
- if (VAR_P (expr))
- {
- if (complain & tf_error)
- error ("%qD is not a valid template argument "
- "because %qD is a variable, not the address of "
- "a variable", expr, expr);
- return true;
- }
+ tree c;
+ if (!(complain & tf_error))
+ ;
+ else if (cxx_dialect >= cxx17
+ && (c = cxx_constant_value (expr),
+ c == error_mark_node))
+ ;
+ else if (VAR_P (expr))
+ error ("%qD is not a valid template argument "
+ "because %qD is a variable, not the address of "
+ "a variable", expr, expr);
else
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for %qT "
- "because it is not the address of a variable",
- expr, type);
- return true;
- }
+ error ("%qE is not a valid template argument for %qT "
+ "because it is not the address of a variable",
+ expr, type);
+ return true;
}
}
return false;
@@ -12699,7 +12707,17 @@ instantiate_class_template (tree type)
determine_visibility (TYPE_MAIN_DECL (type));
}
if (CLASS_TYPE_P (type))
- CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
+ {
+ CLASSTYPE_FINAL (type) = CLASSTYPE_FINAL (pattern);
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (type)
+ = CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (pattern);
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (type)
+ = CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (pattern);
+ CLASSTYPE_REPLACEABLE_BIT (type)
+ = CLASSTYPE_REPLACEABLE_BIT (pattern);
+ CLASSTYPE_REPLACEABLE_COMPUTED (type)
+ = CLASSTYPE_REPLACEABLE_COMPUTED (pattern);
+ }
pbinfo = TYPE_BINFO (pattern);
@@ -14906,6 +14924,9 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
argvec = NULL_TREE;
}
+ /* Make sure tsubst_decl substitutes all the parameters. */
+ cp_evaluated ev;
+
tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype)
: NULL_TREE);
tree ctx = closure ? closure : DECL_CONTEXT (t);
@@ -17976,9 +17997,7 @@ tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
return decl;
/* Handle OpenMP iterators. */
- if (TREE_CODE (decl) == TREE_LIST
- && TREE_PURPOSE (decl)
- && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC)
+ if (OMP_ITERATOR_DECL_P (decl))
{
tree ret;
if (iterator_cache[0] == TREE_PURPOSE (decl))
@@ -19582,7 +19601,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
finish_static_assert (condition, message,
STATIC_ASSERT_SOURCE_LOCATION (t),
- /*member_p=*/false, /*show_expr_p=*/true);
+ /*member_p=*/false, /*show_expr_p=*/true,
+ CONSTEVAL_BLOCK_P (t));
}
break;
@@ -20147,7 +20167,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:
@@ -20479,11 +20506,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
r = error_mark_node;
else
{
- /* The body of a lambda-expression is not a subexpression of the
- enclosing expression. Parms are to have DECL_CHAIN tsubsted,
- which would be skipped if cp_unevaluated_operand. */
- cp_evaluated ev;
-
/* Fix the type of 'this'.
For static and xobj member functions we use this to transport the
lambda's closure type. It appears that in the regular case the
@@ -20509,6 +20531,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Let finish_function set this. */
DECL_DECLARED_CONSTEXPR_P (fn) = false;
+ /* The body of a lambda-expression is not a subexpression of the
+ enclosing expression. */
+ cp_evaluated ev;
+
bool nested = cfun;
if (nested)
push_function_context ();
@@ -31199,14 +31225,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
/* Substitute the deduced arguments plus the rewritten template
parameters into f to get g. This covers the type, copyness,
guideness, and explicit-specifier. */
- tree g;
- {
- /* Parms are to have DECL_CHAIN tsubsted, which would be skipped
- if cp_unevaluated_operand. */
- cp_evaluated ev;
- g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain,
+ tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain,
/*use_spec_table=*/false);
- }
if (g == error_mark_node)
continue;
DECL_NAME (g) = name;
@@ -31636,7 +31656,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree outer_targs,
/* Be permissive with equivalent alias templates. */
tree u = get_underlying_template (tmpl);
auto_diagnostic_group d;
- diagnostic_t dk = (u == tmpl) ? DK_ERROR : DK_PEDWARN;
+ const enum diagnostics::kind dk = ((u == tmpl)
+ ? diagnostics::kind::error
+ : diagnostics::kind::pedwarn);
bool complained
= emit_diagnostic (dk, input_location, 0,
"alias template deduction only available "
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 28baf7b..be79b50 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2338,7 +2338,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string,
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. */
@@ -2397,7 +2398,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string,
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
bool constraint_parsed
= parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg);
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr);
/* If the operand is going to end up in memory, don't call
decay_conversion. */
if (constraint_parsed && !allows_reg && allows_mem)
@@ -3605,11 +3607,13 @@ finish_this_expr (void)
{
tree result = NULL_TREE;
- if (current_class_type && LAMBDA_TYPE_P (current_class_type))
+ if (current_class_ref && !LAMBDA_TYPE_P (TREE_TYPE (current_class_ref)))
+ result = current_class_ptr;
+ else if (current_class_type && LAMBDA_TYPE_P (current_class_type))
result = (lambda_expr_this_capture
(CLASSTYPE_LAMBDA_EXPR (current_class_type), /*add*/true));
- else if (current_class_ptr)
- result = current_class_ptr;
+ else
+ gcc_checking_assert (!current_class_ptr);
if (result)
/* The keyword 'this' is a prvalue expression. */
@@ -3739,6 +3743,11 @@ finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr expr,
if (!(complain & tf_warning))
return result;
+ /* These will never fold into a constant, so no need to check for
+ overflow for them. */
+ if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+ return result;
+
tree result_ovl = result;
tree expr_ovl = expr;
@@ -3983,9 +3992,15 @@ finish_compound_literal (tree type, tree compound_literal,
tree
finish_fname (tree id)
{
- tree decl;
-
- decl = fname_decl (input_location, C_RID_CODE (id), id);
+ tree decl = fname_decl (input_location, C_RID_CODE (id), id);
+ /* [expr.prim.lambda.closure]/16 "Unless the compound-statement is that
+ of a consteval-block-declaration, a variable __func__ is implicitly
+ defined...". We could be in a consteval block in a function, though,
+ and then we shouldn't warn. */
+ if (current_function_decl
+ && !current_nonlambda_function (/*only_skip_consteval_block_p=*/true))
+ pedwarn (input_location, 0, "%qD is not defined outside of function scope",
+ decl);
if (processing_template_decl && current_function_decl
&& decl != error_mark_node)
decl = DECL_NAME (decl);
@@ -6295,9 +6310,7 @@ handle_omp_array_sections (tree &c, enum c_omp_region_type ort)
tree *tp = &OMP_CLAUSE_DECL (c);
if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
|| OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY)
- && TREE_CODE (*tp) == TREE_LIST
- && TREE_PURPOSE (*tp)
- && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC)
+ && OMP_ITERATOR_DECL_P (*tp))
tp = &TREE_VALUE (*tp);
tree first = handle_omp_array_sections_1 (c, *tp, types,
maybe_zero_len, first_non_one,
@@ -8817,9 +8830,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
/* FALLTHRU */
case OMP_CLAUSE_AFFINITY:
t = OMP_CLAUSE_DECL (c);
- if (TREE_CODE (t) == TREE_LIST
- && TREE_PURPOSE (t)
- && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
+ if (OMP_ITERATOR_DECL_P (t))
{
if (TREE_PURPOSE (t) != last_iterators)
last_iterators_remove
@@ -12593,11 +12604,14 @@ cexpr_str::extract (location_t location, const char * & msg, int &len)
CONDITION and the message text MESSAGE. LOCATION is the location
of the static assertion in the source code. When MEMBER_P, this
static assertion is a member of a class. If SHOW_EXPR_P is true,
- print the condition (because it was instantiation-dependent). */
+ print the condition (because it was instantiation-dependent).
+ If CONSTEVAL_BLOCK_P is true, this static assertion represents
+ a consteval block. */
void
finish_static_assert (tree condition, tree message, location_t location,
- bool member_p, bool show_expr_p)
+ bool member_p, bool show_expr_p,
+ bool consteval_block_p/*=false*/)
{
tsubst_flags_t complain = tf_warning_or_error;
@@ -12625,6 +12639,7 @@ finish_static_assert (tree condition, tree message, location_t location,
STATIC_ASSERT_CONDITION (assertion) = orig_condition;
STATIC_ASSERT_MESSAGE (assertion) = cstr.message;
STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+ CONSTEVAL_BLOCK_P (assertion) = consteval_block_p;
if (member_p)
maybe_add_class_template_decl_list (current_class_type,
@@ -12636,6 +12651,13 @@ finish_static_assert (tree condition, tree message, location_t location,
return;
}
+ /* Evaluate the consteval { }. This must be done only once. */
+ if (consteval_block_p)
+ {
+ cxx_constant_value (condition);
+ return;
+ }
+
/* Fold the expression and convert it to a boolean value. */
condition = contextual_conv_bool (condition, complain);
condition = fold_non_dependent_expr (condition, complain,
@@ -13359,6 +13381,18 @@ object_type_p (const_tree type)
&& !VOID_TYPE_P (type));
}
+/* [defns.referenceable] True iff TYPE is a referenceable type. */
+
+static bool
+referenceable_type_p (const_tree type)
+{
+ return (TYPE_REF_P (type)
+ || object_type_p (type)
+ || (FUNC_OR_METHOD_TYPE_P (type)
+ && type_memfn_quals (type) == TYPE_UNQUALIFIED
+ && type_memfn_rqual (type) == REF_QUAL_NONE));
+}
+
/* Actually evaluates the trait. */
static bool
@@ -13528,6 +13562,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_NOTHROW_INVOCABLE:
return expr_noexcept_p (build_invoke (type1, type2, tf_none), tf_none);
+ case CPTK_IS_NOTHROW_RELOCATABLE:
+ if (trivially_relocatable_type_p (type1))
+ return true;
+ else
+ {
+ type1 = strip_array_types (type1);
+ if (!referenceable_type_p (type1))
+ return false;
+ tree arg = make_tree_vec (1);
+ TREE_VEC_ELT (arg, 0)
+ = cp_build_reference_type (type1, /*rval=*/true);
+ return (is_nothrow_xible (INIT_EXPR, type1, arg)
+ && is_nothrow_xible (BIT_NOT_EXPR, type1, NULL_TREE));
+ }
+
case CPTK_IS_OBJECT:
return object_type_p (type1);
@@ -13546,6 +13595,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_REFERENCE:
return type_code1 == REFERENCE_TYPE;
+ case CPTK_IS_REPLACEABLE:
+ return replaceable_type_p (type1);
+
case CPTK_IS_SAME:
return same_type_p (type1, type2);
@@ -13570,6 +13622,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
return is_trivially_xible (BIT_NOT_EXPR, type1, NULL_TREE);
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
+ return trivially_relocatable_type_p (type1);
+
case CPTK_IS_UNBOUNDED_ARRAY:
return array_of_unknown_bound_p (type1);
@@ -13653,7 +13708,8 @@ check_trait_type (tree type, int kind = 1)
type = complete_type (strip_array_types (type));
if (!COMPLETE_TYPE_P (type)
- && cxx_incomplete_type_diagnostic (NULL_TREE, type, DK_PERMERROR)
+ && cxx_incomplete_type_diagnostic (NULL_TREE, type,
+ diagnostics::kind::permerror)
&& !flag_permissive)
return false;
return true;
@@ -13700,18 +13756,6 @@ same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2)
(non_reference (to), non_reference (from))));
}
-/* [defns.referenceable] True iff TYPE is a referenceable type. */
-
-static bool
-referenceable_type_p (const_tree type)
-{
- return (TYPE_REF_P (type)
- || object_type_p (type)
- || (FUNC_OR_METHOD_TYPE_P (type)
- && (type_memfn_quals (type) == TYPE_UNQUALIFIED
- && type_memfn_rqual (type) == REF_QUAL_NONE)));
-}
-
/* Process a trait expression. */
tree
@@ -13760,8 +13804,11 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_LITERAL_TYPE:
case CPTK_IS_POD:
case CPTK_IS_STD_LAYOUT:
+ case CPTK_IS_REPLACEABLE:
+ case CPTK_IS_NOTHROW_RELOCATABLE:
case CPTK_IS_TRIVIAL:
case CPTK_IS_TRIVIALLY_COPYABLE:
+ case CPTK_IS_TRIVIALLY_RELOCATABLE:
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
if (!check_trait_type (type1, /* kind = */ 2))
return error_mark_node;
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 5863b68..d56d73f 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -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;
@@ -3695,6 +3696,58 @@ build_min_non_dep_op_overload (enum tree_code op,
int nargs, expected_nargs;
tree fn, call, obj = NULL_TREE;
+ releasing_vec args;
+ va_start (p, overload);
+
+ bool negated = false, rewritten = false, reversed = false;
+ if (cxx_dialect >= cxx20 && TREE_CODE (overload) == TREE_LIST)
+ {
+ /* Handle rebuilding a C++20 rewritten comparison operator expression,
+ e.g. !(x == y), y <=> x, (x <=> y) @ 0 etc, that resolved to a call
+ to a user-defined operator<=>/==. */
+ gcc_checking_assert (TREE_CODE_CLASS (op) == tcc_comparison
+ || op == SPACESHIP_EXPR);
+ int flags = TREE_INT_CST_LOW (TREE_PURPOSE (overload));
+ if (TREE_CODE (non_dep) == TRUTH_NOT_EXPR)
+ {
+ negated = true;
+ non_dep = TREE_OPERAND (non_dep, 0);
+ }
+ if (flags & LOOKUP_REWRITTEN)
+ rewritten = true;
+ if (flags & LOOKUP_REVERSED)
+ reversed = true;
+ if (rewritten
+ && DECL_OVERLOADED_OPERATOR_IS (TREE_VALUE (overload),
+ SPACESHIP_EXPR))
+ {
+ /* Handle (x <=> y) @ 0 and 0 @ (y <=> x) by recursing to first
+ rebuild the <=>. Note that both OVERLOAD and the provided arguments
+ in this case already correspond to the selected operator<=>. */
+
+ tree spaceship_non_dep = CALL_EXPR_ARG (non_dep, reversed ? 1 : 0);
+ gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR);
+ tree spaceship_op0 = va_arg (p, tree);
+ tree spaceship_op1 = va_arg (p, tree);
+ if (reversed)
+ std::swap (spaceship_op0, spaceship_op1);
+
+ /* Push the correct arguments for the operator OP expression, and
+ set OVERLOAD appropriately. */
+ tree op0 = build_min_non_dep_op_overload (SPACESHIP_EXPR,
+ spaceship_non_dep,
+ TREE_VALUE (overload),
+ spaceship_op0,
+ spaceship_op1);
+ tree op1 = CALL_EXPR_ARG (non_dep, reversed ? 0 : 1);
+ gcc_checking_assert (integer_zerop (op1));
+ vec_safe_push (args, op0);
+ vec_safe_push (args, op1);
+ overload = CALL_EXPR_FN (non_dep);
+ }
+ else
+ overload = TREE_VALUE (overload);
+ }
non_dep = extract_call_expr (non_dep);
nargs = call_expr_nargs (non_dep);
@@ -3715,32 +3768,40 @@ build_min_non_dep_op_overload (enum tree_code op,
expected_nargs += 1;
gcc_assert (nargs == expected_nargs);
- releasing_vec args;
- va_start (p, overload);
-
if (!DECL_OBJECT_MEMBER_FUNCTION_P (overload))
{
fn = overload;
- if (op == ARRAY_REF)
- obj = va_arg (p, tree);
- for (int i = 0; i < nargs; i++)
+ if (vec_safe_length (args) != 0)
+ /* The correct arguments were already pushed above. */
+ gcc_checking_assert (rewritten);
+ else
{
- tree arg = va_arg (p, tree);
- vec_safe_push (args, arg);
+ if (op == ARRAY_REF)
+ obj = va_arg (p, tree);
+ for (int i = 0; i < nargs; i++)
+ {
+ tree arg = va_arg (p, tree);
+ vec_safe_push (args, arg);
+ }
}
+ if (reversed)
+ std::swap ((*args)[0], (*args)[1]);
}
else
{
+ gcc_checking_assert (vec_safe_length (args) == 0);
tree object = va_arg (p, tree);
- tree binfo = TYPE_BINFO (TREE_TYPE (object));
- tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
- fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
- object, method, NULL_TREE);
for (int i = 0; i < nargs; i++)
{
tree arg = va_arg (p, tree);
vec_safe_push (args, arg);
}
+ if (reversed)
+ std::swap (object, (*args)[0]);
+ tree binfo = TYPE_BINFO (TREE_TYPE (object));
+ tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
+ fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
+ object, method, NULL_TREE);
}
va_end (p);
@@ -3752,6 +3813,8 @@ build_min_non_dep_op_overload (enum tree_code op,
CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
+ if (negated)
+ call = build_min (TRUTH_NOT_EXPR, boolean_type_node, call);
if (obj)
return keep_unused_object_arg (call, obj, overload);
return call;
@@ -4715,6 +4778,293 @@ trivial_type_p (const_tree t)
return scalarish_type_p (t);
}
+/* Returns 1 iff type T is a default-movable type, as defined in
+ [class.prop]. */
+
+static bool
+default_movable_type_p (tree t)
+{
+ if (!CLASS_TYPE_P (t) || !COMPLETE_TYPE_P (t))
+ return false;
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (user_provided_p (dtor) || DECL_DELETED_FN (dtor))
+ return false;
+
+ tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE;
+ tree copy_assign = NULL_TREE, move_assign = NULL_TREE;
+ if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+ move_ctor = lazily_declare_fn (sfk_move_constructor, t);
+ if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+ move_assign = lazily_declare_fn (sfk_move_assignment, t);
+ if (!move_ctor)
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_ctor = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_ctor = *iter;
+ break;
+ }
+ }
+ if (!move_assign)
+ for (ovl_iterator iter (get_class_binding_direct (t,
+ assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_assign = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_assign = *iter;
+ break;
+ }
+ }
+ if (!move_ctor)
+ {
+ if (CLASSTYPE_LAZY_COPY_CTOR (t))
+ copy_ctor = lazily_declare_fn (sfk_copy_constructor, t);
+ if (!copy_ctor)
+ return false;
+ if (user_provided_p (copy_ctor)
+ || DECL_DELETED_FN (copy_ctor)
+ || DECL_CONTEXT (copy_ctor) != t
+ || DECL_INHERITED_CTOR (copy_ctor))
+ return false;
+ }
+ else if (user_provided_p (move_ctor)
+ || DECL_DELETED_FN (move_ctor)
+ || DECL_CONTEXT (move_ctor) != t
+ || DECL_INHERITED_CTOR (move_ctor))
+ return false;
+ if (!move_assign)
+ {
+ if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
+ copy_assign = lazily_declare_fn (sfk_copy_assignment, t);
+ if (!copy_assign)
+ return false;
+ if (user_provided_p (copy_assign)
+ || DECL_DELETED_FN (copy_assign)
+ || DECL_CONTEXT (copy_assign) != t)
+ return false;
+ }
+ else if (user_provided_p (move_assign)
+ || DECL_DELETED_FN (move_assign)
+ || DECL_CONTEXT (move_assign) != t)
+ return false;
+ return true;
+}
+
+/* Returns 1 iff type T is a union with no user declared special member
+ functions. */
+
+static bool
+union_with_no_declared_special_member_fns (tree t)
+{
+ if (TREE_CODE (t) != UNION_TYPE)
+ return false;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL
+ && !DECL_ARTIFICIAL (*iter)
+ && (default_ctor_p (*iter) || copy_fn_p (*iter) || move_fn_p (*iter)))
+ return false;
+
+ for (ovl_iterator iter (get_class_binding_direct (t, assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL
+ && !DECL_ARTIFICIAL (*iter)
+ && (copy_fn_p (*iter) || move_fn_p (*iter)))
+ return false;
+
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (!DECL_ARTIFICIAL (dtor))
+ return false;
+
+ return true;
+}
+
+/* Returns 1 iff type T is a trivially relocatable type, as defined in
+ [basic.types.general] and [class.prop]. */
+
+bool
+trivially_relocatable_type_p (tree t)
+{
+ t = strip_array_types (t);
+
+ if (!CLASS_TYPE_P (t))
+ return scalarish_type_p (t);
+
+ t = TYPE_MAIN_VARIANT (t);
+ if (CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t))
+ return CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t);
+ if (!COMPLETE_TYPE_P (t))
+ return false;
+
+ if (!CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t)
+ && !union_with_no_declared_special_member_fns (t)
+ && !default_movable_type_p (t))
+ {
+ nontriv:
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) = 0;
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1;
+ return false;
+ }
+
+ if (CLASSTYPE_VBASECLASSES (t))
+ goto nontriv;
+
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (DECL_DELETED_FN (dtor))
+ goto nontriv;
+
+ tree binfo, base_binfo;
+ unsigned int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!trivially_relocatable_type_p (basetype))
+ goto nontriv;
+ }
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && !DECL_ARTIFICIAL (field)
+ && !DECL_UNNAMED_BIT_FIELD (field))
+ {
+ tree type = TREE_TYPE (field);
+ if (type == error_mark_node)
+ goto nontriv;
+ if (!TYPE_REF_P (type) && !trivially_relocatable_type_p (type))
+ goto nontriv;
+ }
+
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_BIT (t) = 1;
+ CLASSTYPE_TRIVIALLY_RELOCATABLE_COMPUTED (t) = 1;
+ return true;
+}
+
+/* Returns 1 iff type T is a replaceable type, as defined in [basic.types]
+ and [class]. */
+
+bool
+replaceable_type_p (tree t)
+{
+ t = strip_array_types (t);
+
+ if (cv_qualified_p (t))
+ return false;
+
+ if (!CLASS_TYPE_P (t))
+ return scalarish_type_p (t);
+
+ t = TYPE_MAIN_VARIANT (t);
+ if (CLASSTYPE_REPLACEABLE_COMPUTED (t))
+ return CLASSTYPE_REPLACEABLE_BIT (t);
+ if (!COMPLETE_TYPE_P (t))
+ return false;
+
+ if (!CLASSTYPE_REPLACEABLE_BIT (t)
+ && !union_with_no_declared_special_member_fns (t)
+ && !default_movable_type_p (t))
+ {
+ nonrepl:
+ CLASSTYPE_REPLACEABLE_BIT (t) = 0;
+ CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1;
+ return false;
+ }
+
+ if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+ lazily_declare_fn (sfk_destructor, t);
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t))
+ if (DECL_DELETED_FN (dtor))
+ goto nonrepl;
+
+ tree copy_ctor = NULL_TREE, move_ctor = NULL_TREE;
+ tree copy_assign = NULL_TREE, move_assign = NULL_TREE;
+ if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+ move_ctor = lazily_declare_fn (sfk_move_constructor, t);
+ if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+ move_assign = lazily_declare_fn (sfk_move_assignment, t);
+ if (!move_ctor)
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_ctor = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_ctor = *iter;
+ break;
+ }
+ }
+ if (!move_assign)
+ for (ovl_iterator iter (get_class_binding_direct (t,
+ assign_op_identifier));
+ iter; ++iter)
+ if (TREE_CODE (*iter) == FUNCTION_DECL)
+ {
+ if (copy_fn_p (*iter))
+ copy_assign = *iter;
+ else if (move_fn_p (*iter))
+ {
+ move_assign = *iter;
+ break;
+ }
+ }
+ if (!move_ctor)
+ {
+ if (CLASSTYPE_LAZY_COPY_CTOR (t))
+ copy_ctor = lazily_declare_fn (sfk_copy_constructor, t);
+ if (!copy_ctor || DECL_DELETED_FN (copy_ctor))
+ goto nonrepl;
+ }
+ else if (DECL_DELETED_FN (move_ctor))
+ goto nonrepl;
+ if (!move_assign)
+ {
+ if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
+ copy_assign = lazily_declare_fn (sfk_copy_assignment, t);
+ if (!copy_assign || DECL_DELETED_FN (copy_assign))
+ goto nonrepl;
+ }
+ else if (DECL_DELETED_FN (move_assign))
+ goto nonrepl;
+
+ tree binfo, base_binfo;
+ unsigned int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!replaceable_type_p (basetype))
+ goto nonrepl;
+ }
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && !DECL_ARTIFICIAL (field)
+ && !DECL_UNNAMED_BIT_FIELD (field))
+ {
+ tree type = TREE_TYPE (field);
+ if (type == error_mark_node)
+ goto nonrepl;
+ if (!replaceable_type_p (type))
+ goto nonrepl;
+ }
+
+ CLASSTYPE_REPLACEABLE_BIT (t) = 1;
+ CLASSTYPE_REPLACEABLE_COMPUTED (t) = 1;
+ return true;
+}
+
/* Returns 1 iff type T is a POD type, as defined in [basic.types]. */
bool
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 0bf5ae4..f592894 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -155,7 +155,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
else if (!COMPLETE_TYPE_P (type))
{
if (complain & tf_error)
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
note_failed_type_completion (type, complain);
return NULL_TREE;
}
@@ -618,7 +618,7 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
static void
composite_pointer_error (const op_location_t &location,
- diagnostic_t kind, tree t1, tree t2,
+ enum diagnostics::kind kind, tree t1, tree t2,
composite_pointer_operation operation)
{
switch (operation)
@@ -690,7 +690,7 @@ composite_pointer_type_r (const op_location_t &location,
else
{
if (complain & tf_error)
- composite_pointer_error (location, DK_PERMERROR,
+ composite_pointer_error (location, diagnostics::kind::permerror,
t1, t2, operation);
else
return error_mark_node;
@@ -716,7 +716,7 @@ composite_pointer_type_r (const op_location_t &location,
TYPE_PTRMEM_CLASS_TYPE (t2)))
{
if (complain & tf_error)
- composite_pointer_error (location, DK_PERMERROR,
+ composite_pointer_error (location, diagnostics::kind::permerror,
t1, t2, operation);
else
return error_mark_node;
@@ -851,7 +851,8 @@ composite_pointer_type (const op_location_t &location,
else
{
if (complain & tf_error)
- composite_pointer_error (location, DK_ERROR, t1, t2, operation);
+ composite_pointer_error (location, diagnostics::kind::error,
+ t1, t2, operation);
return error_mark_node;
}
}
@@ -4530,7 +4531,11 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
{
if (complain & tf_error)
{
- if (!flag_diagnostics_show_caret)
+ if (is_stub_object (original))
+ error_at (input_location,
+ "%qT cannot be used as a function",
+ TREE_TYPE (original));
+ else if (!flag_diagnostics_show_caret)
error_at (input_location,
"%qE cannot be used as a function", original);
else if (DECL_P (original))
@@ -4672,12 +4677,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
if (type == void_type_node)
{
if (complain & tf_error)
- {
- error_args_num (input_location, fndecl, /*too_many_p=*/true);
- return i;
- }
- else
- return -1;
+ error_args_num (input_location, fndecl, /*too_many_p=*/true);
+ return -1;
}
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
@@ -7680,7 +7681,18 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
if (val != 0)
goto return_build_unary_op;
- arg = mark_lvalue_use (arg);
+ tree stripped_arg;
+ stripped_arg = tree_strip_any_location_wrapper (arg);
+ if ((VAR_P (stripped_arg) || TREE_CODE (stripped_arg) == PARM_DECL)
+ && !DECL_READ_P (stripped_arg)
+ && (VAR_P (stripped_arg) ? warn_unused_but_set_variable
+ : warn_unused_but_set_parameter) > 1)
+ {
+ arg = mark_lvalue_use (arg);
+ DECL_READ_P (stripped_arg) = 0;
+ }
+ else
+ arg = mark_lvalue_use (arg);
/* Increment or decrement the real part of the value,
and don't change the imaginary part. */
@@ -9796,7 +9808,22 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
{
auto_diagnostic_group d;
rhs = stabilize_expr (rhs, &init);
+ bool clear_decl_read = false;
+ tree stripped_lhs = tree_strip_any_location_wrapper (lhs);
+ if ((VAR_P (stripped_lhs) || TREE_CODE (stripped_lhs) == PARM_DECL)
+ && !DECL_READ_P (stripped_lhs)
+ && (VAR_P (stripped_lhs) ? warn_unused_but_set_variable
+ : warn_unused_but_set_parameter) > 2
+ && !CLASS_TYPE_P (TREE_TYPE (lhs))
+ && !CLASS_TYPE_P (TREE_TYPE (rhs)))
+ {
+ mark_exp_read (rhs);
+ if (!DECL_READ_P (stripped_lhs))
+ clear_decl_read = true;
+ }
newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
+ if (clear_decl_read)
+ DECL_READ_P (stripped_lhs) = 0;
if (newrhs == error_mark_node)
{
if (complain & tf_error)
@@ -10779,7 +10806,9 @@ maybe_warn_about_returning_address_of_local (tree retval, location_t loc)
{
if (TYPE_REF_P (valtype))
/* P2748 made this an error in C++26. */
- emit_diagnostic (cxx_dialect >= cxx26 ? DK_PERMERROR : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::permerror
+ : diagnostics::kind::warning),
loc, OPT_Wreturn_local_addr,
"returning reference to temporary");
else if (TYPE_PTR_P (valtype))
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 45edd18..faaf1df 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -119,6 +119,11 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring)
G_("increment of read-only reference %qD"),
G_("decrement of read-only reference %qD"),
TREE_OPERAND (arg, 0));
+ else if (is_stub_object (arg))
+ {
+ gcc_assert (errstring == lv_assign);
+ error_at (loc, "assignment to read-only type %qT", TREE_TYPE (arg));
+ }
else
readonly_error (loc, arg, errstring);
}
@@ -290,11 +295,12 @@ cxx_incomplete_type_inform (const_tree type)
/* Print an error message for invalid use of an incomplete type.
VALUE is the expression that was used (or 0 if that isn't known)
and TYPE is the type that was invalid. DIAG_KIND indicates the
- type of diagnostic (see diagnostic.def). */
+ type of diagnostic (see diagnostics/kinds.def). */
bool
cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
- const_tree type, diagnostic_t diag_kind)
+ const_tree type,
+ enum diagnostics::kind diag_kind)
{
bool is_decl = false, complained = false;
@@ -440,7 +446,7 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
void
cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type)
{
- cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (loc, value, type, diagnostics::kind::error);
}
@@ -2627,7 +2633,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
bool ok;
tree core = spec;
bool is_ptr;
- diagnostic_t diag_type = DK_UNSPECIFIED; /* none */
+ enum diagnostics::kind diag_type = diagnostics::kind::unspecified; /* none */
if (spec == error_mark_node)
return list;
@@ -2659,7 +2665,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
and calls. So just give a pedwarn at this point; we will give an
error later if we hit one of those two cases. */
if (!COMPLETE_TYPE_P (complete_type (core)))
- diag_type = DK_PEDWARN; /* pedwarn */
+ diag_type = diagnostics::kind::pedwarn; /* pedwarn */
}
if (ok)
@@ -2673,9 +2679,9 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
list = tree_cons (NULL_TREE, spec, list);
}
else
- diag_type = DK_ERROR; /* error */
+ diag_type = diagnostics::kind::error; /* error */
- if (diag_type != DK_UNSPECIFIED
+ if (diag_type != diagnostics::kind::unspecified
&& (complain & tf_warning_or_error))
cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type);