aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog1555
-rw-r--r--gcc/cp/Make-lang.in4
-rw-r--r--gcc/cp/call.cc89
-rw-r--r--gcc/cp/class.cc162
-rw-r--r--gcc/cp/constexpr.cc2272
-rw-r--r--gcc/cp/constraint.cc76
-rw-r--r--gcc/cp/contracts.cc9
-rw-r--r--gcc/cp/coroutines.cc781
-rw-r--r--gcc/cp/coroutines.h7
-rw-r--r--gcc/cp/cp-gimplify.cc61
-rw-r--r--gcc/cp/cp-objcp-common.cc2
-rw-r--r--gcc/cp/cp-objcp-common.h9
-rw-r--r--gcc/cp/cp-trait.def4
-rw-r--r--gcc/cp/cp-tree.h151
-rw-r--r--gcc/cp/cxx-pretty-print.cc3
-rw-r--r--gcc/cp/decl.cc170
-rw-r--r--gcc/cp/decl2.cc63
-rw-r--r--gcc/cp/error.cc155
-rw-r--r--gcc/cp/except.cc16
-rw-r--r--gcc/cp/init.cc17
-rw-r--r--gcc/cp/lambda.cc102
-rw-r--r--gcc/cp/lex.cc22
-rw-r--r--gcc/cp/mangle.cc28
-rw-r--r--gcc/cp/method.cc64
-rw-r--r--gcc/cp/module.cc725
-rw-r--r--gcc/cp/name-lookup.cc126
-rw-r--r--gcc/cp/name-lookup.h5
-rw-r--r--gcc/cp/optimize.cc4
-rw-r--r--gcc/cp/parser.cc688
-rw-r--r--gcc/cp/pt.cc463
-rw-r--r--gcc/cp/rtti.cc16
-rw-r--r--gcc/cp/semantics.cc290
-rw-r--r--gcc/cp/std-name-hint.h974
-rw-r--r--gcc/cp/tree.cc1
-rw-r--r--gcc/cp/typeck.cc94
35 files changed, 7211 insertions, 1997 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index fe8aa4b..2944f22 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,1558 @@
+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
+ * decl.cc (duplicate_decls): Change logic to not always exclude FMV
+ annotated functions in cases of return type non-ambiguation.
+
+2025-07-07 Jason Merrill <jason@redhat.com>
+
+ PR c++/120917
+ * parser.cc (cp_parser_simple_type_specifier): Attach
+ auto in targ in parameter to -Wabbreviated-auto-in-template-arg.
+ (cp_parser_placeholder_type_specifier): Diagnose constrained auto in
+ template arg.
+
+2025-07-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84009
+ * parser.cc (cp_parser_decomposition_declaration): Pedwarn
+ on thread_local, __thread or static in decl_specifiers for
+ for-range-declaration.
+ (cp_parser_init_declarator): Likewise, and also for extern
+ or register.
+
+2025-07-04 Jason Merrill <jason@redhat.com>
+
+ PR c++/120575
+ PR c++/116064
+ * parser.cc (cp_parser_abort_tentative_parse): Check seen_error
+ instead of errorcount.
+
+2025-07-03 Jason Merrill <jason@redhat.com>
+
+ PR c++/120716
+ * lambda.cc (finish_lambda_function): Pass cur_stmt_list to
+ prune_lambda_captures.
+
+2025-07-03 Jason Merrill <jason@redhat.com>
+
+ PR c++/120748
+ * lambda.cc (lambda_expr_this_capture): Don't return a FIELD_DECL.
+ * parser.cc (cp_parser_primary_expression): Ignore THIS_FORBIDDEN
+ if cp_unevaluated_operand.
+
+2025-07-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120940
+ * typeck.cc (cp_build_array_ref): Fix a pasto.
+
+2025-07-03 Jason Merrill <jason@redhat.com>
+
+ PR c++/120684
+ PR c++/118856
+ * constexpr.cc (cxx_eval_constant_expression) [TARGET_EXPR]: Clear
+ the value first if is_complex.
+
+2025-07-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120471
+ * typeck.cc (cp_build_array_ref) <case COND_EXPR>: If idx is not
+ INTEGER_CST, don't optimize the case (but cp_default_conversion on
+ array early if it has ARRAY_TYPE) or use
+ SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0> as new op0 depending
+ on flag_strong_eval_order and whether op1 and op2 are arrays with
+ invariant address or tree invariant pointers. Formatting fixes.
+
+2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * module.cc (trees_out::walking_bit_field_unit): New flag.
+ (trees_out::trees_out): Initialize it.
+ (trees_out::core_vals): Set it.
+ (trees_out::get_merge_kind): Use it, move previous ad-hoc check
+ into assertion.
+
+2025-06-28 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120644
+ * decl.cc (cp_finish_decl): Also propagate type to partial
+ templates.
+ * module.cc (trees_out::decl_value): Add assertion that the
+ TREE_TYPE of a streamed template decl matches its inner.
+ (trees_in::is_matching_decl): Clarify function return type
+ deduction should only occur for non-TEMPLATE_DECL.
+ * pt.cc (template_for_substitution): Handle partial specs.
+
+2025-06-27 Marek Polacek <polacek@redhat.com>
+
+ PR c++/120756
+ * pt.cc (resolve_nondeduced_context): Pass complain to mark_used.
+
+2025-06-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120777
+ * constexpr.cc: Implement C++26 P3533R2 - constexpr virtual
+ inheritance.
+ (is_valid_constexpr_fn): Don't reject constexpr cdtors in classes
+ with virtual bases for C++26, adjust error wording.
+ (cxx_bind_parameters_in_call): Add ORIG_FUN argument, add
+ values for __in_chrg and __vtt_parm arguments when needed.
+ (cxx_eval_dynamic_cast_fn): Adjust function comment, HINT -1
+ should be possible. For C++26 if obj is cast from POINTER_PLUS_EXPR,
+ attempt to use cxx_fold_indirect_ref to simplify it and if successful,
+ build ADDR_EXPR of that.
+ (cxx_eval_call_expression): Add orig_fun variable, set it to
+ fun before looking through clones, pass it to
+ cxx_bind_parameters_in_call.
+ (reduced_constant_expression_p): Add SZ argument, pass DECL_SIZE
+ of FIELD_DECL e.index to recursive calls and don't return false
+ if SZ is non-NULL and there are unfilled fields with bit position
+ at or above SZ.
+ (cxx_fold_indirect_ref_1): Handle reading of vtables using
+ ptrdiff_t dynamic type instead of some pointer type. Set el_sz
+ to DECL_SIZE_UNIT value rather than TYPE_SIZE_UNIT of
+ DECL_FIELD_IS_BASE fields in classes with virtual bases.
+ (cxx_fold_indirect_ref): In canonicalize_obj_off lambda look
+ through COMPONENT_REFs with DECL_FIELD_IS_BASE in classes with
+ virtual bases and adjust off correspondingly. Remove assertion that
+ off is integer_zerop, pass tree_to_uhwi (off) instead of 0 to the
+ cxx_fold_indirect_ref_1 call.
+ * cp-tree.h (publicly_virtually_derived_p): Declare.
+ (reduced_constant_expression_p): Add another tree argument defaulted
+ to NULL_TREE.
+ * method.cc (synthesized_method_walk): Don't clear *constexpr_p
+ if there are virtual bases for C++26.
+ * class.cc (build_base_path): Compute fixed_type_p and
+ virtual_access before checks for build_simple_base_path instead of
+ after that and conditional cp_build_addr_expr. Use build_simple_path
+ if !virtual_access even when v_binfo is non-NULL.
+ (layout_virtual_bases): For build_base_field calls use
+ access_public_node rather than access_private_node if
+ publicly_virtually_derived_p.
+ (build_vtbl_initializer): Revert 2018-09-18 and 2018-12-11 changes.
+ (publicly_virtually_derived_p): New function.
+
+2025-06-27 Jason Merrill <jason@redhat.com>
+
+ * class.cc (fixed_type_or_null): Handle class-type CALL_EXPR.
+ * parser.cc (cp_parser_binary_expression): Fix decltype_p handling.
+
+2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/98735
+ PR c++/118904
+ * cp-gimplify.cc (source_location_id): Remove.
+ (fold_builtin_source_location): Use generate_internal_label.
+ * module.cc (enum tree_tag): Add 'tt_internal_id' enumerator.
+ (trees_out::tree_value): Adjust assertion, write definitions
+ of uncontexted VAR_DECLs.
+ (trees_in::tree_value): Read variable definitions.
+ (trees_out::tree_node): Write internal labels, adjust assert.
+ (trees_in::tree_node): Read internal labels.
+
+2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120040
+ * constexpr.cc (cxx_eval_constant_expression): Handle TYPE_NAME
+ now being a TYPE_DECL rather than just an IDENTIFIER_NODE.
+ * init.cc (build_new_constexpr_heap_type): Build a TYPE_DECL for
+ the returned type; mark the type as artificial.
+ * module.cc (trees_out::type_node): Add some assertions.
+
+2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/98735
+ PR c++/120040
+ * module.cc (trees_out::tree_value): Write TYPE_DECLs.
+ (trees_in::tree_value): Read TYPE_DECLs.
+ (trees_out::tree_node): Support uncontexted TYPE_DECLs, and
+ ensure that all parts of a by-value decl are marked for
+ streaming.
+ (trees_out::get_merge_kind): Treat members of uncontexted types
+ as always unique.
+
+2025-06-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * decl.cc (grokfndecl): Add explanation of how to attach to
+ global module.
+
+2025-06-26 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc (cxx_initialize_diagnostics): Use
+ diagnostic_context::set_adjust_diagnostic_info_callback.
+
+2025-06-26 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-trait.def: Implement C++26 P2830R10 - Constexpr Type Ordering.
+ (TYPE_ORDER): New.
+ * method.cc (type_order_value): Define.
+ * cp-tree.h (type_order_value): Declare.
+ * semantics.cc (trait_expr_value): Use gcc_unreachable also
+ for CPTK_TYPE_ORDER, adjust comment.
+ (finish_trait_expr): Handle CPTK_TYPE_ORDER.
+ * constraint.cc (diagnose_trait_expr): Likewise.
+
+2025-06-25 Martin Jambor <mjambor@suse.cz>
+
+ * coroutines.h (class cp_coroutine_transform): Remove member
+ orig_fn_body.
+
+2025-06-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120773
+ * decl.cc (grokfndecl): Implement C++26 P3618R0 - Allow attaching
+ main to the global module. Only pedwarn for current_lang_name
+ other than lang_name_cplusplus and adjust pedwarn wording.
+
+2025-06-23 Tobias Burnus <tburnus@baylibre.com>
+
+ * parser.cc (OACC_WAIT_CLAUSE_MASK): Ass if clause.
+
+2025-06-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/115908
+ PR c++/118074
+ PR c++/95615
+ * coroutines.cc (coro_frame_refcount_id): New.
+ (coro_init_identifiers): Initialise coro_frame_refcount_id.
+ (build_actor_fn): Set up initial_await_resume_called. Handle
+ decrementing of the frame reference count. Return directly to
+ the caller if that is non-zero.
+ (cp_coroutine_transform::wrap_original_function_body): Use a
+ conditional eh-only cleanup around the initial await expression
+ to release the body use on exception before initial await
+ resume.
+ (cp_coroutine_transform::build_ramp_function): Wrap the called
+ body in a cleanup that releases a use of the frame when we
+ return to the ramp. Implement frame, promise and argument copy
+ destruction via conditional cleanups when the frame use count
+ is zero.
+
+2025-06-17 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (struct coroutine_info): Update comments.
+ (struct coro_aw_data): Remove self_handle and add in
+ information to create the handle in lowering.
+ (expand_one_await_expression): Build a temporary coroutine
+ handle.
+ (build_actor_fn): Remove reference to the frame copy of the
+ coroutine handle.
+ (cp_coroutine_transform::wrap_original_function_body): Remove
+ reference to the frame copy of the coroutine handle.
+
+2025-06-17 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (analyze_expression_awaits): Elide assume
+ attributes containing await expressions, since these have
+ side effects. Emit a diagnostic that this has been done.
+
+2025-06-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/120678
+ * cp-trait.def (IS_TRIVIALLY_DESTRUCTIBLE): Fix nargs.
+
+2025-06-17 Jason Merrill <jason@redhat.com>
+
+ * module.cc (module_state::write_diagnostic_classification): New.
+ (module_state::write_begin): Call it.
+ (module_state::read_diagnostic_classification): New.
+ (module_state::read_initial): Call it.
+ (dk_string, dump_dc_change): New.
+
+2025-06-17 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (finish_co_await_expr): Do not allow in an
+ unevaluated context.
+ (finish_co_yield_expr): Likewise.
+
+2025-06-17 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/120273
+ * coroutines.cc
+ (cp_coroutine_transform::wrap_original_function_body): Use
+ function start and end locations when synthesizing code.
+ (cp_coroutine_transform::cp_coroutine_transform): Set the
+ function end location.
+
+2025-06-16 Jason Merrill <jason@redhat.com>
+
+ * constraint.cc (failed_completions_map): New.
+ (note_failed_type_completion): Rename from
+ note_failed_type_completion_for_satisfaction. Add
+ -Wsfinae-incomplete handling.
+ (failed_completion_location): New.
+ * class.cc (finish_struct_1): Add -Wsfinae-incomplete warning.
+ * decl.cc (require_deduced_type): Adjust.
+ (finish_function): Add -Wsfinae-incomplete warning.
+ * typeck.cc (complete_type_or_maybe_complain): Adjust.
+ (cxx_sizeof_or_alignof_type): Call note_failed_type_completion.
+ * pt.cc (dependent_template_arg_p): No longer static.
+ * cp-tree.h: Adjust.
+
+2025-06-16 yxj-github-437 <2457369732@qq.com>
+
+ * parser.cc (cp_parser_asm_operand_list): Check for unexpanded
+ parameter packs.
+
+2025-06-14 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (build_co_await): Identify diagnostics
+ for initial and final await expressions.
+ (cp_coroutine_transform::wrap_original_function_body): Do
+ not handle initial and final await expressions here ...
+ (cp_coroutine_transform::apply_transforms): ... handle them
+ here and avoid duplicate diagnostics.
+ * coroutines.h: Declare inital and final await expressions
+ in the transform class. Save the function closing brace
+ location.
+
+2025-06-13 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/116775
+ * coroutines.cc (analyze_expression_awaits): When we see
+ a builtin_constant_p call, and that contains one or more
+ await expressions, then replace the call with its result
+ and discard the unevaluated operand.
+
+2025-06-13 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (build_actor_fn): Set can_throw.
+
+2025-06-12 Alfie Richards <alfie.richards@arm.com>
+
+ * decl.cc (maybe_version_functions): Change record_function_versions
+ call to add_function_version.
+
+2025-06-12 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-tree.h (union lang_type::maybe_objc_info): New type.
+ (struct lang_type): Use union maybe_objc_info info member
+ instead of tree objc_info.
+ * lex.cc (copy_lang_type): Use sizeof (struct lang_type)
+ just for ObjC++ and otherwise offsetof (struct lang_type, info).
+ (maybe_add_lang_type_raw): Likewise.
+ (cxx_make_type): Formatting fix.
+
+2025-06-09 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/120495
+ PR c++/115605
+ * pt.cc (lookup_template_class): Honour provided namespace contexts
+ when looking up class templates.
+
+2025-06-06 Jason Merrill <jason@redhat.com>
+
+ PR c++/120555
+ * decl2.cc (fn_being_defined, fn_template_being_defined): New.
+ (mark_used): Check fn_template_being_defined.
+
+2025-06-05 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/120224
+ * pt.cc (tsubst_function_decl): Return error_mark_node if
+ substituting into the formal parameter list failed.
+ (tsubst_decl) <case PARM_DECL>: Return error_mark_node
+ upon TREE_TYPE substitution failure, when in a SFINAE
+ context. Return error_mark_node upon DECL_CHAIN substitution
+ failure.
+
+2025-06-05 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/118340
+ * constexpr.cc (maybe_constant_value): First try looking up each
+ operand in the cv_cache and reusing the result.
+
+2025-06-05 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (analyze_fn_parms): Move from free function..
+ (cp_coroutine_transform::analyze_fn_parms):... to method.
+ (cp_coroutine_transform::apply_transforms): Adjust call to
+ analyze_fn_parms.
+ * coroutines.h: Declare analyze_fn_parms.
+
+2025-06-05 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (expand_one_await_expression): Set the
+ initial_await_resume_called flag here.
+ (build_actor_fn): Populate the frame accessor for the
+ initial_await_resume_called flag.
+ (cp_coroutine_transform::wrap_original_function_body): Do
+ not modify the initial_await expression to include the
+ initial_await_resume_called flag here.
+
+2025-06-04 Jason Merrill <jason@redhat.com>
+
+ PR c++/120502
+ * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation
+ before genericize.
+ * constexpr.cc (cxx_eval_store_expression): Add comment.
+
+2025-06-03 Jason Merrill <jason@redhat.com>
+
+ * name-lookup.h (operator|, operator|=): Define for WMB_Flags.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * method.cc (destructible_expr): Fix refs and arrays of unknown
+ bound.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/120506
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Always check
+ CONSTRUCTOR_NO_CLEARING.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (build_actor_fn): Remove an unused
+ label, guard the frame deallocation correctly, use
+ simpler APIs to build if and return statements.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/118903
+ * constexpr.cc (potential_constant_expression_1): Emit
+ an error when co_await et. al. are used in constexpr
+ contexts.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ * error.cc (dump_expr): Add co_await, co_yield and co_return.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * method.cc (destructible_expr): Handle non-classes.
+ (constructible_expr): Check for abstract class here...
+ (is_xible_helper): ...not here.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]:
+ Add cp_unevaluated.
+
+2025-06-02 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * cp-tree.h (maybe_convert_cond): Declare.
+ * parser.cc (cp_parser_omp_context_selector): Call
+ maybe_convert_cond and fold_build_cleanup_point_expr on the
+ expression for OMP_TRAIT_PROPERTY_BOOL_EXPR.
+ * pt.cc (tsubst_omp_context_selector): Likewise.
+ * semantics.cc (maybe_convert_cond): Remove static declaration.
+
+2025-05-30 Jason Merrill <jason@redhat.com>
+
+ PR c++/113563
+ * lambda.cc (lambda_capture_field_type): Handle 'this' normally.
+ (build_capture_proxy): Special-case 'this' by-ref capture more.
+ (nonlambda_method_basetype): Look through xobj lambdas.
+
+2025-05-30 Julian Brown <julian@codesourcery.com>
+ Tobias Burnus <tburnus@baylibre.com>
+
+ * constexpr.cc (reduced_constant_expression_p): Add OMP_DECLARE_MAPPER
+ case.
+ (cxx_eval_constant_expression, potential_constant_expression_1):
+ Likewise.
+ * cp-gimplify.cc (cxx_omp_finish_mapper_clauses): New function.
+ * cp-objcp-common.h (LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES,
+ LANG_HOOKS_OMP_MAPPER_LOOKUP, LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE,
+ LANG_HOOKS_OMP_MAP_ARRAY_SECTION): Define langhooks.
+ * cp-tree.h (lang_decl_base): Add omp_declare_mapper_p field. Recount
+ spare bits comment.
+ (DECL_OMP_DECLARE_MAPPER_P): New macro.
+ (omp_mapper_id): Add prototype.
+ (cp_check_omp_declare_mapper): Add prototype.
+ (omp_instantiate_mappers): Add prototype.
+ (cxx_omp_finish_mapper_clauses): Add prototype.
+ (cxx_omp_mapper_lookup): Add prototype.
+ (cxx_omp_extract_mapper_directive): Add prototype.
+ (cxx_omp_map_array_section): Add prototype.
+ * decl.cc (check_initializer): Add OpenMP declare mapper support.
+ (cp_finish_decl): Set DECL_INITIAL for OpenMP declare mapper var decls
+ as appropriate.
+ * decl2.cc (mark_used): Instantiate OpenMP "declare mapper" magic var
+ decls.
+ * error.cc (dump_omp_declare_mapper): New function.
+ (dump_simple_decl): Use above.
+ * parser.cc (cp_parser_omp_clause_map): Add KIND parameter. Support
+ "mapper" modifier.
+ (cp_parser_omp_all_clauses): Add KIND argument to
+ cp_parser_omp_clause_map call.
+ (cp_parser_omp_target): Call omp_instantiate_mappers before
+ finish_omp_clauses.
+ (cp_parser_omp_declare_mapper): New function.
+ (cp_parser_omp_declare): Add "declare mapper" support.
+ * pt.cc (tsubst_decl): Adjust name of "declare mapper" magic var decls
+ once we know their type.
+ (tsubst_omp_clauses): Call omp_instantiate_mappers before
+ finish_omp_clauses, for target regions.
+ (tsubst_expr): Support OMP_DECLARE_MAPPER nodes.
+ (instantiate_decl): Instantiate initialiser (i.e definition) for OpenMP
+ declare mappers.
+ * semantics.cc (gimplify.h): Include.
+ (omp_mapper_id, omp_mapper_lookup, omp_extract_mapper_directive,
+ cxx_omp_map_array_section, cp_check_omp_declare_mapper): New functions.
+ (finish_omp_clauses): Delete GOMP_MAP_PUSH_MAPPER_NAME and
+ GOMP_MAP_POP_MAPPER_NAME artificial clauses.
+ (omp_target_walk_data): Add MAPPERS field.
+ (finish_omp_target_clauses_r): Scan for uses of struct/union/class type
+ variables.
+ (finish_omp_target_clauses): Create artificial mapper binding clauses
+ for used structs/unions/classes in offload region.
+
+2025-05-29 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc (cxx_format_postprocessor::clone): Update to use
+ unique_ptr.
+ (cxx_dump_pretty_printer::cxx_dump_pretty_printer): Likewise.
+ (cxx_initialize_diagnostics): Likewise.
+
+2025-05-29 Jason Merrill <jason@redhat.com>
+
+ PR c++/113563
+ * lambda.cc (build_capture_proxy): Check pointerness of the
+ member, not the proxy type.
+ (lambda_expr_this_capture): Don't assume current_class_ref.
+ (nonlambda_method_basetype): Likewise.
+ * semantics.cc (finish_non_static_data_member): Don't assume
+ TREE_TYPE (object) is set.
+ (finish_this_expr): Check current_class_type for lambda,
+ not current_class_ref.
+
+2025-05-29 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/109283
+ * coroutines.cc (find_any_await): Only save the statement
+ pointer if the caller passes a place for it.
+ (flatten_await_stmt): When checking that ternary expressions
+ have been handled, also check that they contain a co_await.
+
+2025-05-29 Jason Merrill <jason@redhat.com>
+
+ * decl.cc (start_decl): Also set invalid_constexpr
+ for maybe_constexpr_fn.
+ * parser.cc (cp_parser_jump_statement): Likewise.
+ * constexpr.cc (potential_constant_expression_1): Ignore
+ goto to an artificial label.
+
+2025-05-29 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * parser.cc (cp_parser_omp_metadirective): Do not call
+ cp_parser_skip_to_end_of_block_or_statement after an error.
+
+2025-05-29 Sandra Loosemore <sloosemore@baylibre.com>
+
+ PR c/120180
+ * parser.cc (cp_parser_omp_metadirective): Only consume the
+ token if it is the expected close paren.
+
+2025-05-29 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (analyze_fn_parms): No longer
+ create a parameter copy guard var.
+ * coroutines.h (struct param_info): Remove the
+ entry for the parameter copy destructor guard.
+
+2025-05-29 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/120453
+ * cp-tree.h (DECL_RAMP_P): New.
+ * typeck.cc (check_return_expr): Use DECL_RAMP_P instead
+ of DECL_RAMP_FN.
+
+2025-05-29 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * cp-trait.def (IS_DESTRUCTIBLE, IS_NOTHROW_DESTRUCTIBLE)
+ (IS_TRIVIALLY_DESTRUCTIBLE): New.
+ * constraint.cc (diagnose_trait_expr): Explain them.
+ * method.cc (destructible_expr): New.
+ (is_xible_helper): Use it.
+ * semantics.cc (finish_trait_expr): Handle new traits.
+ (trait_expr_value): Likewise. Complain about asking
+ whether a deleted dtor is trivial.
+
+2025-05-28 Jason Merrill <jason@redhat.com>
+
+ * module.cc (module_state::write_namespaces): Write
+ using-directives.
+ (module_state::read_namespaces): And read them.
+ * name-lookup.cc (add_using_namespace): Add overload. Build a
+ USING_DECL for modules.
+ (name_lookup::search_usings, name_lookup::queue_usings)
+ (using_directives_contain_std_p): Strip the USING_DECL.
+ * name-lookup.h: Declare it.
+ * parser.cc (cp_parser_import_declaration): Set MK_EXPORTING
+ for export import.
+
+2025-05-27 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (cp_coroutine_transform::build_ramp_function):
+ Replace TRUTH_AND_EXPR with TRUTH_ANDIF_EXPR in three places.
+
+2025-05-26 Tobias Burnus <tburnus@baylibre.com>
+
+ PR c++/120413
+ * semantics.cc (finish_omp_target_clauses_r): Handle
+ BIND_EXPR with empty BIND_EXPR_BLOCK.
+
+2025-05-26 Jason Merrill <jason@redhat.com>
+
+ * cp-tree.h: Declare tinst_dump_id.
+ * cp-objcp-common.cc (cp_register_dumps): Set it.
+ * pt.cc (push_tinst_level_loc): Dump it.
+ (reopen_tinst_level): Here too.
+ (tinst_complete_p): New.
+ (instantiate_pending_templates): Don't reopen_tinst_level for
+ already-complete instantiations.
+
+2025-05-26 Jason Merrill <jason@redhat.com>
+
+ * cp-tree.h (class cxx_dump_pretty_printer): New.
+ * error.cc (cxx_dump_pretty_printer): Ctor/dtor definitions.
+
+2025-05-25 Jason Merrill <jason@redhat.com>
+
+ * error.cc (dump_template_bindings): Correct skipping of
+ redundant bindings.
+
+2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120363
+ * decl2.cc (get_tls_init_fn): Set context as global_namespace.
+ (get_tls_wrapper_fn): Likewise.
+
+2025-05-23 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120414
+ * module.cc (trees_in::tree_node): Allow reading a USING_DECL
+ when streaming tt_data_member.
+
+2025-05-23 Jason Merrill <jason@redhat.com>
+
+ * mangle.cc (mangle_decl_string): Don't push_tinst_level.
+
+2025-05-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/120935
+ * cp-gimplify.cc (cp_fold): Check always_inline.
+
+2025-05-21 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc
+ (cp_coroutine_transform::build_ramp_function): Replace ramp
+ cleanup try-catch block with eh-only cleanup statements.
+
+2025-05-21 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc
+ (cp_coroutine_transform::build_ramp_function): Use
+ decltype(auto) to determine the type of the temporary
+ get_return_object.
+
+2025-05-21 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/119916
+ * coroutines.cc
+ (cp_coroutine_transform::wrap_original_function_body): Do not
+ initialise initial_await_resume_called here...
+ (cp_coroutine_transform::build_ramp_function): ... but here.
+ When the coroutine is not void, initialize a GRO object from
+ promise.get_return_object(). Use this as the argument to the
+ return expression. Use a regular cleanup for the GRO, since
+ it is ramp-local.
+
+2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120349
+ * module.cc (trees_out::core_bools): Always mark vtables as
+ DECL_EXTERNAL.
+
+2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120013
+ * module.cc (trees_in::install_entity): Handle re-registering
+ the inner TYPE_DECL of a partial specialisation.
+
+2025-05-20 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120350
+ * rtti.cc (get_tinfo_decl_direct): Mark TREE_ADDRESSABLE.
+
+2025-05-16 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ * cp-gimplify.cc (cp_fold): Do the conversion unconditionally, even for same-type cases.
+
+2025-05-16 Iain Sandoe <iain@sandoe.co.uk>
+
+ * typeck.cc (check_return_expr): Suppress conversions for NVRO
+ in coroutine ramp functions.
+
+2025-05-16 Iain Sandoe <iain@sandoe.co.uk>
+
+ * decl.cc (poplevel): Set BLOCK_OUTER_CURLY_BRACE_P on the
+ body block for functions with no subblocks.
+
+2025-05-16 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * module.cc (importer_interface): Adjust flags.
+ (get_importer_interface): Rename flags.
+ (trees_out::core_bools): Clean up special casing.
+ (trees_out::write_function_def): Rename flag.
+
+2025-05-15 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/120161
+ * pt.cc (unify) <case RECORD_TYPE>: When comparing specializations
+ of a non-primary template, still perform a type comparison.
+
+2025-05-15 Jason Merrill <jason@redhat.com>
+
+ * module.cc (trees_out::lang_decl_bools): Stream implicit_constexpr.
+ (trees_in::lang_decl_bools): Likewise.
+ (trees_in::is_matching_decl): Check it.
+
+2025-05-15 Jason Merrill <jason@redhat.com>
+
+ PR c++/99599
+ * pt.cc (conversion_may_instantiate_p): Make sure
+ classes are complete.
+
+2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ * cp-gimplify.cc (cp_fold): Remove a remnant comment.
+
+2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120125
+ * module.cc (trees_out::write_function_def): Only set
+ DECL_NOT_REALLY_EXTERN if the importer might need to emit it.
+ * optimize.cc (maybe_thunk_body): Don't assume 'fn' has a cgraph
+ node created.
+
+2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119864
+ * decl2.cc (start_objects): Only use module initialized for
+ host.
+ (c_parse_final_cleanups): Don't always create an OMP offload
+ init function in modules.
+
+2025-05-14 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * name-lookup.cc (lookup_imported_hidden_friend): Add back
+ lazy_load_pendings with comment.
+
+2025-05-14 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ * cp-gimplify.cc (cp_fold): Add to_underlying.
+
+2025-05-14 Owen Avery <powerboat9.gamer@gmail.com>
+ Jason Merrill <jason@redhat.com>
+
+ * method.cc (synthesized_method_walk): Check whether
+ -Wvirtual-move-assign is enabled at the location of a base
+ class's move assignment operator.
+
+2025-05-12 Jason Merrill <jason@redhat.com>
+
+ PR c++/120012
+ * class.cc (check_non_pod_aggregate): Check is_empty_class.
+
+2025-05-10 Jason Merrill <jason@redhat.com>
+
+ PR c++/120204
+ * pt.cc (tsubst_baselink): Always error if lookup fails.
+
+2025-05-09 Jason Merrill <jason@redhat.com>
+
+ * decl2.cc (determine_visibility): Ignore args for friend templates.
+
+2025-05-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/99599
+ PR c++/120185
+ * class.cc (type_has_converting_constructor): Handle null parm.
+ * pt.cc (fn_type_unification): Skip early non-dep checking if
+ no concepts.
+
+2025-05-08 Jason Merrill <jason@redhat.com>
+
+ PR c++/99599
+ * cp-tree.h (type_has_converting_constructor): Declare.
+ * class.cc (type_has_converting_constructor): New.
+ * pt.cc (conversion_may_instantiate_p): Don't check completeness.
+
+2025-05-05 Simon Martin <simon@nasilyan.com>
+
+ * cp-tree.h (parsing_default_capturing_generic_lambda_in_template):
+ Remove obsolete prototype.
+
+2025-05-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/115207
+ * decl.cc (cp_finish_decl): Call layout_decl after CTAD.
+
+2025-05-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/120012
+ * cp-tree.h (struct lang_type): Add non_aggregate_pod.
+ (CLASSTYPE_NON_AGGREGATE_POD): New.
+ * class.cc (check_bases_and_members): Set it.
+ (check_non_pod_aggregate): Diagnose it.
+
+2025-05-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117827
+ * init.cc (build_vec_init): Push to *cleanup_flags clearing of rval
+ instead of setting of iterator to maxindex.
+
+2025-05-01 Patrick Palka <ppalka@redhat.com>
+
+ * constexpr.cc (explain_invalid_constexpr_fn): In the
+ DECL_CONSTRUCTOR_P branch pass the non-genericized body to
+ require_potential_constant_expression.
+
+2025-05-01 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119034
+ PR c++/68942
+ * pt.cc (tsubst_expr) <case CALL_EXPR>: Revert PR68942 fix.
+ * semantics.cc (finish_call_expr): Ensure the callee of an
+ ADL-enabled call is wrapped in an OVERLOAD.
+
+2025-05-01 Jason Merrill <jason@redhat.com>
+
+ * Make-lang.in: Don't pass the full path to gperf.
+ * std-name-hint.h: Regenerate.
+
+2025-05-01 Jason Merrill <jason@redhat.com>
+
+ PR c++/119162
+ * constexpr.cc (find_deleted_heap_var): Remove.
+ (cxx_eval_call_expression): Don't call it. Don't set TREE_STATIC on
+ heap vars.
+ (cxx_eval_outermost_constant_expr): Don't mess with varpool.
+
+2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120023
+ * module.cc (depset::hash::find_dependencies): Also call
+ add_deduction_guides when walking one.
+
+2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119938
+ * pt.cc (get_template_parm_object): When !check_init, add assert
+ that expr really is constant and mark decl as such.
+
+2025-04-30 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119551
+ PR c++/119996
+ * module.cc (depset::hash::make_dependency): Also mark inline
+ variables referencing TU-local values as exposures here.
+ (depset::hash::finalize_dependencies): Add error message for
+ inline variables.
+
+2025-04-30 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119981
+ PR c++/119378
+ * pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Substitute
+ into template parameter list first. When substituting the
+ context, only set processing_template_decl if there's more
+ than one level of introduced template parameters.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.cc: Include "analyzer/analyzer-language.h".
+ (ana::cp_translation_unit): New class.
+ (cp_parser_translation_unit): Add call to
+ ana::on_finish_translation_unit.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * cxx-pretty-print.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+ * error.cc: Likewise.
+ * name-lookup.cc: Likewise.
+ * parser.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * name-lookup.cc: Include "make-unique.h".
+ (namespace_hints::convert_candidates_to_name_hint): Use
+ ::make_unique rather than "new" when making
+ show_candidate_location and suggest_alternatives.
+ (namespace_hints::maybe_decorate_with_limit): Likewise when making
+ namespace_limit_reached.
+ (suggest_alternatives_for_1): Likewise when making
+ suggest_missing_option.
+ (maybe_suggest_missing_std_header): Likewise when making
+ missing_std_header.
+ (macro_use_before_def::maybe_make): Use std::unique_ptr.
+ (macro_use_before_def::macro_use_before_def): Make public.
+ (lookup_name_fuzzy): Use ::make_unique rather than "new" when
+ making suggest_missing_header.
+ * parser.cc: Include "make-unique.h".
+ (cp_parser_error_1): Use ::make_unique rather than "new" when
+ making suggest_missing_header.
+
+2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119939
+ * module.cc (trees_out::lang_decl_vals): Also stream
+ lang->u.fn.context when DECL_UNIQUE_FRIEND_P.
+ (trees_in::lang_decl_vals): Likewise.
+
+2025-04-27 H.J. Lu <hjl.tools@gmail.com>
+
+ PR middle-end/112877
+ * call.cc (type_passed_as): Remove the
+ targetm.calls.promote_prototypes call.
+ (convert_for_arg_passing): Likewise.
+ * typeck.cc (cxx_safe_arg_type_equiv_p): Likewise.
+
+2025-04-25 Jason Merrill <jason@redhat.com>
+
+ PR c++/119764
+ PR c++/87185
+ * lambda.cc (insert_capture_proxy): Handle noexcept lambda.
+ (prune_lambda_captures): Likewise, in ABI v21.
+
+2025-04-25 Jason Merrill <jason@redhat.com>
+
+ * cp-tree.h (struct tinst_level): Add had_errors bit.
+ * pt.cc (push_tinst_level_loc): Clear it.
+ (pop_tinst_level): Set it.
+ (reopen_tinst_level): Check it.
+ (instantiate_pending_templates): Call limit_bad_template_recursion.
+
+2025-04-24 Jason Merrill <jason@redhat.com>
+
+ PR c++/116954
+ * contracts.cc (remove_contract_attributes): Return early if
+ not enabled.
+
+2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * name-lookup.cc (lookup_imported_hidden_friend): Remove
+ unnecessary lazy_load_pendings.
+
+2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119863
+ * name-lookup.cc (get_mergeable_namespace_binding): Remove
+ no-longer-used function.
+ (lookup_imported_hidden_friend): Also look for hidden imported
+ decls in an attached decl's module.
+
+2025-04-21 Jason Merrill <jason@redhat.com>
+
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Move
+ verify_constant later.
+
+2025-04-21 Jason Merrill <jason@redhat.com>
+
+ PR c++/118775
+ * constexpr.cc (cxx_eval_call_expression): Add assert.
+ (fold_to_constant): Handle processing_template_decl.
+ * init.cc (build_new_1): Use fold_to_constant.
+
+2025-04-21 Jason Merrill <jason@redhat.com>
+
+ PR c++/99456
+ * constexpr.cc (cxx_eval_constant_expression): Check strict
+ instead of manifestly_const_eval.
+ (maybe_constant_init_1): Be strict for static constexpr vars.
+
+2025-04-19 Jason Merrill <jason@redhat.com>
+
+ * coroutines.cc (coro_build_expr_stmt)
+ (coro_build_cvt_void_expr_stmt): Remove.
+ (build_actor_fn): Use finish_expr_stmt.
+ * semantics.cc (finish_expr_stmt): Avoid wrapping statement in
+ EXPR_STMT.
+ (finish_stmt_expr_expr): Add comment.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * constexpr.cc (is_valid_constexpr_fn): Improve diagnostic.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Give both
+ expression and allocation location in allocated storage diagnostics.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * name-lookup.cc (name_lookup::preserve_state): Fix reserve call.
+ * rtti.cc (get_tinfo_desc): Use vec_safe_grow_cleared.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * semantics.cc (finish_type_pack_element): Add more info
+ to diagnostics.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * decl.cc (cp_make_fname_decl): Prevent silent failure.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ * lex.cc (unqualified_name_lookup_error): Handle 'requires' better.
+
+2025-04-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/113360
+ * cp-tree.h (struct language_function): Add erroneous bit.
+ * constexpr.cc (explain_invalid_constexpr_fn): Return if set.
+ (cxx_eval_call_expression): Quiet if set.
+ * parser.cc (cp_parser_function_definition_after_declarator)
+ * pt.cc (instantiate_body): Set it.
+
+2025-04-16 Jason Merrill <jason@redhat.com>
+
+ PR c++/114772
+ PR c++/101180
+ * pt.cc (apply_late_template_attributes): Also override
+ target_option_current_node.
+
+2025-04-16 Jason Merrill <jason@redhat.com>
+
+ PR c++/116954
+ * contracts.cc (remove_contract_attributes): Preserve flags
+ on the attribute list.
+
+2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119755
+ * lambda.cc (prune_lambda_captures): Remove pruned capture from
+ function's BLOCK_VARS and BIND_EXPR_VARS.
+
+2025-04-15 Jason Merrill <jason@redhat.com>
+
+ PR c++/111075
+ * constexpr.cc (cxx_eval_call_expression): Allow trivial
+ call from a thunk.
+
+2025-04-15 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119807
+ PR c++/112288
+ * pt.cc (tsubst_friend_function): Skip remapping an
+ existing specialization if it doesn't match the shape of
+ the new friend definition.
+
+2025-04-15 Jason Merrill <jason@redhat.com>
+
+ PR c++/113835
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Bail out early
+ for std::vector(N).
+
+2025-04-14 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/99214
+ * constraint.cc (satisfy_declaration_constraints): Pass the
+ original ARGS to push_tinst_level.
+
+2025-04-13 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/115639
+ * constexpr.cc (struct constexpr_call): Add NSDMIs to each
+ field. Replace 'result' data member with 3-element 'results'
+ array and a 'result' accessor function. Remove
+ 'manifestly_const_eval' data member.
+ (constexpr_call_hasher::equal): Adjust after constexpr_call
+ layout change.
+ (cxx_eval_call_expression): Likewise. Define some local
+ variables closer to their first use. Use unknown_type_node
+ instead of NULL_TREE as the "in progress" result. After
+ successully evaluating a call with mce_unknown, also cache the
+ result in the corresponding mce_true and mce_false slots.
+
+2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * module.cc (trees_in::is_matching_decl): Don't check for
+ mismatches when importing a DECL_MAYBE_DELETED function over one
+ that's already finished.
+
+2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * module.cc (trees_in::is_matching_decl): Add custom errors for
+ different kinds of mismatches.
+
+2025-04-12 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/116416
+ * constexpr.cc (maybe_constant_init_1): Generalize type of
+ of manifestly_const_eval parameter from bool to mce_value.
+ (maybe_constant_init): Define 3-parameter version taking a
+ manifestly_const_eval instead of bool parameter.
+ (cxx_constant_init): Adjust.
+ * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false
+ to maybe_constant_init during prvalue folding if ff_mce_false is
+ set.
+ * cp-tree.h (maybe_constant_init): Declare new overload.
+
+2025-04-11 Jason Merrill <jason@redhat.com>
+
+ PR c++/114970
+ * cp-gimplify.cc (cp_build_init_expr_for_ctor): Suppress warnings on
+ return_this COMPOUND_EXPR.
+
+2025-04-10 Jason Merrill <jason@redhat.com>
+
+ PR c++/119345
+ * pt.cc (add_extra_args): Also register a specialization
+ of the captured variable.
+
+2025-04-10 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119687
+ * pt.cc (alias_ctad_tweaks): Use lkp_range / lkp_iterator
+ instead of ovl_iterator.
+
+2025-04-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR translation/119684
+ * error.cc (cp_print_error_function): Use G_ instead of _ for
+ pp_printf arguments.
+ (function_category): Use G_ instead of _.
+ (print_instantiation_full_context): Use G_ instead of _ in pp_verbatim
+ arguments.
+ (print_location): Likewise.
+ (print_instantiation_partial_context): Likewise.
+ (maybe_print_constexpr_context): Likewise.
+ (print_constrained_decl_info): Use G_() around pp_verbatim argument.
+ (print_concept_check_info): Likewise.
+ (print_constraint_context_head): Likewise.
+ (print_requires_expression_info): Likewise. Merge separate pp_verbatim
+ "in requirements " and "with " into one with conditional messages.
+
+2025-04-10 Jason Merrill <jason@redhat.com>
+
+ PR c++/119175
+ * mangle.cc (decl_mangling_context): Look through lambda type.
+
+2025-04-09 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119574
+ * pt.cc (add_extra_args): Remove checking assert.
+
+2025-04-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/118698
+ * constraint.cc (struct norm_info): Add tf_partial.
+ * pt.cc (any_template_parm_r): Handle LAMBDA_EXPR_EXTRA_ARGS.
+
+2025-04-08 Jason Merrill <jason@redhat.com>
+
+ PR c++/117530
+ * pt.cc (instantiate_template): Check retrieve_specialization after
+ tsubst.
+
+2025-04-07 Jason Merrill <jason@redhat.com>
+
+ PR c++/119652
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Also don't add a
+ TARGET_EXPR around AGGR_INIT_EXPR.
+
+2025-04-06 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/118626
+ * pt.cc (maybe_dependent_member_ref): Restrict TYPENAME_TYPE
+ shortcut to non-typedef TYPE_DECL.
+
+2025-04-06 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/118626
+ * pt.cc (maybe_dependent_member_ref): Substitute and return the
+ stripped type if we decided to not rewrite it directly.
+
+2025-04-05 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/118249
+ * constexpr.cc (potential_constant_expression_1)
+ <case INDIRECT_REF>: Remove obsolete *this handling.
+
+2025-04-05 Jason Merrill <jason@redhat.com>
+
+ PR c++/118629
+ * name-lookup.cc (pushdecl_outermost_localscope): Look for an
+ sk_block.
+
+2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119564
+ * decl.cc (cp_tree_node_structure): Add TU_LOCAL_ENTITY; fix
+ formatting.
+
+2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119608
+ * module.cc (trees_out::decl_node): Maybe require by-value
+ walking not just when streaming.
+
+2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119462
+ * module.cc (trees_in::is_matching_decl): Propagate exception
+ spec and constexpr to DECL_MAYBE_DELETED; clear if appropriate.
+
+2025-04-04 Jason Merrill <jason@redhat.com>
+
+ PR c++/99546
+ PR c++/113925
+ PR c++/106976
+ PR c++/109961
+ PR c++/117336
+ * lambda.cc (build_lambda_object): Handle fake
+ requires-expr processing_template_decl.
+ * parser.cc (cp_parser_lambda_expression): Likewise.
+
+2025-04-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/117849
+ * semantics.cc (finish_id_expression_1): Allow use of constraint
+ variable outside an unevaluated context.
+
+2025-04-03 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119387
+ * constexpr.cc (p2280_active_p): New.
+ (cxx_eval_constant_expression) <case VAR_DECL>: Use it to
+ restrict P2280 relaxations.
+ <case PARM_DECL>: Likewise.
+
+2025-04-03 Jason Merrill <jason@redhat.com>
+
+ * module.cc (module_state::read_cluster)
+ (post_load_processing): Clear DECL_EXTERNAL if DECL_COMDAT.
+
+2025-04-03 Jason Merrill <jason@redhat.com>
+
+ * call.cc (add_candidates): Re-lookup ne_fns if we move into
+ another namespace.
+
+2025-04-03 Andrew Pinski <quic_apinski@quicinc.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119563
+ * call.cc (build_list_conv): Fix a typo in loop gathering
+ summary information from subsubconvs.
+
+2025-04-02 Sandra Loosemore <sloosemore@baylibre.com>
+
+ PR middle-end/118965
+ * parser.cc (c_parser_omp_clause_init_modifiers): Adjust
+ error message.
+ (cp_parser_omp_clause_init): Remove code for recognizing clauses
+ without modifiers. Diagnose missing target/targetsync modifier.
+ (cp_finish_omp_declare_variant): Diagnose missing target/targetsync
+ modifier.
+
+2025-04-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119551
+ * module.cc (trees_out::write_var_def): Only ignore non-inline
+ variable initializers.
+
+2025-04-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * parser.cc (cp_parser_diagnose_invalid_type_name): Replace
+ fmodules-ts with fmodules.
+ (cp_parser_template_declaration): Likewise.
+
+2025-04-01 Marek Polacek <polacek@redhat.com>
+
+ PR c++/119383
+ * call.cc (build_over_call): Use force_lvalue to ensure op= returns
+ an lvalue.
+ * cp-tree.h (force_lvalue): Declare.
+ * cvt.cc (force_lvalue): New.
+ * typeck.cc (cp_build_indirect_ref_1): Revert r15-8011.
+
2025-03-31 Jason Merrill <jason@redhat.com>
PR c++/119401
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 25143c8..dae3c68 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -168,8 +168,8 @@ $(srcdir)/cp/std-name-hint.h: $(srcdir)/cp/std-name-hint.gperf
else
$(srcdir)/cp/std-name-hint.h: | $(srcdir)/cp/std-name-hint.gperf
endif
- gperf -o -C -E -k '1,2,7,11,$$' -D -N find -L C++ \
- $(srcdir)/cp/std-name-hint.gperf --output-file $(srcdir)/cp/std-name-hint.h
+ cd $(srcdir)/cp; gperf -o -C -E -k '1,2,7,11,$$' -D -N find -L C++ \
+ std-name-hint.gperf --output-file std-name-hint.h
# The std-name-hint.gperf file itself is generated from a general
# C++ API description.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index b1469cb..2629625 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -917,7 +917,7 @@ build_list_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
t->rank = cr_exact;
for (j = 0; j < (unsigned) RAW_DATA_LENGTH (val); ++j)
{
- sub = subsubconvs[i];
+ sub = subsubconvs[j];
if (sub->rank > t->rank)
t->rank = sub->rank;
if (sub->user_conv_p)
@@ -1723,6 +1723,56 @@ involves_qualification_conversion_p (tree to, tree from)
return false;
}
+/* Return true if HANDLER is a match for exception object with EXCEPT_TYPE as
+ per [except.handle]/3. */
+
+bool
+handler_match_for_exception_type (tree handler, tree except_type)
+{
+ tree handler_type = HANDLER_TYPE (handler);
+ if (handler_type == NULL_TREE)
+ return true; /* ... */
+ if (same_type_ignoring_top_level_qualifiers_p (handler_type, except_type))
+ return true;
+ if (CLASS_TYPE_P (except_type) && CLASS_TYPE_P (handler_type))
+ {
+ base_kind b_kind;
+ tree binfo = lookup_base (except_type, handler_type, ba_check, &b_kind,
+ tf_none);
+ if (binfo && binfo != error_mark_node)
+ return true;
+ }
+ if (TYPE_PTR_P (handler_type) || TYPE_PTRDATAMEM_P (handler_type))
+ {
+ if (TREE_CODE (except_type) == NULLPTR_TYPE)
+ return true;
+ if ((TYPE_PTR_P (handler_type) && TYPE_PTR_P (except_type))
+ || (TYPE_PTRDATAMEM_P (handler_type)
+ && TYPE_PTRDATAMEM_P (except_type)))
+ {
+ conversion *conv
+ = standard_conversion (handler_type, except_type, NULL_TREE,
+ /*c_cast_p=*/false, 0, tf_none);
+ if (conv && !conv->bad_p)
+ {
+ for (conversion *t = conv; t; t = next_conversion (t))
+ switch (t->kind)
+ {
+ case ck_ptr:
+ case ck_fnptr:
+ case ck_qual:
+ case ck_identity:
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* A reference of the indicated TYPE is being bound directly to the
expression represented by the implicit conversion sequence CONV.
Return a conversion sequence for this binding. */
@@ -6673,6 +6723,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
bool check_list_ctor = false;
bool check_converting = false;
unification_kind_t strict;
+ tree ne_context = NULL_TREE;
tree ne_fns = NULL_TREE;
if (!fns)
@@ -6719,6 +6770,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
tree ne_name = ovl_op_identifier (false, NE_EXPR);
if (DECL_CLASS_SCOPE_P (fn))
{
+ ne_context = DECL_CONTEXT (fn);
ne_fns = lookup_fnfields (TREE_TYPE ((*args)[0]), ne_name,
1, tf_none);
if (ne_fns == error_mark_node || ne_fns == NULL_TREE)
@@ -6728,8 +6780,9 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
}
else
{
- tree context = decl_namespace_context (fn);
- ne_fns = lookup_qualified_name (context, ne_name, LOOK_want::NORMAL,
+ ne_context = decl_namespace_context (fn);
+ ne_fns = lookup_qualified_name (ne_context, ne_name,
+ LOOK_want::NORMAL,
/*complain*/false);
if (ne_fns == error_mark_node
|| !is_overloaded_fn (ne_fns))
@@ -6828,8 +6881,26 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
/* When considering reversed operator==, if there's a corresponding
operator!= in the same scope, it's not a rewrite target. */
- if (ne_fns)
+ if (ne_context)
{
+ if (TREE_CODE (ne_context) == NAMESPACE_DECL)
+ {
+ /* With argument-dependent lookup, fns can span multiple
+ namespaces; make sure we look in the fn's namespace for a
+ corresponding operator!=. */
+ tree fn_ns = decl_namespace_context (fn);
+ if (fn_ns != ne_context)
+ {
+ ne_context = fn_ns;
+ tree ne_name = ovl_op_identifier (false, NE_EXPR);
+ ne_fns = lookup_qualified_name (ne_context, ne_name,
+ LOOK_want::NORMAL,
+ /*complain*/false);
+ if (ne_fns == error_mark_node
+ || !is_overloaded_fn (ne_fns))
+ ne_fns = NULL_TREE;
+ }
+ }
bool found = false;
for (lkp_iterator ne (ne_fns); !found && ne; ++ne)
if (0 && !ne.using_p ()
@@ -9686,11 +9757,6 @@ type_passed_as (tree type)
/* Pass classes with copy ctors by invisible reference. */
if (TREE_ADDRESSABLE (type))
type = build_reference_type (type);
- else if (targetm.calls.promote_prototypes (NULL_TREE)
- && INTEGRAL_TYPE_P (type)
- && COMPLETE_TYPE_P (type)
- && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
- type = integer_type_node;
return type;
}
@@ -9726,11 +9792,6 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
/* Pass classes with copy ctors by invisible reference. */
else if (TREE_ADDRESSABLE (type))
val = build1 (ADDR_EXPR, build_reference_type (type), val);
- else if (targetm.calls.promote_prototypes (NULL_TREE)
- && INTEGRAL_TYPE_P (type)
- && COMPLETE_TYPE_P (type)
- && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
- val = cp_perform_integral_promotions (val, complain);
if (complain & tf_warning)
maybe_warn_parm_abi (type, cp_expr_loc_or_input_loc (val));
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 2b694b9..151ee2b 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -347,9 +347,18 @@ build_base_path (enum tree_code code,
|| processing_template_decl
|| in_template_context);
+ fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
+
+ /* Do we need to look in the vtable for the real offset? */
+ virtual_access = (v_binfo && fixed_type_p <= 0);
+
/* For a non-pointer simple base reference, express it as a COMPONENT_REF
without taking its address (and so causing lambda capture, 91933). */
- if (code == PLUS_EXPR && !v_binfo && !want_pointer && !has_empty && !uneval)
+ if (code == PLUS_EXPR
+ && !want_pointer
+ && !has_empty
+ && !uneval
+ && !virtual_access)
return build_simple_base_path (expr, binfo);
if (!want_pointer)
@@ -362,7 +371,6 @@ build_base_path (enum tree_code code,
expr = mark_rvalue_use (expr);
offset = BINFO_OFFSET (binfo);
- fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
target_type = code == PLUS_EXPR ? BINFO_TYPE (binfo) : BINFO_TYPE (d_binfo);
/* TARGET_TYPE has been extracted from BINFO, and, is therefore always
cv-unqualified. Extract the cv-qualifiers from EXPR so that the
@@ -371,9 +379,6 @@ build_base_path (enum tree_code code,
(target_type, cp_type_quals (TREE_TYPE (TREE_TYPE (expr))));
ptr_target_type = build_pointer_type (target_type);
- /* Do we need to look in the vtable for the real offset? */
- virtual_access = (v_binfo && fixed_type_p <= 0);
-
/* Don't bother with the calculations inside sizeof; they'll ICE if the
source type is incomplete and the pointer value doesn't matter. In a
template (even in instantiate_non_dependent_expr), we don't have vtables
@@ -5724,6 +5729,50 @@ type_has_user_provided_constructor (tree t)
return false;
}
+/* Returns true iff class T has a constructor that accepts a single argument
+ and does not have a single parameter of type reference to T.
+
+ This does not exclude explicit constructors because they are still
+ considered for conversions within { } even though choosing one is
+ ill-formed. */
+
+bool
+type_has_converting_constructor (tree t)
+{
+ if (!CLASS_TYPE_P (t))
+ return false;
+
+ if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+ return false;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ {
+ tree fn = *iter;
+ tree parm = FUNCTION_FIRST_USER_PARMTYPE (fn);
+ if (parm == NULL_TREE)
+ /* Varargs. */
+ return true;
+ if (parm == void_list_node
+ || !sufficient_parms_p (TREE_CHAIN (parm)))
+ /* Can't accept a single argument, so won't be considered for
+ conversion. */
+ continue;
+ if (TREE_CODE (fn) == TEMPLATE_DECL
+ || TREE_CHAIN (parm) != void_list_node)
+ /* Not a simple single parameter. */
+ return true;
+ if (TYPE_MAIN_VARIANT (non_reference (TREE_VALUE (parm)))
+ != DECL_CONTEXT (fn))
+ /* The single parameter has the wrong type. */
+ return true;
+ if (get_constraints (fn))
+ /* Constrained. */
+ return true;
+ }
+
+ return false;
+}
+
/* Returns true iff class T has a user-provided or explicit constructor. */
bool
@@ -6413,9 +6462,7 @@ check_bases_and_members (tree t)
Again, other conditions for being an aggregate are checked
elsewhere. */
CLASSTYPE_NON_AGGREGATE (t)
- |= ((cxx_dialect < cxx20
- ? type_has_user_provided_or_explicit_constructor (t)
- : TYPE_HAS_USER_CONSTRUCTOR (t))
+ |= (type_has_user_provided_or_explicit_constructor (t)
|| TYPE_POLYMORPHIC_P (t));
/* This is the C++98/03 definition of POD; it changed in C++0x, but we
retain the old definition internally for ABI reasons. */
@@ -6437,6 +6484,20 @@ check_bases_and_members (tree t)
CLASSTYPE_NON_LAYOUT_POD_P (t) = true;
}
+ /* P1008: Prohibit aggregates with user-declared constructors. */
+ if (cxx_dialect >= cxx20 && TYPE_HAS_USER_CONSTRUCTOR (t))
+ {
+ CLASSTYPE_NON_AGGREGATE (t) = true;
+ if (!CLASSTYPE_NON_LAYOUT_POD_P (t))
+ {
+ /* c++/120012: The C++20 aggregate change affected layout. */
+ if (!abi_version_at_least (21))
+ CLASSTYPE_NON_LAYOUT_POD_P (t) = true;
+ if (abi_version_crosses (21))
+ CLASSTYPE_NON_AGGREGATE_POD (t) = true;
+ }
+ }
+
/* If the only explicitly declared default constructor is user-provided,
set TYPE_HAS_COMPLEX_DFLT. */
if (!TYPE_HAS_COMPLEX_DFLT (t)
@@ -6698,9 +6759,11 @@ layout_virtual_bases (record_layout_info rli, splay_tree offsets)
{
/* This virtual base is not a primary base of any class in the
hierarchy, so we have to add space for it. */
- next_field = build_base_field (rli, vbase,
- access_private_node,
- offsets, next_field);
+ tree access = access_private_node;
+ if (publicly_virtually_derived_p (BINFO_TYPE (vbase), t))
+ access = access_public_node;
+ next_field = build_base_field (rli, vbase, access, offsets,
+ next_field);
}
}
}
@@ -6809,7 +6872,8 @@ end_of_class (tree t, eoc_mode mode)
static void
check_non_pod_aggregate (tree field)
{
- if (!abi_version_crosses (17) || cxx_dialect < cxx14)
+ if ((!abi_version_crosses (17) || cxx_dialect < cxx14)
+ && (!abi_version_crosses (21) || cxx_dialect < cxx20))
return;
if (TREE_CODE (field) != FIELD_DECL
|| (!DECL_FIELD_IS_BASE (field)
@@ -6822,7 +6886,10 @@ check_non_pod_aggregate (tree field)
tree type = TREE_TYPE (field);
if (TYPE_IDENTIFIER (type) == as_base_identifier)
type = TYPE_CONTEXT (type);
- if (!CLASS_TYPE_P (type) || !CLASSTYPE_NON_POD_AGGREGATE (type))
+ if (!CLASS_TYPE_P (type)
+ || is_empty_class (type)
+ || (!CLASSTYPE_NON_POD_AGGREGATE (type)
+ && !CLASSTYPE_NON_AGGREGATE_POD (type)))
return;
tree size = end_of_class (type, (DECL_FIELD_IS_BASE (field)
? eoc_nvsize : eoc_nv_or_dsize));
@@ -6831,13 +6898,31 @@ check_non_pod_aggregate (tree field)
{
location_t loc = DECL_SOURCE_LOCATION (next);
if (DECL_FIELD_IS_BASE (next))
- warning_at (loc, OPT_Wabi,"offset of %qT base class for "
- "%<-std=c++14%> and up changes in "
- "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next));
+ {
+ if (abi_version_crosses (17)
+ && CLASSTYPE_NON_POD_AGGREGATE (type))
+ warning_at (loc, OPT_Wabi,"offset of %qT base class for "
+ "%<-std=c++14%> and up changes in "
+ "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next));
+ else if (abi_version_crosses (21)
+ && CLASSTYPE_NON_AGGREGATE_POD (type))
+ warning_at (loc, OPT_Wabi,"offset of %qT base class for "
+ "%<-std=c++20%> and up changes in "
+ "%<-fabi-version=21%> (GCC 16)", TREE_TYPE (next));
+ }
else
- warning_at (loc, OPT_Wabi, "offset of %qD for "
- "%<-std=c++14%> and up changes in "
- "%<-fabi-version=17%> (GCC 12)", next);
+ {
+ if (abi_version_crosses (17)
+ && CLASSTYPE_NON_POD_AGGREGATE (type))
+ warning_at (loc, OPT_Wabi, "offset of %qD for "
+ "%<-std=c++14%> and up changes in "
+ "%<-fabi-version=17%> (GCC 12)", next);
+ else if (abi_version_crosses (21)
+ && CLASSTYPE_NON_AGGREGATE_POD (type))
+ warning_at (loc, OPT_Wabi, "offset of %qD for "
+ "%<-std=c++20%> and up changes in "
+ "%<-fabi-version=21%> (GCC 16)", next);
+ }
}
}
@@ -7367,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;
}
@@ -7842,6 +7927,17 @@ finish_struct_1 (tree t)
return;
}
+ if (location_t fcloc = failed_completion_location (t))
+ {
+ auto_diagnostic_group adg;
+ if (warning (OPT_Wsfinae_incomplete_,
+ "defining %qT, which previously failed to be complete "
+ "in a SFINAE context", t)
+ && warn_sfinae_incomplete == 1)
+ inform (fcloc, "here. Use %qs for a diagnostic at that point",
+ "-Wsfinae-incomplete=2");
+ }
+
/* If this type was previously laid out as a forward reference,
make sure we lay it out again. */
TYPE_SIZE (t) = NULL_TREE;
@@ -8261,6 +8357,15 @@ fixed_type_or_null (tree instance, int *nonnull, int *cdtorp)
*nonnull = 1;
return TREE_TYPE (instance);
}
+ if (CLASS_TYPE_P (TREE_TYPE (instance)))
+ {
+ /* We missed a build_cplus_new somewhere, likely due to tf_decltype
+ mishandling. */
+ gcc_checking_assert (false);
+ if (nonnull)
+ *nonnull = 1;
+ return TREE_TYPE (instance);
+ }
return NULL_TREE;
case SAVE_EXPR:
@@ -10531,7 +10636,7 @@ build_vtbl_initializer (tree binfo,
int i;
if (init == size_zero_node)
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
- CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
+ CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
else
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
{
@@ -10539,11 +10644,11 @@ build_vtbl_initializer (tree binfo,
fn, build_int_cst (NULL_TREE, i));
TREE_CONSTANT (fdesc) = 1;
- CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
+ CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
}
}
else
- CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
+ CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
}
}
@@ -10882,6 +10987,17 @@ publicly_uniquely_derived_p (tree parent, tree type)
return base && base != error_mark_node;
}
+/* TRUE iff TYPE is publicly & virtually derived from PARENT. */
+
+bool
+publicly_virtually_derived_p (tree parent, tree type)
+{
+ tree base = lookup_base (type, parent,
+ ba_ignore_scope | ba_check | ba_require_virtual,
+ NULL, tf_none);
+ return base && base != error_mark_node;
+}
+
/* CTX1 and CTX2 are declaration contexts. Return the innermost common
class between them, if any. */
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 4820bcc..eb19784 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -303,11 +303,20 @@ is_valid_constexpr_fn (tree fun, bool complain)
}
}
}
- else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
+ else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)) && cxx_dialect < cxx26)
{
ret = false;
if (complain)
- error ("%q#T has virtual base classes", DECL_CONTEXT (fun));
+ {
+ if (DECL_CONSTRUCTOR_P (fun))
+ error ("%<constexpr%> constructor in %q#T that has "
+ "virtual base classes only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun));
+ else
+ error ("%<constexpr%> destructor in %q#T that has "
+ "virtual base classes only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun));
+ }
}
return ret;
@@ -1048,6 +1057,12 @@ explain_invalid_constexpr_fn (tree fun)
{
static hash_set<tree> *diagnosed;
tree body;
+
+ /* Don't try to explain a function we already complained about. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ return;
+
/* In C++23, a function marked 'constexpr' may not actually be a constant
expression. We haven't diagnosed the problem yet: -Winvalid-constexpr
wasn't enabled. The function was called, so diagnose why it cannot be
@@ -1097,17 +1112,14 @@ explain_invalid_constexpr_fn (tree fun)
body = fd->body;
else
body = DECL_SAVED_TREE (fun);
- body = massage_constexpr_body (fun, body);
- require_potential_rvalue_constant_expression (body);
+ tree massaged = massage_constexpr_body (fun, body);
+ require_potential_rvalue_constant_expression (massaged);
if (DECL_CONSTRUCTOR_P (fun))
{
- cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
+ cx_check_missing_mem_inits (DECL_CONTEXT (fun), massaged, true);
if (cxx_dialect > cxx11)
- {
- /* Also check the body, not just the ctor-initializer. */
- body = DECL_SAVED_TREE (fun);
- require_potential_rvalue_constant_expression (body);
- }
+ /* Also check the body, not just the ctor-initializer. */
+ require_potential_rvalue_constant_expression (body);
}
}
}
@@ -1119,20 +1131,22 @@ explain_invalid_constexpr_fn (tree fun)
struct GTY((for_user)) constexpr_call {
/* Description of the constexpr function definition. */
- constexpr_fundef *fundef;
+ constexpr_fundef *fundef = nullptr;
/* Parameter bindings environment. A TREE_VEC of arguments. */
- tree bindings;
- /* Result of the call.
- NULL means the call is being evaluated.
+ tree bindings = NULL_TREE;
+ /* Result of the call, indexed by the value of
+ constexpr_ctx::manifestly_const_eval.
+ unknown_type_node means the call is being evaluated.
error_mark_node means that the evaluation was erroneous or otherwise
uncacheable (e.g. because it depends on the caller).
Otherwise, the actual value of the call. */
- tree result;
+ tree results[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
/* The hash of this call; we remember it here to avoid having to
recalculate it when expanding the hash table. */
- hashval_t hash;
- /* The value of constexpr_ctx::manifestly_const_eval. */
- enum mce_value manifestly_const_eval;
+ hashval_t hash = 0;
+
+ /* The result slot corresponding to the given mce_value. */
+ tree& result (mce_value mce) { return results[1 + int(mce)]; }
};
struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call>
@@ -1170,6 +1184,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
@@ -1177,10 +1195,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)
{
@@ -1294,6 +1315,64 @@ 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. */
+
+static bool
+p2280_active_p (const constexpr_ctx *ctx)
+{
+ if (ctx->manifestly_const_eval != mce_true)
+ /* Disable these relaxations during speculative constexpr folding,
+ as it can significantly increase compile time/memory use
+ (PR119387). */
+ return false;
+
+ /* P2280R4 was accepted as a DR against C++11. */
+ return cxx_dialect >= cxx11;
+}
+
/* Remove T from the global values map, checking for attempts to destroy
a value that has already finished its lifetime. */
@@ -1411,8 +1490,6 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs)
return true;
if (lhs->hash != rhs->hash)
return false;
- if (lhs->manifestly_const_eval != rhs->manifestly_const_eval)
- return false;
if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef))
return false;
return cp_tree_equal (lhs->bindings, rhs->bindings);
@@ -1515,13 +1592,671 @@ 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 *);
-static tree find_deleted_heap_var (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
@@ -1530,7 +2265,8 @@ static tree find_deleted_heap_var (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));
@@ -1576,6 +2312,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))
@@ -1650,8 +2392,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)
@@ -1740,7 +2488,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
@@ -1854,20 +2603,29 @@ 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,
- bool *non_constant_p, bool *overflow_p,
- bool *non_constant_args)
+ tree orig_fun, bool *non_constant_p,
+ bool *overflow_p, bool *non_constant_args,
+ tree *jump_target)
{
- const int nargs = call_expr_nargs (t);
+ int nargs = call_expr_nargs (t);
tree parms = DECL_ARGUMENTS (fun);
- int i;
+ int i, j = 0;
+ if (DECL_HAS_IN_CHARGE_PARM_P (fun) && fun != orig_fun)
+ ++nargs;
+ if (DECL_HAS_VTT_PARM_P (fun)
+ && fun != orig_fun
+ && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun)))
+ ++nargs;
/* We don't record ellipsis args below. */
int nparms = list_length (parms);
int nbinds = nargs < nparms ? nargs : nparms;
tree binds = make_tree_vec (nbinds);
/* The call is not a constant expression if it involves the cdtor for a type
- with virtual bases. */
- if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))
+ with virtual bases before C++26. */
+ if (cxx_dialect < cxx26
+ && (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun)))
{
if (!ctx->quiet)
{
@@ -1885,7 +2643,30 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
tree type = parms ? TREE_TYPE (parms) : void_type_node;
if (parms && DECL_BY_REFERENCE (parms))
type = TREE_TYPE (type);
- x = get_nth_callarg (t, i);
+ if (i == 1
+ && j == 0
+ && DECL_HAS_IN_CHARGE_PARM_P (fun)
+ && orig_fun != fun)
+ {
+ if (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun))
+ x = boolean_true_node;
+ else
+ x = boolean_false_node;
+ j = -1;
+ }
+ else if (i == 2
+ && j == -1
+ && DECL_HAS_VTT_PARM_P (fun)
+ && orig_fun != fun
+ && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun)))
+ {
+ x = build_zero_cst (type);
+ j = -2;
+ }
+ else
+ x = get_nth_callarg (t, i + j);
/* For member function, the first argument is a pointer to the implied
object. For a constructor, it might still be a dummy object, in
which case we get the real argument from ctx. */
@@ -1900,14 +2681,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)
@@ -1925,6 +2708,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;
@@ -2036,9 +2821,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);
@@ -2125,7 +2911,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))
@@ -2138,12 +2924,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)
@@ -2175,7 +2964,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;
@@ -2208,13 +2998,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;
@@ -2232,10 +3024,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);
@@ -2504,14 +3299,12 @@ get_component_with_type (tree path, tree type, tree stop)
dst_ptr + src2dst == src_ptr
-1: unspecified relationship
-2: src_type is not a public base of dst_type
- -3: src_type is a multiple public non-virtual base of dst_type
-
- Since literal types can't have virtual bases, we only expect hint >=0,
- -2, or -3. */
+ -3: src_type is a multiple public non-virtual base of dst_type */
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)
@@ -2530,19 +3323,42 @@ 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
+ d.D.1234 using cxx_fold_indirect_ref. */
+ if (cxx_dialect >= cxx26 && CONVERT_EXPR_P (obj))
+ {
+ tree objo = obj;
+ STRIP_NOPS (objo);
+ if (TREE_CODE (objo) == POINTER_PLUS_EXPR)
+ {
+ objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)),
+ obj, NULL, jump_target);
+ if (objo)
+ obj = build_fold_addr_expr (objo);
+ }
+ }
/* We expect OBJ to be in form of &d.D.2102 when HINT == 0,
but when HINT is > 0, it can also be something like
@@ -2554,7 +3370,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)
{
@@ -2576,9 +3392,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))
@@ -2610,7 +3429,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)
{
@@ -2643,7 +3462,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)
{
@@ -2665,7 +3484,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)
{
@@ -2761,7 +3580,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);
@@ -2804,7 +3623,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
@@ -2814,7 +3634,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)))
@@ -2822,8 +3642,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;
}
}
@@ -2835,23 +3658,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);
- constexpr_call new_call
- = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval };
- int depth_ok;
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);
@@ -2894,6 +3719,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
+ tree orig_fun = fun;
if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))
fun = DECL_CLONED_FUNCTION (fun);
@@ -2902,9 +3728,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
@@ -2919,7 +3748,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)
@@ -2930,12 +3762,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
gcc_assert (arg0);
if (new_op_p)
{
- /* FIXME: We should not get here; the VERIFY_CONSTANT above
- should have already caught it. But currently a conversion
- from pointer type to arithmetic type is only considered
- non-constant for CONVERT_EXPRs, not NOP_EXPRs. */
if (!tree_fits_uhwi_p (arg0))
{
+ /* We should not get here; the VERIFY_CONSTANT above
+ should have already caught it. */
+ gcc_checking_assert (false);
if (!ctx->quiet)
error_at (loc, "cannot allocate array: size not constant");
*non_constant_p = true;
@@ -2950,14 +3781,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
: heap_uninit_identifier,
type);
DECL_ARTIFICIAL (var) = 1;
- TREE_STATIC (var) = 1;
- // Temporarily register the artificial var in varpool,
- // so that comparisons of its address against NULL are folded
- // through nonzero_address even with
- // -fno-delete-null-pointer-checks or that comparison of
- // addresses of different heap artificial vars is folded too.
- // See PR98988 and PR99031.
- varpool_node::finalize_decl (var);
ctx->global->heap_vars.safe_push (var);
ctx->global->put_value (var, NULL_TREE);
return fold_convert (ptr_type_node, build_address (var));
@@ -3043,7 +3866,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
@@ -3053,19 +3879,35 @@ 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;
+ ctx = &new_ctx;
if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
&& TREE_CODE (t) == AGGR_INIT_EXPR)
{
@@ -3075,30 +3917,30 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
CONSTRUCTOR_NO_CLEARING (ctor) = true;
ctx->global->put_value (new_ctx.object, ctor);
- ctx = &new_ctx;
}
/* An immediate invocation is manifestly constant evaluated including the
arguments of the call, so use mce_true even for the argument
evaluation. */
if (DECL_IMMEDIATE_FUNCTION_P (fun))
- {
- new_ctx.manifestly_const_eval = mce_true;
- new_call.manifestly_const_eval = mce_true;
- ctx = &new_ctx;
- }
+ new_ctx.manifestly_const_eval = mce_true;
/* We used to shortcut trivial constructor/op= here, but nowadays
we can only get a trivial function here with -fno-elide-constructors. */
gcc_checking_assert (!trivial_fn_p (fun)
|| !flag_elide_constructors
+ /* Or it's a call from maybe_thunk_body (111075). */
+ || (TREE_CODE (t) == CALL_EXPR ? CALL_FROM_THUNK_P (t)
+ : AGGR_INIT_FROM_THUNK_P (t))
/* We don't elide constructors when processing
a noexcept-expression. */
|| cp_noexcept_operand);
bool non_constant_args = false;
+ constexpr_call new_call;
new_call.bindings
- = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p,
- overflow_p, &non_constant_args);
+ = cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p,
+ 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
@@ -3112,8 +3954,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)
@@ -3169,7 +4024,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
}
}
- depth_ok = push_cx_call_context (t);
+ /* Don't complain about problems evaluating an ill-formed function. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ new_ctx.quiet = true;
+
+ int depth_ok = push_cx_call_context (t);
/* Remember the object we are constructing or destructing. */
tree new_obj = NULL_TREE;
@@ -3181,7 +4041,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. */
@@ -3211,8 +4073,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef);
new_call.hash
= iterative_hash_template_arg (new_call.bindings, new_call.hash);
- new_call.hash
- = iterative_hash_object (ctx->manifestly_const_eval, new_call.hash);
/* If we have seen this call before, we are done. */
maybe_initialize_constexpr_call_table ();
@@ -3230,22 +4090,23 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
the slot can move during evaluation of the body. */
*slot = entry = ggc_alloc<constexpr_call> ();
*entry = new_call;
+ entry->result (ctx->manifestly_const_eval) = unknown_type_node;
fb.preserve ();
}
}
- /* Calls that are in progress have their result set to NULL, so that we
- can detect circular dependencies. Now that we only cache up to
- constexpr_cache_depth this won't catch circular dependencies that
+ /* Calls that are in progress have their result set to unknown_type_node,
+ so that we can detect circular dependencies. Now that we only cache
+ up to constexpr_cache_depth this won't catch circular dependencies that
start deeper, but they'll hit the recursion or ops limit. */
- else if (entry->result == NULL)
+ else if (entry->result (ctx->manifestly_const_eval) == unknown_type_node)
{
if (!ctx->quiet)
error ("call has circular dependency");
*non_constant_p = true;
- entry->result = result = error_mark_node;
+ entry->result (ctx->manifestly_const_eval) = result = error_mark_node;
}
else
- result = entry->result;
+ result = entry->result (ctx->manifestly_const_eval);
}
if (!depth_ok)
@@ -3331,7 +4192,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. */
@@ -3345,16 +4206,25 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
build_constructor (TREE_TYPE (new_obj),
NULL));
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
@@ -3382,7 +4252,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);
@@ -3425,11 +4295,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
cacheable = false;
break;
}
- /* And don't cache a ref to a deleted heap variable (119162). */
- if (cacheable
- && (cp_walk_tree_without_duplicates
- (&result, find_deleted_heap_var, NULL)))
- cacheable = false;
}
/* Rewrite all occurrences of the function's RESULT_DECL with the
@@ -3447,7 +4312,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;
+ }
}
}
@@ -3466,7 +4337,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
else if (!result)
result = void_node;
if (entry)
- entry->result = cacheable ? result : error_mark_node;
+ {
+ entry->result (ctx->manifestly_const_eval)
+ = cacheable ? result : error_mark_node;
+
+ if (result != error_mark_node
+ && ctx->manifestly_const_eval == mce_unknown)
+ {
+ /* Evaluation succeeded and was independent of whether we're in a
+ manifestly constant-evaluated context, so we can also reuse
+ this result when evaluating this call with a fixed context. */
+ if (!entry->result (mce_true))
+ entry->result (mce_true) = entry->result (mce_unknown);
+ if (!entry->result (mce_false))
+ entry->result (mce_false) = entry->result (mce_unknown);
+ }
+ }
}
/* The result of a constexpr function must be completely initialized.
@@ -3487,11 +4373,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
/* Return true if T is a valid constant initializer. If a CONSTRUCTOR
initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
- cleared.
+ cleared. If called recursively on a FIELD_DECL's CONSTRUCTOR, SZ
+ is DECL_SIZE of the FIELD_DECL, otherwise NULL.
FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
bool
-reduced_constant_expression_p (tree t)
+reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */)
{
if (t == NULL_TREE)
return false;
@@ -3502,6 +4389,9 @@ reduced_constant_expression_p (tree t)
/* Even if we can't lower this yet, it's constant. */
return true;
+ case OMP_DECLARE_MAPPER:
+ return true;
+
case CONSTRUCTOR:
/* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
tree field;
@@ -3556,7 +4446,12 @@ reduced_constant_expression_p (tree t)
{
/* If VAL is null, we're in the middle of initializing this
element. */
- if (!reduced_constant_expression_p (e.value))
+ if (!reduced_constant_expression_p (e.value,
+ (e.index
+ && (TREE_CODE (e.index)
+ == FIELD_DECL))
+ ? DECL_SIZE (e.index)
+ : NULL_TREE))
return false;
/* We want to remove initializers for empty fields in a struct to
avoid confusing output_constructor. */
@@ -3576,7 +4471,16 @@ reduced_constant_expression_p (tree t)
/* There could be a non-empty field at the end. */
for (; field; field = next_subobject_field (DECL_CHAIN (field)))
if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false))
- return false;
+ {
+ /* Ignore FIELD_DECLs with bit positions beyond DECL_SIZE of
+ the parent FIELD_DECL (if any) for classes with virtual
+ bases. */
+ if (cxx_dialect >= cxx26
+ && sz
+ && tree_int_cst_le (sz, bit_position (field)))
+ break;
+ return false;
+ }
ok:
if (CONSTRUCTOR_NO_CLEARING (t))
/* All the fields are initialized. */
@@ -3772,12 +4676,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);
@@ -3801,7 +4709,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)
@@ -3823,9 +4731,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;
@@ -3845,7 +4756,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;
@@ -3889,22 +4801,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);
@@ -3960,13 +4879,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)
@@ -4025,7 +4948,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))
{
@@ -4086,19 +5012,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);
@@ -4486,7 +5422,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)
@@ -4503,7 +5440,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;
}
@@ -4534,13 +5472,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)
@@ -4552,7 +5494,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)
@@ -4572,14 +5516,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)))
@@ -4589,9 +5537,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;
@@ -4709,7 +5660,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;
@@ -4721,7 +5672,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;
@@ -4730,9 +5682,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)))
{
@@ -4841,7 +5796,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
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.
@@ -4851,7 +5807,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;
@@ -4859,10 +5816,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
@@ -5143,7 +6103,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))
@@ -5157,9 +6117,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)
@@ -5237,8 +6200,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;
}
}
@@ -5279,19 +6243,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;
}
@@ -5448,7 +6417,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;
@@ -5501,7 +6471,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;
@@ -5591,7 +6564,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);
@@ -5602,7 +6576,7 @@ 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);
/* For the default constructor, build up a call to the default
constructor of the element type. We only need to handle class types
@@ -5639,7 +6613,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)
{
@@ -5665,9 +6641,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)
{
@@ -5681,7 +6657,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
@@ -5697,8 +6674,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)
@@ -5748,7 +6728,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);
@@ -5780,10 +6760,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
@@ -5812,14 +6792,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
@@ -5832,12 +6814,28 @@ 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;
if (off == 0 && similar_type_p (optype, type))
return op;
+ else if (cxx_dialect >= cxx26
+ && VAR_P (op)
+ && DECL_VTABLE_OR_VTT_P (op)
+ && same_type_ignoring_top_level_qualifiers_p (type,
+ ptrdiff_type_node)
+ && POINTER_TYPE_P (strip_array_types (optype)))
+ {
+ /* We often read some virtual table elements using ptrdiff_t rather
+ than pointer type. */
+ if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc,
+ strip_array_types (optype),
+ op, off, empty_base,
+ jump_target))
+ return fold_convert (type, ret);
+ }
else if (TREE_CODE (optype) == COMPLEX_TYPE
&& similar_type_p (type, TREE_TYPE (optype)))
{
@@ -5881,7 +6879,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 */
@@ -5890,7 +6888,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)));
@@ -5899,7 +6897,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;
}
}
@@ -5931,15 +6930,21 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
if (!tree_fits_uhwi_p (pos))
continue;
unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos);
- unsigned HOST_WIDE_INT el_sz
- = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+ unsigned HOST_WIDE_INT el_sz;
+ if (DECL_FIELD_IS_BASE (field)
+ && CLASS_TYPE_P (optype)
+ && CLASSTYPE_VBASECLASSES (optype))
+ el_sz = tree_to_uhwi (DECL_SIZE_UNIT (field));
+ else
+ el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
if (upos <= off && off < upos + el_sz)
{
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 - upos,
- empty_base))
+ empty_base,
+ jump_target))
return ret;
}
}
@@ -5959,7 +6964,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;
@@ -5983,6 +6988,25 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
offset positive, so that cxx_fold_indirect_ref_1 can identify
more folding opportunities. */
auto canonicalize_obj_off = [] (tree& obj, tree& off) {
+ if (cxx_dialect >= cxx26)
+ {
+ /* For C++26, we need to fold *(B *)(&x.D.1234 + 32) used
+ to access virtual base members. */
+ tree nobj = obj;
+ while (TREE_CODE (nobj) == COMPONENT_REF
+ && DECL_FIELD_IS_BASE (TREE_OPERAND (nobj, 1)))
+ nobj = TREE_OPERAND (nobj, 0);
+ if (nobj != obj
+ && CLASS_TYPE_P (TREE_TYPE (nobj))
+ && CLASSTYPE_VBASECLASSES (TREE_TYPE (nobj)))
+ while (obj != nobj)
+ {
+ tree field = TREE_OPERAND (obj, 1);
+ tree pos = byte_position (field);
+ off = int_const_binop (PLUS_EXPR, off, pos);
+ obj = TREE_OPERAND (obj, 0);
+ }
+ }
while (TREE_CODE (obj) == COMPONENT_REF
/* We need to preserve union member accesses so that we can
later properly diagnose accessing the wrong member. */
@@ -6021,8 +7045,9 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
{
tree off = integer_zero_node;
canonicalize_obj_off (op, off);
- gcc_assert (integer_zerop (off));
- return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base);
+ return cxx_fold_indirect_ref_1 (ctx, loc, type, op,
+ tree_to_uhwi (off), empty_base,
+ jump_target);
}
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
@@ -6037,7 +7062,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] */
@@ -6047,7 +7073,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
@@ -6065,7 +7094,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;
@@ -6083,13 +7113,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;
@@ -6103,7 +7137,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
@@ -6133,7 +7169,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;
@@ -6243,7 +7282,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];
@@ -6253,7 +7293,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]);
}
@@ -6375,7 +7418,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;
@@ -6383,7 +7427,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CLOBBER_P (init)
&& CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
- /* Only handle clobbers ending the lifetime of objects. */
+ /* Only handle clobbers ending the lifetime of objects.
+ ??? We should probably set CONSTRUCTOR_NO_CLEARING. */
return void_node;
/* First we figure out where we're storing to. */
@@ -6400,7 +7445,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;
}
@@ -6412,8 +7460,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;
}
@@ -6439,7 +7490,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;
}
@@ -6496,8 +7550,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;
}
@@ -6841,7 +7898,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. */
@@ -6967,7 +8027,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);
@@ -6981,12 +8042,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));
@@ -7025,8 +8092,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;
@@ -7040,42 +8110,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. */
@@ -7123,6 +8157,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 ();
}
@@ -7137,15 +8176,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;
@@ -7173,18 +8206,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;
}
@@ -7196,13 +8222,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;
@@ -7258,7 +8277,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);
@@ -7353,7 +8372,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;
@@ -7400,6 +8420,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 ();
@@ -7418,7 +8439,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)
{
@@ -7551,7 +8575,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));
@@ -7587,13 +8612,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;
@@ -7614,6 +8643,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 */
@@ -7623,9 +8684,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. */
@@ -7749,7 +8810,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:
@@ -7792,7 +8853,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = TARGET_EXPR_INITIAL (r);
if (DECL_P (r)
/* P2280 allows references to unknown. */
- && !(VAR_P (t) && TYPE_REF_P (TREE_TYPE (t))))
+ && !(p2280_active_p (ctx) && VAR_P (t) && TYPE_REF_P (TREE_TYPE (t))))
{
if (!ctx->quiet)
non_const_var_error (loc, r, /*fundef_p*/false);
@@ -7811,6 +8872,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case LABEL_EXPR:
case CASE_LABEL_EXPR:
case PREDICT_EXPR:
+ case OMP_DECLARE_MAPPER:
return t;
case PARM_DECL:
@@ -7826,7 +8888,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. */;
@@ -7844,9 +8909,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = build_constructor (TREE_TYPE (t), NULL);
TREE_CONSTANT (r) = true;
}
- else if (TYPE_REF_P (TREE_TYPE (t)))
+ else if (p2280_active_p (ctx) && TYPE_REF_P (TREE_TYPE (t)))
/* P2280 allows references to unknown... */;
- else if (is_this_parameter (t))
+ else if (p2280_active_p (ctx) && is_this_parameter (t))
/* ...as well as the this pointer. */;
else
{
@@ -7859,7 +8924,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:
@@ -7923,7 +8988,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
@@ -7982,14 +9050,23 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
ctx->global->put_value (new_ctx.object, new_ctx.ctor);
ctx = &new_ctx;
}
+
+ /* If the initializer is complex, evaluate it to initialize slot. */
+ bool is_complex = target_expr_needs_replace (t);
+ if (is_complex)
+ /* In case no initialization actually happens, clear out any
+ void_node from a previous evaluation. */
+ ctx->global->put_value (slot, NULL_TREE);
+
/* 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 the initializer is complex, evaluate it to initialize slot. */
- bool is_complex = target_expr_needs_replace (t);
+ if (*jump_target)
+ return NULL_TREE;
if (!is_complex)
{
r = unshare_constructor (r);
@@ -7997,8 +9074,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)
@@ -8012,33 +9096,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:
@@ -8047,9 +9126,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)
@@ -8057,16 +9137,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),
@@ -8075,6 +9146,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;
@@ -8092,47 +9199,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;
@@ -8142,14 +9334,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;
@@ -8169,7 +9365,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)
@@ -8190,7 +9389,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:
@@ -8228,6 +9428,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);
@@ -8280,7 +9482,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
@@ -8289,19 +9492,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:
@@ -8316,17 +9522,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))
@@ -8364,7 +9572,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:
@@ -8376,7 +9584,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:
@@ -8386,12 +9594,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:
@@ -8399,7 +9608,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:
@@ -8423,7 +9633,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);
@@ -8434,7 +9647,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (t) == CONVERT_EXPR
&& ARITHMETIC_TYPE_P (type)
&& INDIRECT_TYPE_P (TREE_TYPE (op))
- && ctx->manifestly_const_eval == mce_true)
+ && ctx->strict)
{
if (!ctx->quiet)
error_at (loc,
@@ -8480,7 +9693,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);
@@ -8586,7 +9802,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree cookie_size = NULL_TREE;
tree arg_size = NULL_TREE;
if (TREE_CODE (elt_type) == RECORD_TYPE
- && TYPE_NAME (elt_type) == heap_identifier)
+ && TYPE_IDENTIFIER (elt_type) == heap_identifier)
{
tree fld1 = TYPE_FIELDS (elt_type);
tree fld2 = DECL_CHAIN (fld1);
@@ -8607,10 +9823,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));
}
@@ -8649,7 +9869,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);
@@ -8686,14 +9909,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:
@@ -8707,7 +9936,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. */
@@ -8717,7 +9947,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;
@@ -8730,7 +9961,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;
@@ -8842,7 +10076,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:
@@ -8981,20 +10215,6 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
return NULL_TREE;
}
-/* Look for deleted heap variables in the expression *TP. */
-
-static tree
-find_deleted_heap_var (tree *tp, int *walk_subtrees, void */*data*/)
-{
- if (VAR_P (*tp)
- && DECL_NAME (*tp) == heap_deleted_identifier)
- return *tp;
-
- if (TYPE_P (*tp))
- *walk_subtrees = 0;
- return NULL_TREE;
-}
-
/* Find immediate function decls in *TP if any. */
static tree
@@ -9100,6 +10320,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
tree fndecl = cp_get_callee_fndecl_nofold (x);
if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
is_consteval = true;
+ /* Don't try to evaluate a std::vector constructor taking an integer, it
+ will fail in the 'if (heap_var)' block below after doing all the work
+ (c++/113835). This will need adjustment if P3554 is accepted. Note
+ that evaluation of e.g. the vector default constructor can succeed, so
+ we don't shortcut all vector constructors. */
+ if (fndecl && DECL_CONSTRUCTOR_P (fndecl) && allow_non_constant
+ && is_std_class (type, "vector") && call_expr_nargs (x) > 1
+ && TREE_CODE (TREE_TYPE (get_nth_callarg (x, 1))) == INTEGER_TYPE)
+ return t;
}
if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
{
@@ -9166,30 +10395,67 @@ 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. */
if (r == void_node && !constexpr_dtor && ctx.ctor)
r = ctx.ctor;
- if (!constexpr_dtor)
- verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
- else
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
-
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 "
@@ -9197,15 +10463,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
- if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
- {
- if (!allow_non_constant)
- error ("%qE is not a constant expression because it refers to "
- "an incompletely initialized variable", t);
- TREE_CONSTANT (r) = false;
- non_constant_p = true;
- }
-
if (!non_constant_p && cxx_dialect >= cxx20
&& !global_ctx.heap_vars.is_empty ())
{
@@ -9215,9 +10472,16 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (heap_var)
{
if (!allow_non_constant && !non_constant_p)
- error_at (DECL_SOURCE_LOCATION (heap_var),
- "%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;
non_constant_p = true;
}
@@ -9226,13 +10490,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
if (!allow_non_constant && !non_constant_p)
- error_at (DECL_SOURCE_LOCATION (heap_var),
- "%qE is not a constant expression because allocated "
- "storage has not been deallocated", t);
+ {
+ error ("%qE is not a constant expression because allocated "
+ "storage has not been deallocated", t);
+ inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
+ }
r = t;
non_constant_p = true;
}
- varpool_node::get (heap_var)->remove ();
}
}
@@ -9258,6 +10523,20 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
+ if (!non_constant_p && !constexpr_dtor)
+ verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
+
+ /* After verify_constant because reduced_constant_expression_p can unset
+ CONSTRUCTOR_NO_CLEARING. */
+ if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
+ {
+ if (!allow_non_constant)
+ error ("%qE is not a constant expression because it refers to "
+ "an incompletely initialized variable", t);
+ TREE_CONSTANT (r) = false;
+ non_constant_p = true;
+ }
+
if (non_constant_p)
/* If we saw something bad, go back to our argument. The wrapping below is
only for the cases of TREE_CONSTANT argument or overflow. */
@@ -9274,13 +10553,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (non_constant_p && !allow_non_constant)
return error_mark_node;
- else if (constexpr_dtor)
- return r;
else if (non_constant_p && TREE_CONSTANT (r))
r = mark_non_constant (r);
else if (non_constant_p)
return t;
+ if (constexpr_dtor)
+ {
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
+ return r;
+ }
+
/* Check we are not trying to return the wrong type. */
if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (r)))
{
@@ -9300,7 +10583,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (TREE_CODE (t) == TARGET_EXPR
&& TARGET_EXPR_INITIAL (t) == r)
return t;
- else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR)
+ else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR
+ || TREE_CODE (t) == AGGR_INIT_EXPR)
/* Don't add a TARGET_EXPR if our argument didn't have one. */;
else if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_CLEANUP (t))
r = get_target_expr (r);
@@ -9431,6 +10715,9 @@ fold_simple (tree t)
tree
fold_to_constant (tree t)
{
+ if (processing_template_decl)
+ return t;
+
tree r = fold (t);
if (CONSTANT_CLASS_P (r) && !TREE_OVERFLOW (r))
return r;
@@ -9450,8 +10737,35 @@ tree
maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
mce_value manifestly_const_eval /* = mce_unknown */)
{
+ tree orig_t = t;
tree r;
+ if (EXPR_P (t) && manifestly_const_eval == mce_unknown)
+ {
+ /* Look up each operand in the cv_cache first to see if we've already
+ reduced it, and reuse that result to avoid quadratic behavior if
+ we're called when building up a large expression. */
+ int n = cp_tree_operand_length (t);
+ tree *ops = XALLOCAVEC (tree, n);
+ bool rebuild = false;
+ for (int i = 0; i < n; ++i)
+ {
+ ops[i] = TREE_OPERAND (t, i);
+ if (tree *cached = hash_map_safe_get (cv_cache, ops[i]))
+ if (*cached != ops[i])
+ {
+ ops[i] = *cached;
+ rebuild = true;
+ }
+ }
+ if (rebuild)
+ {
+ t = copy_node (t);
+ for (int i = 0; i < n; ++i)
+ TREE_OPERAND (t, i) = ops[i];
+ }
+ }
+
if (!is_nondependent_constant_expression (t))
{
if (TREE_OVERFLOW_P (t)
@@ -9469,6 +10783,10 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
return fold_to_constant (t);
if (manifestly_const_eval != mce_unknown)
+ /* TODO: Extend the cache to be mce_value aware. And if we have a
+ previously cached mce_unknown result that's TREE_CONSTANT, it means
+ the reduced value is independent of mce_value and so we should
+ be able to reuse it in the mce_true/false case. */
return cxx_eval_outermost_constant_expr (t, true, true,
manifestly_const_eval, false, decl);
@@ -9498,7 +10816,7 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
|| (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
|| !cp_tree_equal (r, t));
if (!c.evaluation_restricted_p ())
- cv_cache->put (t, r);
+ cv_cache->put (orig_t, r);
return r;
}
@@ -9662,7 +10980,7 @@ fold_non_dependent_init (tree t,
static tree
maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
- bool manifestly_const_eval)
+ mce_value manifestly_const_eval)
{
if (!t)
return t;
@@ -9688,17 +11006,27 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
{
/* [basic.start.static] allows constant-initialization of variables with
static or thread storage duration even if it isn't required, but we
- shouldn't bend the rules the same way for automatic variables. */
+ shouldn't bend the rules the same way for automatic variables.
+
+ But still enforce the requirements of constexpr/constinit.
+ [dcl.constinit] "If a variable declared with the constinit specifier
+ has dynamic initialization, the program is ill-formed, even if the
+ implementation would perform that initialization as a static
+ initialization." */
bool is_static = (decl && DECL_P (decl)
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)));
+ bool strict = (!is_static
+ || (decl && DECL_P (decl)
+ && (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_DECLARED_CONSTINIT_P (decl))));
if (is_static)
- manifestly_const_eval = true;
+ manifestly_const_eval = mce_true;
- if (cp_unevaluated_operand && !manifestly_const_eval)
+ if (cp_unevaluated_operand && manifestly_const_eval != mce_true)
return fold_to_constant (t);
- t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static,
- mce_value (manifestly_const_eval),
+ t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict,
+ manifestly_const_eval,
false, decl);
}
if (TREE_CODE (t) == TARGET_EXPR)
@@ -9715,6 +11043,12 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
tree
maybe_constant_init (tree t, tree decl, bool manifestly_const_eval)
{
+ return maybe_constant_init_1 (t, decl, true, mce_value (manifestly_const_eval));
+}
+
+tree
+maybe_constant_init (tree t, tree decl, mce_value manifestly_const_eval)
+{
return maybe_constant_init_1 (t, decl, true, manifestly_const_eval);
}
@@ -9723,7 +11057,25 @@ maybe_constant_init (tree t, tree decl, bool manifestly_const_eval)
tree
cxx_constant_init (tree t, tree decl)
{
- return maybe_constant_init_1 (t, decl, false, true);
+ 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
@@ -9758,11 +11110,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)
{
@@ -9847,6 +11201,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;
@@ -10052,8 +11413,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%> "
@@ -10098,7 +11478,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;
}
@@ -10263,22 +11648,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
return true;
case INDIRECT_REF:
- {
- tree x = TREE_OPERAND (t, 0);
- STRIP_NOPS (x);
- if (is_this_parameter (x) && !is_capture_proxy (x))
- {
- if (now || !var_in_maybe_constexpr_fn (x))
- {
- if (flags & tf_error)
- constexpr_error (loc, fundef_p, "use of %<this%> in a "
- "constant expression");
- return false;
- }
- return true;
- }
- return RECUR (x, rval);
- }
+ return RECUR (TREE_OPERAND (t, 0), rval);
case STATEMENT_LIST:
for (tree stmt : tsi_range (t))
@@ -10336,11 +11706,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;
}
}
@@ -10380,11 +11752,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))
@@ -10408,7 +11782,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))
@@ -10417,6 +11791,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;
@@ -10446,7 +11822,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:
@@ -10497,6 +11872,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
"expression", t);
return false;
+ case OMP_DECLARE_MAPPER:
+ /* This can be used to initialize VAR_DECLs: it's treated as a magic
+ 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);
@@ -10625,6 +12010,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:
@@ -10866,9 +12267,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))
@@ -10880,7 +12281,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,
@@ -10893,6 +12295,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;
@@ -10944,6 +12348,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
*jump_target = *target;
return true;
}
+ if (DECL_ARTIFICIAL (*target))
+ /* The user didn't write this goto, this isn't the problem. */
+ return true;
if (flags & tf_error)
constexpr_error (loc, fundef_p, "%<goto%> is not a constant "
"expression");
@@ -10977,6 +12384,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CO_AWAIT_EXPR:
case CO_YIELD_EXPR:
case CO_RETURN_EXPR:
+ if (flags & tf_error)
+ constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p,
+ "%qE is not a constant expression", t);
return false;
/* Assume a TU-local entity is not constant, we'll error later when
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a9caba8..c8eef24 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -354,7 +354,7 @@ struct norm_info : subst_info
/* Construct a top-level context for DECL. */
norm_info (tree in_decl, bool diag)
- : subst_info (tf_warning_or_error, in_decl),
+ : subst_info (tf_warning_or_error|tf_partial, in_decl),
generate_diagnostics (diag)
{
if (in_decl)
@@ -1836,7 +1836,7 @@ tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_
static bool satisfying_constraint;
/* A vector of incomplete types (and of declarations with undeduced return type),
- appended to by note_failed_type_completion_for_satisfaction. The
+ appended to by note_failed_type_completion. The
satisfaction caches use this in order to keep track of "potentially unstable"
satisfaction results.
@@ -1845,21 +1845,69 @@ static bool satisfying_constraint;
static GTY((deletable)) vec<tree, va_gc> *failed_type_completions;
+/* A map of where types were found to be incomplete in SFINAE context, for
+ warning if they are later completed. */
+
+static GTY((cache)) hash_map<tree, location_t, decl_location_traits> *failed_completions_map;
+
/* Called whenever a type completion (or return type deduction) failure occurs
that definitely affects the meaning of the program, by e.g. inducing
substitution failure. */
void
-note_failed_type_completion_for_satisfaction (tree t)
+note_failed_type_completion (tree t, tsubst_flags_t complain)
{
+ if (dependent_template_arg_p (t))
+ return;
+
+ gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t))
+ || (DECL_P (t) && undeduced_auto_decl (t)));
+
if (satisfying_constraint)
+ vec_safe_push (failed_type_completions, t);
+
+ if (TYPE_P (t))
{
- gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t))
- || (DECL_P (t) && undeduced_auto_decl (t)));
- vec_safe_push (failed_type_completions, t);
+ if (!CLASS_TYPE_P (t))
+ return;
+ t = TYPE_MAIN_DECL (t);
+ }
+ if (!(complain & tf_error)
+ && warning_enabled_at (DECL_SOURCE_LOCATION (t),
+ OPT_Wsfinae_incomplete_))
+ {
+ if (warn_sfinae_incomplete > 1)
+ {
+ if (TREE_CODE (t) == TYPE_DECL)
+ warning (OPT_Wsfinae_incomplete_,
+ "failed to complete %qT in SFINAE context", TREE_TYPE (t));
+ else
+ warning (OPT_Wsfinae_incomplete_,
+ "failed to deduce %qD in SFINAE context", t);
+ }
+ if (!failed_completions_map)
+ failed_completions_map
+ = hash_map<tree, location_t, decl_location_traits>::create_ggc ();
+ failed_completions_map->put (t, input_location);
}
}
+/* If T was previously found to be incomplete in SFINAE context, return the
+ location where that happened, otherwise UNKNOWN_LOCATION. */
+
+location_t
+failed_completion_location (tree t)
+{
+ if (failed_completions_map)
+ {
+ if (TYPE_P (t))
+ t = TYPE_MAIN_DECL (t);
+ if (location_t *p = failed_completions_map->get (t))
+ return *p;
+ }
+ return UNKNOWN_LOCATION;
+}
+
/* Returns true if the range [BEGIN, END) of elements within the
failed_type_completions vector contains a complete type (or a
declaration with a non-placeholder return type). */
@@ -2704,6 +2752,8 @@ satisfy_declaration_constraints (tree t, sat_info info)
static tree
satisfy_declaration_constraints (tree t, tree args, sat_info info)
{
+ tree orig_args = args;
+
/* Update the declaration for diagnostics. */
info.in_decl = t;
@@ -2732,7 +2782,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
tree result = boolean_true_node;
if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ()))
{
- if (!push_tinst_level (t, args))
+ if (!push_tinst_level (t, orig_args))
return result;
tree pattern = DECL_TEMPLATE_RESULT (t);
push_to_top_level ();
@@ -3098,6 +3148,9 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_IS_CONVERTIBLE:
inform (loc, " %qT is not convertible from %qE", t2, t1);
break;
+ case CPTK_IS_DESTRUCTIBLE:
+ inform (loc, " %qT is not destructible", t1);
+ break;
case CPTK_IS_EMPTY:
inform (loc, " %qT is not an empty class", t1);
break;
@@ -3143,6 +3196,9 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_IS_NOTHROW_CONVERTIBLE:
inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
break;
+ case CPTK_IS_NOTHROW_DESTRUCTIBLE:
+ inform (loc, " %qT is not nothrow destructible", t1);
+ break;
case CPTK_IS_NOTHROW_INVOCABLE:
if (!t2)
inform (loc, " %qT is not nothrow invocable", t1);
@@ -3192,6 +3248,9 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_IS_TRIVIALLY_COPYABLE:
inform (loc, " %qT is not trivially copyable", t1);
break;
+ case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
+ inform (loc, " %qT is not trivially destructible", t1);
+ break;
case CPTK_IS_UNBOUNDED_ARRAY:
inform (loc, " %qT is not an unbounded array", t1);
break;
@@ -3207,6 +3266,9 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_RANK:
inform (loc, " %qT cannot yield a rank", t1);
break;
+ case CPTK_TYPE_ORDER:
+ 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 "
"object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index f2b126c..d0cfd2e 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -860,10 +860,17 @@ cp_contract_assertion_p (const_tree attr)
void
remove_contract_attributes (tree fndecl)
{
+ if (!flag_contracts)
+ return;
+
tree list = NULL_TREE;
for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
if (!cxx_contract_attribute_p (p))
- list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list);
+ {
+ tree nl = copy_node (p);
+ TREE_CHAIN (nl) = list;
+ list = nl;
+ }
DECL_ATTRIBUTES (fndecl) = nreverse (list);
}
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index b92d09f..52cc186 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -191,8 +191,87 @@ static bool coro_promise_type_found_p (tree, location_t);
just syntactic sugar for a co_await).
We defer the analysis and transformation until template expansion is
- complete so that we have complete types at that time. */
+ complete so that we have complete types at that time.
+ ---------------------------------------------------------------------------
+
+ Coroutine state, and responsibility for its release.
+
+ As noted above, a coroutine has some state that persists across suspensions.
+
+ The state has two components:
+ * State that is specified by the standard and persists for the entire
+ life of the coroutine.
+ * Local state that is constructed/destructed as scopes in the original
+ function body are entered/exited. The destruction of local state is
+ always the responsibility of the body code.
+
+ The persistent state (and the overall storage for the state) must be
+ managed in two places:
+ * The ramp function (which allocates and builds this - and can, in some
+ cases, be responsible for destroying it)
+ * The re-written function body which can destroy it when that body
+ completes its final suspend - or when the handle.destroy () is called.
+
+ In all cases the ramp holds responsibility for constructing the standard-
+ mandated persistent state.
+
+ There are four ways in which the ramp might be re-entered after starting
+ the function body:
+ A The body could suspend (one might expect that to be the 'normal' case
+ for most coroutines).
+ B The body might complete either synchronously or via continuations.
+ C An exception might be thrown during the setup of the initial await
+ expression, before the initial awaiter resumes.
+ D An exception might be processed by promise.unhandled_exception () and
+ that, in turn, might re-throw it (or throw something else). In this
+ case, the coroutine is considered suspended at the final suspension
+ point.
+
+ Until the ramp return value has been constructed, the ramp is considered
+ to have a use of the state.
+
+ To manage these interacting conditions we allocate a reference counter
+ for the frame state. This is initialised to 1 by the ramp as part of its
+ startup (note that failures/exceptions in the startup code are handled
+ locally to the ramp).
+
+ When the body returns (either normally, or by exception) the ramp releases
+ its use.
+
+ Once the rewritten coroutine body is started, the body is considered to
+ have a use of the frame. This use (potentially) needs to be released if
+ an exception is thrown from the body. We implement this using an eh-only
+ cleanup around the initial await and function body. If we have the case
+ D above, then we do not release the use.
+
+ In case:
+
+ A, typically the ramp would be re-entered with the body holding a use,
+ and therefore the ramp should not destroy the state.
+
+ B, both the body and ramp will have released their uses, and the ramp
+ should destroy the state.
+
+ C, we must arrange for the body to release its use, because we require
+ the ramp to cleanup in this circumstance.
+
+ D is an outlier, since the responsibility for destruction of the state
+ now rests with the user's code (via a handle.destroy() call).
+
+ NOTE: In the case that the body has never suspended before such an
+ exception occurs, the only reasonable way for the user code to obtain the
+ necessary handle is if unhandled_exception() throws the handle or some
+ object that contains the handle. That is outside of the designs here -
+ if the user code might need this corner-case, then such provision will
+ have to be made.
+
+ In the ramp, we implement destruction for the persistent frame state by
+ means of cleanups. These are run conditionally when the reference count
+ is 0 signalling that both the body and the ramp have completed.
+
+ In the body, once we pass the final suspend, then we test the use and
+ delete the state if the use is 0. */
/* The state that we collect during parsing (and template expansion) for
a coroutine. */
@@ -206,11 +285,10 @@ struct GTY((for_user)) coroutine_info
tree traits_type; /* The cached traits type for this function. */
tree handle_type; /* The cached coroutine handle for this function. */
tree self_h_proxy; /* A handle instance that is used as the proxy for the
- one that will eventually be allocated in the coroutine
- frame. */
+ one that will eventually be built in lowering. */
tree promise_proxy; /* Likewise, a proxy promise instance. */
- tree from_address; /* handle_type from_address function. */
- tree return_void; /* The expression for p.return_void() if it exists. */
+ tree from_address; /* handle_type from_address() function. */
+ tree return_void; /* The expression for p.return_void(), if it exists. */
location_t first_coro_keyword; /* The location of the keyword that made this
function into a coroutine. */
@@ -348,6 +426,7 @@ static GTY(()) tree coro_resume_index_id;
static GTY(()) tree coro_self_handle_id;
static GTY(()) tree coro_actor_continue_id;
static GTY(()) tree coro_frame_i_a_r_c_id;
+static GTY(()) tree coro_frame_refcount_id;
/* Create the identifiers used by the coroutines library interfaces and
the implementation frame state. */
@@ -385,6 +464,7 @@ coro_init_identifiers ()
coro_resume_index_id = get_identifier ("_Coro_resume_index");
coro_self_handle_id = get_identifier ("_Coro_self_handle");
coro_actor_continue_id = get_identifier ("_Coro_actor_continue");
+ coro_frame_refcount_id = get_identifier ("_Coro_frame_refcount");
}
/* Trees we only need to set up once. */
@@ -1277,8 +1357,14 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind,
if (TREE_CODE (o_type) != RECORD_TYPE)
{
- error_at (loc, "awaitable type %qT is not a structure",
- o_type);
+ if (suspend_kind == FINAL_SUSPEND_POINT)
+ error_at (loc, "%qs awaitable type %qT is not a structure",
+ "final_suspend()", o_type);
+ else if (suspend_kind == INITIAL_SUSPEND_POINT)
+ error_at (loc, "%qs awaitable type %qT is not a structure",
+ "initial_suspend()", o_type);
+ else
+ error_at (loc, "awaitable type %qT is not a structure", o_type);
return error_mark_node;
}
@@ -1461,6 +1547,12 @@ finish_co_await_expr (location_t kw, tree expr)
if (!expr || error_operand_p (expr))
return error_mark_node;
+ if (cp_unevaluated_operand)
+ {
+ error_at (kw, "%qs cannot be used in an unevaluated context","co_await");
+ return error_mark_node;
+ }
+
if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
"co_await"))
return error_mark_node;
@@ -1541,6 +1633,12 @@ finish_co_yield_expr (location_t kw, tree expr)
if (!expr || error_operand_p (expr))
return error_mark_node;
+ if (cp_unevaluated_operand)
+ {
+ error_at (kw, "%qs cannot be used in an unevaluated context","co_yield");
+ return error_mark_node;
+ }
+
/* Check the general requirements and simple syntax errors. */
if (!coro_common_keyword_context_valid_p (current_function_decl, kw,
"co_yield"))
@@ -1852,21 +1950,6 @@ coro_build_frame_access_expr (tree coro_ref, tree member_id, bool preserve_ref,
return expr;
}
-/* Helpers to build EXPR_STMT and void-cast EXPR_STMT, common ops. */
-
-static tree
-coro_build_expr_stmt (tree expr, location_t loc)
-{
- return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr));
-}
-
-static tree
-coro_build_cvt_void_expr_stmt (tree expr, location_t loc)
-{
- tree t = build1 (CONVERT_EXPR, void_type_node, expr);
- return coro_build_expr_stmt (t, loc);
-}
-
/* Helpers to build an artificial var, with location LOC, NAME and TYPE, in
CTX, and with initializer INIT. */
@@ -1979,12 +2062,13 @@ struct coro_aw_data
tree coro_fp; /* Frame pointer var. */
tree resume_idx; /* This is the index var in the frame. */
tree i_a_r_c; /* initial suspend await_resume() was called if true. */
- tree self_h; /* This is a handle to the current coro (frame var). */
tree cleanup; /* This is where to go once we complete local destroy. */
tree cororet; /* This is where to go if we suspend. */
tree corocont; /* This is where to go if we continue. */
tree dispatch; /* This is where we go if we restart the dispatch. */
tree conthand; /* This is the handle for a continuation. */
+ tree handle_type; /* Handle type for this coroutine... */
+ tree hfa_m; /* ... and handle.from_address() for this. */
unsigned index; /* This is our current resume index. */
};
@@ -2042,8 +2126,10 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d)
tree awaiter_calls = TREE_OPERAND (saved_co_await, 3);
tree source = TREE_OPERAND (saved_co_await, 4);
- bool is_final = (source
- && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT);
+ bool is_final
+ = (source && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT);
+ bool is_initial
+ = (source && TREE_INT_CST_LOW (source) == (int) INITIAL_SUSPEND_POINT);
/* Build labels for the destinations of the control flow when we are resuming
or destroying. */
@@ -2100,6 +2186,18 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d)
tree suspend = TREE_VEC_ELT (awaiter_calls, 1); /* await_suspend(). */
tree susp_type = TREE_TYPE (suspend);
+ tree susp_call = suspend;
+ if (TREE_CODE (suspend) == TARGET_EXPR)
+ susp_call = TARGET_EXPR_INITIAL (suspend);
+ gcc_checking_assert (TREE_CODE (susp_call) == CALL_EXPR);
+ tree dummy_ch = build_dummy_object (data->handle_type);
+ r = fold_convert (build_pointer_type (void_type_node), data->coro_fp);
+ vec<tree, va_gc> *args = make_tree_vector_single (r);
+ tree hfa = cp_fold_rvalue (
+ build_new_method_call (dummy_ch, data->hfa_m, &args, NULL_TREE,
+ LOOKUP_NORMAL, NULL, tf_warning_or_error));
+ release_tree_vector (args);
+ CALL_EXPR_ARG (susp_call, call_expr_nargs (susp_call) - 1) = hfa;
bool is_cont = false;
/* NOTE: final suspend can't resume; the "resume" label in that case
@@ -2171,6 +2269,13 @@ expand_one_await_expression (tree *expr, tree *await_expr, void *d)
/* Resume point. */
add_stmt (build_stmt (loc, LABEL_EXPR, resume_label));
+ if (is_initial && data->i_a_r_c)
+ {
+ r = cp_build_modify_expr (loc, data->i_a_r_c, NOP_EXPR, boolean_true_node,
+ tf_warning_or_error);
+ finish_expr_stmt (r);
+ }
+
/* This will produce the value (if one is provided) from the co_await
expression. */
tree resume_call = TREE_VEC_ELT (awaiter_calls, 2); /* await_resume(). */
@@ -2412,6 +2517,11 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
bool spf = start_preparsed_function (actor, NULL_TREE, SF_PRE_PARSED);
gcc_checking_assert (spf);
gcc_checking_assert (cfun && current_function_decl && TREE_STATIC (actor));
+ if (flag_exceptions)
+ /* We, unconditionally, add a try/catch and rethrow.
+ TODO: Determine if the combination of initial suspend and the original
+ body cannot throw, and elide these additions. */
+ cp_function_chain->can_throw = true;
tree stmt = begin_function_body ();
tree actor_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
@@ -2558,8 +2668,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
/* Finish the resume dispatcher. */
finish_switch_stmt (dispatcher);
- finish_else_clause (lsb_if);
+ finish_else_clause (lsb_if);
finish_if_stmt (lsb_if);
/* If we reach here then we've hit UB. */
@@ -2569,22 +2679,16 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
/* Now we start building the rewritten function body. */
add_stmt (build_stmt (loc, LABEL_EXPR, actor_begin_label));
- /* actor's coroutine 'self handle'. */
- tree ash = coro_build_frame_access_expr (actor_frame, coro_self_handle_id,
- false, tf_warning_or_error);
- /* So construct the self-handle from the frame address. */
- tree hfa_m = get_coroutine_from_address (orig);
- /* Should have been set earlier by coro_promise_type_found_p. */
- gcc_assert (hfa_m);
-
- tree r = build1 (CONVERT_EXPR, build_pointer_type (void_type_node), actor_fp);
- vec<tree, va_gc> *args = make_tree_vector_single (r);
- tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL,
- NULL, tf_warning_or_error);
- r = cp_build_init_expr (ash, hfa);
- r = coro_build_cvt_void_expr_stmt (r, loc);
- add_stmt (r);
- release_tree_vector (args);
+ tree i_a_r_c = NULL_TREE;
+ if (flag_exceptions)
+ {
+ i_a_r_c
+ = coro_build_frame_access_expr (actor_frame, coro_frame_i_a_r_c_id,
+ false, tf_warning_or_error);
+ tree m = cp_build_modify_expr (loc, i_a_r_c, NOP_EXPR,
+ boolean_false_node, tf_warning_or_error);
+ finish_expr_stmt (m);
+ }
/* Now we know the real promise, and enough about the frame layout to
decide where to put things. */
@@ -2599,69 +2703,74 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
/* Add in our function body with the co_returns rewritten to final form. */
add_stmt (fnbody);
- /* now do the tail of the function. */
+ /* We are done with the frame, but if the ramp still has a hold on it
+ we should not cleanup. So decrement the refcount and then return to
+ the ramp if it is > 0. */
+ tree coro_frame_refcount
+ = coro_build_frame_access_expr (actor_frame, coro_frame_refcount_id,
+ false, tf_warning_or_error);
+ tree released = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node,
+ coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 1));
+ tree r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,
+ tf_warning_or_error);
+ finish_expr_stmt (r);
+ tree cond = build2_loc (loc, NE_EXPR, short_unsigned_type_node,
+ coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 0));
+ tree ramp_cu_if = begin_if_stmt ();
+ finish_if_stmt_cond (cond, ramp_cu_if);
+ finish_return_stmt (NULL_TREE);
+ finish_then_clause (ramp_cu_if);
+ finish_if_stmt (ramp_cu_if);
+
+ /* Otherwise, do the tail of the function; first cleanups. */
r = build_stmt (loc, LABEL_EXPR, del_promise_label);
add_stmt (r);
- /* Destructors for the things we built explicitly. */
+ /* Destructors for the things we built explicitly.
+ promise... */
if (tree c = cxx_maybe_build_cleanup (promise_proxy, tf_warning_or_error))
- add_stmt (c);
-
- tree del_frame_label
- = create_named_label_with_ctx (loc, "coro.delete.frame", actor);
- r = build_stmt (loc, LABEL_EXPR, del_frame_label);
- add_stmt (r);
-
- /* Here deallocate the frame (if we allocated it), which we will have at
- present. */
- tree fnf2_x
- = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id,
- false, tf_warning_or_error);
+ finish_expr_stmt (c);
- tree need_free_if = begin_if_stmt ();
- fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x);
- tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node);
- finish_if_stmt_cond (cmp, need_free_if);
+ /* Argument copies ... */
while (!param_dtor_list->is_empty ())
{
tree parm_id = param_dtor_list->pop ();
tree a = coro_build_frame_access_expr (actor_frame, parm_id, false,
tf_warning_or_error);
if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error))
- add_stmt (dtor);
+ finish_expr_stmt (dtor);
}
+ /* Here deallocate the frame (if we allocated it), which we will have at
+ present. */
+ tree fnf2_x
+ = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id,
+ false, tf_warning_or_error);
+ tree need_free_if = begin_if_stmt ();
+ finish_if_stmt_cond (fnf2_x, need_free_if);
+
/* Build the frame DTOR. */
tree del_coro_fr
= build_coroutine_frame_delete_expr (actor_fp, frame_size,
promise_type, loc);
finish_expr_stmt (del_coro_fr);
finish_then_clause (need_free_if);
- tree scope = IF_SCOPE (need_free_if);
- IF_SCOPE (need_free_if) = NULL;
- r = do_poplevel (scope);
- add_stmt (r);
+ finish_if_stmt (need_free_if);
- /* done. */
- r = build_stmt (loc, RETURN_EXPR, NULL);
- suppress_warning (r); /* We don't want a warning about this. */
- r = maybe_cleanup_point_expr_void (r);
- add_stmt (r);
+ /* Done. */
+ finish_return_stmt (NULL_TREE);
/* This is the suspend return point. */
- r = build_stmt (loc, LABEL_EXPR, ret_label);
- add_stmt (r);
+ add_stmt (build_stmt (loc, LABEL_EXPR, ret_label));
- r = build_stmt (loc, RETURN_EXPR, NULL);
- suppress_warning (r); /* We don't want a warning about this. */
- r = maybe_cleanup_point_expr_void (r);
- add_stmt (r);
+ finish_return_stmt (NULL_TREE);
/* This is the 'continuation' return point. For such a case we have a coro
handle (from the await_suspend() call) and we want handle.resume() to
execute as a tailcall allowing arbitrary chaining of coroutines. */
- r = build_stmt (loc, LABEL_EXPR, continue_label);
- add_stmt (r);
+ add_stmt (build_stmt (loc, LABEL_EXPR, continue_label));
/* Should have been set earlier by the coro_initialized code. */
gcc_assert (void_coro_handle_address);
@@ -2678,19 +2787,25 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
we must tail call them. However, some targets do not support indirect
tail calls to arbitrary callees. See PR94359. */
CALL_EXPR_TAILCALL (resume) = true;
- resume = coro_build_cvt_void_expr_stmt (resume, loc);
- add_stmt (resume);
+ finish_expr_stmt (resume);
r = build_stmt (loc, RETURN_EXPR, NULL);
gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r);
add_stmt (r);
+ /* How to construct the handle for this coroutine from the frame address. */
+ tree hfa_m = get_coroutine_from_address (orig);
+ /* Should have been set earlier by coro_promise_type_found_p. */
+ gcc_assert (hfa_m);
+ tree handle_type = TREE_TYPE (get_coroutine_self_handle_proxy (orig));
+
/* We've now rewritten the tree and added the initial and final
co_awaits. Now pass over the tree and expand the co_awaits. */
- coro_aw_data data = {actor, actor_fp, resume_idx_var, NULL_TREE,
- ash, del_promise_label, ret_label,
- continue_label, restart_dispatch_label, continuation, 2};
+ coro_aw_data data = {actor, actor_fp, resume_idx_var, i_a_r_c,
+ del_promise_label, ret_label,
+ continue_label, restart_dispatch_label, continuation,
+ handle_type, hfa_m, 2};
cp_walk_tree (&actor_body, await_statement_expander, &data, NULL);
BIND_EXPR_BODY (actor_bind) = pop_stmt_list (actor_body);
@@ -2882,8 +2997,8 @@ find_any_await (tree *stmt, int *dosub, void *d)
if (TREE_CODE (*stmt) == CO_AWAIT_EXPR)
{
*dosub = 0; /* We don't need to consider this any further. */
- tree **p = (tree **) d;
- *p = stmt;
+ if (d)
+ *(tree **)d = stmt;
return *stmt;
}
return NULL_TREE;
@@ -3133,7 +3248,9 @@ flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted,
bool already_present = promoted->add (var);
gcc_checking_assert (!already_present);
tree inner = TARGET_EXPR_INITIAL (init);
- gcc_checking_assert (TREE_CODE (inner) != COND_EXPR);
+ gcc_checking_assert
+ (TREE_CODE (inner) != COND_EXPR
+ || !cp_walk_tree (&inner, find_any_await, nullptr, nullptr));
init = cp_build_modify_expr (input_location, var, INIT_EXPR, init,
tf_warning_or_error);
/* Simplify for the case that we have an init containing the temp
@@ -3438,7 +3555,8 @@ maybe_promote_temps (tree *stmt, void *d)
return cp_walk_tree (stmt, register_awaits, d, &visited);
}
-/* Lightweight callback to determine two key factors:
+/* Relatively lightweight callback to do initial assessment:
+ 0) Rewrite some await expressions.
1) If the statement/expression contains any await expressions.
2) If the statement/expression potentially requires a re-write to handle
TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion
@@ -3455,6 +3573,39 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d)
switch (TREE_CODE (*stmt))
{
default: return NULL_TREE;
+ case CALL_EXPR:
+ {
+ tree fn = cp_get_callee_fndecl_nofold (*stmt);
+ /* Special-cases where we want to re-write await expressions to some
+ other value before they are otherwise processed. */
+ if (fn && DECL_IS_BUILTIN_CONSTANT_P (fn))
+ {
+ gcc_checking_assert (call_expr_nargs (*stmt) == 1);
+ tree expr = CALL_EXPR_ARG (*stmt, 0);
+ if (cp_walk_tree (&expr, find_any_await, nullptr, NULL))
+ {
+ if (TREE_CONSTANT (maybe_constant_value (expr)))
+ *stmt = integer_one_node;
+ else
+ *stmt = integer_zero_node;
+ }
+ *do_subtree = 0;
+ }
+ else if (!fn && CALL_EXPR_IFN (*stmt) == IFN_ASSUME)
+ {
+ tree expr = CALL_EXPR_ARG (*stmt, 0);
+ if (TREE_SIDE_EFFECTS (expr))
+ {
+ location_t loc_e = cp_expr_location (expr);
+ location_t loc_s = cp_expr_location (*stmt);
+ location_t loc_n = make_location (loc_e, loc_s, loc_s);
+ warning_at (loc_n, OPT_Wattributes,"assumption ignored"
+ " because it contains an await-expression");
+ *stmt = build_empty_stmt (loc_n);
+ }
+ }
+ }
+ break;
case CO_YIELD_EXPR:
/* co_yield is syntactic sugar, re-write it to co_await. */
*stmt = TREE_OPERAND (*stmt, 1);
@@ -4045,12 +4196,14 @@ rewrite_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d)
}
/* Build up a set of info that determines how each param copy will be
- handled. */
+ handled. We store this in a hash map so that we can access it from
+ a tree walk callback that re-writes the original parameters to their
+ copies. */
-static void
-analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses)
+void
+cp_coroutine_transform::analyze_fn_parms ()
{
- if (!DECL_ARGUMENTS (orig))
+ if (!DECL_ARGUMENTS (orig_fn_decl))
return;
/* Build a hash map with an entry for each param.
@@ -4060,19 +4213,19 @@ analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses)
Then a tree list of the uses.
The second two entries start out empty - and only get populated
when we see uses. */
- bool lambda_p = LAMBDA_FUNCTION_P (orig);
+ bool lambda_p = LAMBDA_FUNCTION_P (orig_fn_decl);
/* Count the param copies from 1 as per the std. */
unsigned parm_num = 1;
- for (tree arg = DECL_ARGUMENTS (orig); arg != NULL;
+ for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL;
++parm_num, arg = DECL_CHAIN (arg))
{
bool existed;
- param_info &parm = param_uses->get_or_insert (arg, &existed);
+ param_info &parm = param_uses.get_or_insert (arg, &existed);
gcc_checking_assert (!existed);
parm.body_uses = NULL;
tree actual_type = TREE_TYPE (arg);
- actual_type = complete_type_or_else (actual_type, orig);
+ actual_type = complete_type_or_else (actual_type, orig_fn_decl);
if (actual_type == NULL_TREE)
actual_type = error_mark_node;
parm.orig_type = actual_type;
@@ -4106,17 +4259,7 @@ analyze_fn_parms (tree orig, hash_map<tree, param_info> *param_uses)
}
parm.field_id = name;
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type))
- {
- char *buf = xasprintf ("_Coro_q%u_%s_live", parm_num,
- DECL_NAME (arg) ? IDENTIFIER_POINTER (name)
- : "__unnamed");
- parm.guard_var
- = coro_build_artificial_var (UNKNOWN_LOCATION, get_identifier (buf),
- boolean_type_node, orig,
- boolean_false_node);
- free (buf);
- parm.trivial_dtor = false;
- }
+ parm.trivial_dtor = false;
else
parm.trivial_dtor = true;
}
@@ -4307,8 +4450,7 @@ cp_coroutine_transform::wrap_original_function_body ()
{
/* Avoid the code here attaching a location that makes the debugger jump. */
iloc_sentinel stable_input_loc (fn_start);
- location_t loc = UNKNOWN_LOCATION;
- input_location = loc;
+ location_t loc = fn_start;
/* This will be our new outer scope. */
tree update_body
@@ -4356,7 +4498,6 @@ cp_coroutine_transform::wrap_original_function_body ()
/* Wrap the function body in a try {} catch (...) {} block, if exceptions
are enabled. */
tree var_list = NULL_TREE;
- tree initial_await = build_init_or_final_await (fn_start, false);
/* [stmt.return.coroutine] / 3
If p.return_void() is a valid expression, flowing off the end of a
@@ -4395,16 +4536,6 @@ cp_coroutine_transform::wrap_original_function_body ()
var_list = promise;
add_decl_expr (promise);
- /* We need a handle to this coroutine, which is passed to every
- await_suspend(). This was created on demand when parsing we now link it
- into our scope. */
- var = get_coroutine_self_handle_proxy (orig_fn_decl);
- DECL_CONTEXT (var) = orig_fn_decl;
- DECL_SOURCE_LOCATION (var) = loc;
- DECL_CHAIN (var) = var_list;
- var_list = var;
- add_decl_expr (var);
-
/* If we have function parms, then these will be copied to the coroutine
frame as per [dcl.fct.def.coroutine] / 13.
Here, we create a local (proxy) variable for each parm, since the original
@@ -4448,27 +4579,44 @@ cp_coroutine_transform::wrap_original_function_body ()
var_list = resume_idx_var;
add_decl_expr (resume_idx_var);
+ tree coro_frame_refcount
+ = coro_build_artificial_var (loc, coro_frame_refcount_id,
+ short_unsigned_type_node, orig_fn_decl,
+ NULL_TREE);
+ DECL_CHAIN (coro_frame_refcount) = var_list;
+ var_list = coro_frame_refcount;
+ add_decl_expr (coro_frame_refcount);
+
/* If the coroutine has a frame that needs to be freed, this will be set by
the ramp. */
- var = coro_build_artificial_var (fn_start, coro_frame_needs_free_id,
+ var = coro_build_artificial_var (loc, coro_frame_needs_free_id,
boolean_type_node, orig_fn_decl, NULL_TREE);
DECL_CHAIN (var) = var_list;
var_list = var;
add_decl_expr (var);
+ /* We consider that the body has a use of the frame once we start to process
+ the initial suspend expression. (the use might be relinquished if we
+ encounter an exception before the body is finished). */
+ tree body_use
+ = build2_loc (loc, PLUS_EXPR, short_unsigned_type_node, coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 1));
+ body_use = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, body_use,
+ tf_warning_or_error);
+ finish_expr_stmt (body_use);
if (flag_exceptions)
{
/* Build promise.unhandled_exception(); */
tree ueh
= coro_build_promise_expression (orig_fn_decl, promise,
coro_unhandled_exception_identifier,
- fn_start, NULL, /*musthave=*/true);
+ loc, NULL, /*musthave=*/true);
/* Create and initialize the initial-await-resume-called variable per
[dcl.fct.def.coroutine] / 5.3. */
tree i_a_r_c
= coro_build_artificial_var (loc, coro_frame_i_a_r_c_id,
boolean_type_node, orig_fn_decl,
- boolean_false_node);
+ NULL_TREE);
DECL_CHAIN (i_a_r_c) = var_list;
var_list = i_a_r_c;
add_decl_expr (i_a_r_c);
@@ -4476,34 +4624,28 @@ cp_coroutine_transform::wrap_original_function_body ()
tree tcb = build_stmt (loc, TRY_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (tcb);
TRY_STMTS (tcb) = push_stmt_list ();
- if (initial_await != error_mark_node)
- {
- /* Build a compound expression that sets the
- initial-await-resume-called variable true and then calls the
- initial suspend expression await resume.
- In the case that the user decides to make the initial await
- await_resume() return a value, we need to discard it and, it is
- a reference type, look past the indirection. */
- if (INDIRECT_REF_P (initial_await))
- initial_await = TREE_OPERAND (initial_await, 0);
- /* In the case that the initial_await returns a target expression
- we might need to look through that to update the await expr. */
- tree iaw = initial_await;
- if (TREE_CODE (iaw) == TARGET_EXPR)
- iaw = TARGET_EXPR_INITIAL (iaw);
- gcc_checking_assert (TREE_CODE (iaw) == CO_AWAIT_EXPR);
- tree vec = TREE_OPERAND (iaw, 3);
- tree aw_r = TREE_VEC_ELT (vec, 2);
- aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error);
- tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c,
- boolean_true_node);
- aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error);
- TREE_VEC_ELT (vec, 2) = aw_r;
- }
+ /* We need a new scope to handle the cleanup for the ramp use that is
+ needed for exceptions. */
+ tree except_scope = begin_compound_stmt (0);
+ current_binding_level->artificial = 1;
+ tree release
+ = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node,
+ coro_frame_refcount, build_int_cst (short_unsigned_type_node, 1));
+ release = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR,
+ release, tf_warning_or_error);
+ /* Once we pass the initial await resume, the cleanup rules on exception
+ change so that the responsibility lies with the caller. */
+ release = build3 (COND_EXPR, void_type_node, i_a_r_c,
+ build_empty_stmt (loc), release);
+ push_cleanup (NULL_TREE, release, /*ehonly*/true);
/* Add the initial await to the start of the user-authored function. */
finish_expr_stmt (initial_await);
+ /* End the scope that handles the remove of frame-use on exception. */
+ finish_compound_stmt (except_scope);
+
/* Append the original function body. */
add_stmt (coroutine_body);
+
if (return_void)
add_stmt (return_void);
TRY_STMTS (tcb) = pop_stmt_list (TRY_STMTS (tcb));
@@ -4548,9 +4690,9 @@ cp_coroutine_transform::wrap_original_function_body ()
tree ueh_meth
= lookup_promise_method (orig_fn_decl,
coro_unhandled_exception_identifier,
- fn_start, /*musthave=*/false);
+ loc, /*musthave=*/false);
if (!ueh_meth || ueh_meth == error_mark_node)
- warning_at (fn_start, 0, "no member named %qE in %qT",
+ warning_at (loc, 0, "no member named %qE in %qT",
coro_unhandled_exception_identifier,
get_coroutine_promise_type (orig_fn_decl));
}
@@ -4563,6 +4705,10 @@ cp_coroutine_transform::wrap_original_function_body ()
add_stmt (return_void);
}
+ /* We are now doing actions associated with the end of the function, so
+ point to the closing brace. */
+ input_location = loc = fn_end;
+
/* co_return branches to the final_suspend label, so declare that now. */
fs_label
= create_named_label_with_ctx (loc, "final.suspend", NULL_TREE);
@@ -4574,7 +4720,8 @@ cp_coroutine_transform::wrap_original_function_body ()
zero_resume = build2_loc (loc, MODIFY_EXPR, act_des_fn_ptr_type,
resume_fn_ptr, zero_resume);
finish_expr_stmt (zero_resume);
- finish_expr_stmt (build_init_or_final_await (fn_start, true));
+ finish_expr_stmt (final_await);
+
BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body));
BIND_EXPR_VARS (update_body) = nreverse (var_list);
BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body);
@@ -4883,47 +5030,6 @@ cp_coroutine_transform::build_ramp_function ()
coro_fp = pushdecl (coro_fp);
add_decl_expr (coro_fp);
- tree coro_promise_live = NULL_TREE;
- tree coro_gro_live = NULL_TREE;
- if (flag_exceptions)
- {
- /* Signal that we need to clean up the promise object on exception. */
- coro_promise_live
- = coro_build_and_push_artificial_var (loc, "_Coro_promise_live",
- boolean_type_node, orig_fn_decl,
- boolean_false_node);
-
- /* When the get-return-object is in the RETURN slot, we need to arrange
- for cleanup on exception. */
- coro_gro_live
- = coro_build_and_push_artificial_var (loc, "_Coro_gro_live",
- boolean_type_node, orig_fn_decl,
- boolean_false_node);
-
- /* To signal that we need to cleanup copied function args. */
- if (DECL_ARGUMENTS (orig_fn_decl))
- for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL;
- arg = DECL_CHAIN (arg))
- {
- param_info *parm_i = param_uses.get (arg);
- if (parm_i->trivial_dtor)
- continue;
- parm_i->guard_var = pushdecl (parm_i->guard_var);
- add_decl_expr (parm_i->guard_var);
- }
- }
-
- /* deref the frame pointer, to use in member access code. */
- tree deref_fp
- = cp_build_indirect_ref (loc, coro_fp, RO_UNARY_STAR,
- tf_warning_or_error);
- tree frame_needs_free
- = coro_build_and_push_artificial_var_with_dve (loc,
- coro_frame_needs_free_id,
- boolean_type_node,
- orig_fn_decl, NULL_TREE,
- deref_fp);
-
/* Build the frame. */
/* The CO_FRAME internal function is a mechanism to allow the middle end
@@ -4967,37 +5073,35 @@ cp_coroutine_transform::build_ramp_function ()
finish_if_stmt (if_stmt);
}
+ /* Dereference the frame pointer, to use in member access code. */
+ tree deref_fp
+ = cp_build_indirect_ref (loc, coro_fp, RO_UNARY_STAR, tf_warning_or_error);
+
/* For now, once allocation has succeeded we always assume that this needs
destruction, there's no impl. for frame allocation elision. */
- r = cp_build_init_expr (frame_needs_free, boolean_true_node);
- finish_expr_stmt (r);
-
- /* Set up the promise. */
- tree p
- = coro_build_and_push_artificial_var_with_dve (loc, coro_promise_id,
- promise_type, orig_fn_decl,
- NULL_TREE, deref_fp);
+ tree frame_needs_free
+ = coro_build_and_push_artificial_var_with_dve (loc,
+ coro_frame_needs_free_id,
+ boolean_type_node,
+ orig_fn_decl,
+ boolean_true_node,
+ deref_fp);
+ /* Although it appears to be unused here the frame entry is needed and we
+ just set it true. */
+ TREE_USED (frame_needs_free) = true;
- /* Up to now any exception thrown will propagate directly to the caller.
- This is OK since the only source of such exceptions would be in allocation
- of the coroutine frame, and therefore the ramp will not have initialized
- any further state. From here, we will track state that needs explicit
- destruction in the case that promise or g.r.o setup fails or an exception
- is thrown from the initial suspend expression. */
- tree ramp_try_block = NULL_TREE;
- tree ramp_try_stmts = NULL_TREE;
- tree iarc_x = NULL_TREE;
- if (flag_exceptions)
- {
- iarc_x
- = coro_build_and_push_artificial_var_with_dve (loc,
- coro_frame_i_a_r_c_id,
- boolean_type_node,
- orig_fn_decl, NULL_TREE,
- deref_fp);
- ramp_try_block = begin_try_block ();
- ramp_try_stmts = begin_compound_stmt (BCS_TRY_BLOCK);
- }
+ tree coro_frame_refcount
+ = coro_build_and_push_artificial_var_with_dve (loc, coro_frame_refcount_id,
+ short_unsigned_type_node,
+ orig_fn_decl, NULL_TREE,
+ deref_fp);
+ /* Cleanup if both the ramp and the body have finished. */
+ tree cond
+ = build2_loc (loc, EQ_EXPR, short_unsigned_type_node, coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 0));
+ r = build3 (COND_EXPR, void_type_node, cond, delete_frame_call,
+ build_empty_stmt (loc));
+ push_cleanup (coro_fp, r, /*eh_only*/false);
/* Put the resumer and destroyer functions in. */
@@ -5069,24 +5173,34 @@ cp_coroutine_transform::build_ramp_function ()
tf_warning_or_error);
}
finish_expr_stmt (r);
+
+ /* Arrange for parm copies to be cleaned up when an exception is
+ thrown before initial await resume. */
if (!parm.trivial_dtor)
{
- param_dtor_list.safe_push (parm.field_id);
- /* Cleanup this frame copy on exception. */
parm.fr_copy_dtor
= cxx_maybe_build_cleanup (fld_idx, tf_warning_or_error);
- if (flag_exceptions)
+ if (parm.fr_copy_dtor && parm.fr_copy_dtor != error_mark_node)
{
- /* This var is now live. */
- r = build_modify_expr (loc, parm.guard_var,
- boolean_type_node, INIT_EXPR, loc,
- boolean_true_node, boolean_type_node);
- finish_expr_stmt (r);
+ param_dtor_list.safe_push (parm.field_id);
+ cond
+ = build2_loc (loc, EQ_EXPR, short_unsigned_type_node,
+ coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 0));
+ r = build3_loc (loc, COND_EXPR, void_type_node, cond,
+ parm.fr_copy_dtor, build_empty_stmt (loc));
+ push_cleanup (fld_idx, r, /*eh_only*/false);
}
}
}
}
+ /* Set up the promise. */
+ tree p
+ = coro_build_and_push_artificial_var_with_dve (loc, coro_promise_id,
+ promise_type, orig_fn_decl,
+ NULL_TREE, deref_fp);
+
if (type_build_ctor_call (promise_type))
{
/* Construct the promise object [dcl.fct.def.coroutine] / 5.7.
@@ -5120,11 +5234,16 @@ cp_coroutine_transform::build_ramp_function ()
finish_expr_stmt (r);
}
- tree promise_dtor = cxx_maybe_build_cleanup (p, tf_warning_or_error);;
- if (flag_exceptions && promise_dtor)
+ tree promise_dtor = cxx_maybe_build_cleanup (p, tf_warning_or_error);
+ /* If the promise is live, then run its dtor if that's available. */
+ if (promise_dtor && promise_dtor != error_mark_node)
{
- r = cp_build_init_expr (coro_promise_live, boolean_true_node);
- finish_expr_stmt (r);
+ cond = build2_loc (loc, EQ_EXPR, short_unsigned_type_node,
+ coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 0));
+ r = build3 (COND_EXPR, void_type_node, cond, promise_dtor,
+ build_empty_stmt (loc));
+ push_cleanup (p, r, /*eh_only*/false);
}
tree get_ro
@@ -5139,8 +5258,11 @@ cp_coroutine_transform::build_ramp_function ()
/* Check for a bad get return object type.
[dcl.fct.def.coroutine] / 7 requires:
The expression promise.get_return_object() is used to initialize the
- returned reference or prvalue result object ... */
- tree gro_type = TREE_TYPE (get_ro);
+ returned reference or prvalue result object ...
+ When we use a local to hold this, it is decltype(auto). */
+ tree gro_type
+ = finish_decltype_type (get_ro, /*id_expression_or_member_access_p*/false,
+ tf_warning_or_error);
if (VOID_TYPE_P (gro_type) && !void_ramp_p)
{
error_at (fn_start, "no viable conversion from %<void%> provided by"
@@ -5153,169 +5275,62 @@ cp_coroutine_transform::build_ramp_function ()
(loc, coro_resume_index_id, short_unsigned_type_node, orig_fn_decl,
build_zero_cst (short_unsigned_type_node), deref_fp);
- if (flag_exceptions && iarc_x)
- {
- r = cp_build_init_expr (iarc_x, boolean_false_node);
- finish_expr_stmt (r);
- }
-
- /* Used for return objects in the RESULT slot. */
- tree ret_val_dtor = NULL_TREE;
- tree retval = NULL_TREE;
+ /* We must manage the cleanups ourselves, with the exception of the g_r_o,
+ because the responsibility for them changes after the initial suspend.
+ However, any use of cxx_maybe_build_cleanup () in preceding code can
+ set the throwing_cleanup flag. */
+ cp_function_chain->throwing_cleanup = false;
/* [dcl.fct.def.coroutine] / 7
The expression promise.get_return_object() is used to initialize the
glvalue result or prvalue result object of a call to a coroutine. */
- /* We must manage the cleanups ourselves, because the responsibility for
- them changes after the initial suspend. However, any use of
- cxx_maybe_build_cleanup () can set the throwing_cleanup flag. */
- cp_function_chain->throwing_cleanup = false;
+ tree coro_gro = NULL_TREE;
if (void_ramp_p)
/* We still want to call the method, even if the result is unused. */
- r = get_ro;
+ finish_expr_stmt (get_ro);
else
{
- /* The initial section of finish_return_expr (). */
- bool no_warning;
- bool dangling;
- /* Without a relevant location, bad conversions in check_return_expr
- result in unusable diagnostics, since there is not even a mention
- of the relevant function. Here we carry out the first part of
- finish_return_expr(). */
- input_location = fn_start;
- r = check_return_expr (get_ro, &no_warning, &dangling);
- input_location = UNKNOWN_LOCATION;
- gcc_checking_assert (!dangling);
- /* Check for bad things. */
- if (!r || r == error_mark_node)
- return false;
- if (!aggregate_value_p (fn_return_type, orig_fn_decl)
- && TREE_CODE (r) == INIT_EXPR)
- {
- /* If fn_return_type doesn't need to be returned in memory, normally
- gimplify_return_expr redirects the INIT_EXPR to a temporary. But
- r isn't wrapped in the RETURN_EXPR, so we need to do the
- redirection here as well. See PR118874. */
- tree temp = create_temporary_var (fn_return_type);
- add_decl_expr (temp);
- retval = copy_node (r);
- TREE_OPERAND (r, 0) = temp;
- TREE_OPERAND (retval, 1) = temp;
- }
- else
- retval = DECL_RESULT (orig_fn_decl);
- }
-
- finish_expr_stmt (r);
+ /* Per CWG2563, we keep the result of promise.get_return_object () in
+ a temp which is then used to intialize the return object, including
+ NVRO. */
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (fn_return_type))
- /* If some part of the initalization code (prior to the await_resume
- of the initial suspend expression), then we need to clean up the
- return value. */
- ret_val_dtor = cxx_maybe_build_cleanup (DECL_RESULT (orig_fn_decl),
- tf_warning_or_error);
+ /* 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);
- /* If we have a live g.r.o in the return slot, then signal this for exception
- cleanup. */
- if (flag_exceptions && ret_val_dtor)
- {
- r = cp_build_init_expr (coro_gro_live, boolean_true_node);
+ r = cp_build_init_expr (coro_gro, STRIP_REFERENCE_REF (get_ro));
finish_expr_stmt (r);
+ tree coro_gro_cleanup
+ = cxx_maybe_build_cleanup (coro_gro, tf_warning_or_error);
+ if (coro_gro_cleanup)
+ push_cleanup (coro_gro, coro_gro_cleanup, /*eh_only*/false);
}
- /* Start the coroutine body. */
+ /* Start the coroutine body, we now have a use of the frame... */
+ r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR,
+ build_int_cst (short_unsigned_type_node, 1),
+ tf_warning_or_error);
+ finish_expr_stmt (r);
+ /* ... but when we finish we want to release that, and we want to do that
+ before any of the other cleanups run. */
+ tree released
+ = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node, coro_frame_refcount,
+ build_int_cst (short_unsigned_type_node, 1));
+ released = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,
+ tf_warning_or_error);
+ push_cleanup (NULL_TREE, released, /*eh_only*/false);
+
r = build_call_expr_loc (fn_start, resumer, 1, coro_fp);
finish_expr_stmt (r);
/* The ramp is done, we just need the return statement, which we build from
the return object we constructed before we called the actor. */
- r = retval;
-
- /* The reminder of finish_return_expr (). */
- r = build_stmt (loc, RETURN_EXPR, r);
- r = maybe_cleanup_point_expr_void (r);
- r = add_stmt (r);
+ r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro);
+ finish_return_stmt (r);
- if (flag_exceptions)
- {
- finish_compound_stmt (ramp_try_stmts);
- finish_try_block (ramp_try_block);
- tree handler = begin_handler ();
- finish_handler_parms (NULL_TREE, handler); /* catch (...) */
-
- /* If we have a live G.R.O in the return slot, then run its DTOR. */
- if (ret_val_dtor && ret_val_dtor != error_mark_node)
- {
- tree gro_d_if = begin_if_stmt ();
- finish_if_stmt_cond (coro_gro_live, gro_d_if);
- finish_expr_stmt (ret_val_dtor);
- finish_then_clause (gro_d_if);
- finish_if_stmt (gro_d_if);
- }
-
- /* Before initial resume is called, the responsibility for cleanup on
- exception falls to the ramp. After that, the coroutine body code
- should do the cleanup. This is signalled by the flag
- 'initial_await_resume_called'. */
-
- tree not_iarc
- = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, iarc_x);
- tree cleanup_if = begin_if_stmt ();
- finish_if_stmt_cond (not_iarc, cleanup_if);
- /* If the promise is live, then run its dtor if that's available. */
- if (promise_dtor && promise_dtor != error_mark_node)
- {
- tree promise_d_if = begin_if_stmt ();
- finish_if_stmt_cond (coro_promise_live, promise_d_if);
- finish_expr_stmt (promise_dtor);
- finish_then_clause (promise_d_if);
- finish_if_stmt (promise_d_if);
- }
-
- /* Clean up any frame copies of parms with non-trivial dtors.
- Do this in reverse order from their creation. */
- auto_vec<param_info *> worklist;
- if (DECL_ARGUMENTS (orig_fn_decl))
- for (tree arg = DECL_ARGUMENTS (orig_fn_decl); arg != NULL;
- arg = DECL_CHAIN (arg))
- {
- param_info *parm_i = param_uses.get (arg);
- if (parm_i->trivial_dtor)
- continue;
- worklist.safe_push (parm_i);
- }
- while (!worklist.is_empty ())
- {
- param_info *parm_i = worklist.pop ();
- if (parm_i->fr_copy_dtor && parm_i->fr_copy_dtor != error_mark_node)
- {
- tree dtor_if = begin_if_stmt ();
- finish_if_stmt_cond (parm_i->guard_var, dtor_if);
- finish_expr_stmt (parm_i->fr_copy_dtor);
- finish_then_clause (dtor_if);
- finish_if_stmt (dtor_if);
- }
- }
-
- /* No delete the frame if required. */
- tree fnf_if = begin_if_stmt ();
- finish_if_stmt_cond (frame_needs_free, fnf_if);
- finish_expr_stmt (delete_frame_call);
- finish_then_clause (fnf_if);
- finish_if_stmt (fnf_if);
-
- /* Finished cleanups conditional on "initial resume is not called". */
- finish_then_clause (cleanup_if);
- finish_if_stmt (cleanup_if);
-
- tree rethrow = build_throw (loc, NULL_TREE, tf_warning_or_error);
- suppress_warning (rethrow);
- finish_expr_stmt (rethrow);
- finish_handler (handler);
- finish_handler_sequence (ramp_try_block);
- }
finish_compound_stmt (ramp_fnbody);
return true;
}
@@ -5346,9 +5361,10 @@ cp_coroutine_transform::cp_coroutine_transform (tree _orig_fn, bool _inl)
}
/* We don't have the locus of the opening brace - it's filled in later (and
- there doesn't really seem to be any easy way to get at it).
- The closing brace is assumed to be input_location. */
+ there doesn't really seem to be any easy way to get at it). */
fn_start = DECL_SOURCE_LOCATION (orig_fn_decl);
+ /* The closing brace is assumed to be input_location. */
+ fn_end = input_location;
/* Build types we need. */
tree fr_name = get_fn_local_identifier (orig_fn_decl, "Frame");
@@ -5389,7 +5405,6 @@ cp_coroutine_transform::~cp_coroutine_transform ()
bool _Coro_frame_needs_free; free the coro frame mem if set.
bool _Coro_i_a_r_c; [dcl.fct.def.coroutine] / 5.3
short _Coro_resume_index;
- handle_type _Coro_self_handle;
parameter copies (were required).
local variables saved (including awaitables)
(maybe) trailing space.
@@ -5416,7 +5431,7 @@ cp_coroutine_transform::apply_transforms ()
/* Collect information on the original function params and their use in the
function body. */
- analyze_fn_parms (orig_fn_decl, &param_uses);
+ analyze_fn_parms ();
/* Declare the actor and destroyer functions, the following code needs to
see these. */
@@ -5427,6 +5442,16 @@ cp_coroutine_transform::apply_transforms ()
= coro_build_actor_or_destroy_function (orig_fn_decl, act_des_fn_type,
frame_ptr_type, false);
+ /* Avoid repeating diagnostics about promise or awaiter fails. */
+ if (!seen_error ())
+ {
+ iloc_sentinel stable_input_loc (fn_start);
+ initial_await = build_init_or_final_await (fn_start, false);
+ input_location = fn_end;
+ if (initial_await && initial_await != error_mark_node)
+ final_await = build_init_or_final_await (fn_end, true);
+ }
+
/* Transform the function body as per [dcl.fct.def.coroutine] / 5. */
wrap_original_function_body ();
diff --git a/gcc/cp/coroutines.h b/gcc/cp/coroutines.h
index d13bea0..fcc4645 100644
--- a/gcc/cp/coroutines.h
+++ b/gcc/cp/coroutines.h
@@ -9,7 +9,6 @@ struct param_info
vec<tree *> *body_uses; /* Worklist of uses, void if there are none. */
tree frame_type; /* The type used to represent this parm in the frame. */
tree orig_type; /* The original type of the parm (not as passed). */
- tree guard_var; /* If we need a DTOR on exception, this bool guards it. */
tree fr_copy_dtor; /* If we need a DTOR on exception, this is it. */
bool by_ref; /* Was passed by reference. */
bool pt_ref; /* Was a pointer to object. */
@@ -101,8 +100,8 @@ public:
private:
tree orig_fn_decl; /* The original function decl. */
- tree orig_fn_body = NULL_TREE; /* The original function body. */
location_t fn_start = UNKNOWN_LOCATION;
+ location_t fn_end = UNKNOWN_LOCATION;
tree resumer = error_mark_node;
tree destroyer = error_mark_node;
tree coroutine_body = NULL_TREE;
@@ -127,6 +126,10 @@ private:
bool inline_p = false;
bool valid_coroutine = false;
+ tree initial_await = error_mark_node;
+ tree final_await = error_mark_node;
+
+ void analyze_fn_parms ();
void wrap_original_function_body ();
bool build_ramp_function ();
};
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 550cea29..882a943 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -889,6 +889,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
(EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p),
&CALL_EXPR_ARG (*expr_p, 0));
break;
+ case CP_BUILT_IN_EH_PTR_ADJUST_REF:
+ error_at (EXPR_LOCATION (*expr_p),
+ "%qs used outside of constant expressions",
+ "__builtin_eh_ptr_adjust_ref");
+ *expr_p = void_node;
+ break;
default:
break;
}
@@ -1199,8 +1205,11 @@ cp_build_init_expr_for_ctor (tree call, tree init)
tree s = build_fold_indirect_ref_loc (loc, a);
init = cp_build_init_expr (s, init);
if (return_this)
- init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init,
- fold_convert_loc (loc, TREE_TYPE (call), a));
+ {
+ init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init,
+ fold_convert_loc (loc, TREE_TYPE (call), a));
+ suppress_warning (init);
+ }
return init;
}
@@ -1470,6 +1479,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
break;
case TARGET_EXPR:
+ if (!flag_no_inline)
+ if (tree &init = TARGET_EXPR_INITIAL (stmt))
+ {
+ tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
+ (data->flags & ff_mce_false
+ ? mce_false : mce_unknown));
+ if (folded != init && TREE_CONSTANT (folded))
+ init = folded;
+ }
+
+ /* This needs to happen between the constexpr evaluation (which wants
+ pre-generic trees) and fold (which wants the cp_genericize_init
+ transformations). */
if (data->flags & ff_genericize)
cp_genericize_target_expr (stmt_p);
@@ -1478,12 +1500,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
cp_walk_tree (&init, cp_fold_r, data, NULL);
cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL);
*walk_subtrees = 0;
- if (!flag_no_inline)
- {
- tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt));
- if (folded != init && TREE_CONSTANT (folded))
- init = folded;
- }
/* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in
that case, strip it in favor of this one. */
if (TREE_CODE (init) == TARGET_EXPR)
@@ -2804,6 +2820,12 @@ cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */)
}
}
+tree
+cxx_omp_finish_mapper_clauses (tree clauses)
+{
+ return finish_omp_clauses (clauses, C_ORT_OMP);
+}
+
/* Return true if DECL's DECL_VALUE_EXPR (if any) should be
disregarded in OpenMP construct, because it is going to be
remapped during OpenMP lowering. SHARED is true if DECL
@@ -3338,19 +3360,13 @@ cp_fold (tree x, fold_flags_t flags)
|| id_equal (DECL_NAME (callee), "addressof")
/* This addressof equivalent is used heavily in libstdc++. */
|| id_equal (DECL_NAME (callee), "__addressof")
+ || id_equal (DECL_NAME (callee), "to_underlying")
|| id_equal (DECL_NAME (callee), "as_const")))
{
r = CALL_EXPR_ARG (x, 0);
- /* Check that the return and argument types are sane before
- folding. */
- if (INDIRECT_TYPE_P (TREE_TYPE (x))
- && INDIRECT_TYPE_P (TREE_TYPE (r)))
- {
- if (!same_type_p (TREE_TYPE (x), TREE_TYPE (r)))
- r = build_nop (TREE_TYPE (x), r);
- x = cp_fold (r, flags);
- break;
- }
+ r = build_nop (TREE_TYPE (x), r);
+ x = cp_fold (r, flags);
+ break;
}
int sv = optimize, nw = sv;
@@ -3442,7 +3458,9 @@ cp_fold (tree x, fold_flags_t flags)
Do constexpr expansion of expressions where the call itself is not
constant, but the call followed by an INDIRECT_REF is. */
if (callee && DECL_DECLARED_CONSTEXPR_P (callee)
- && !flag_no_inline)
+ && (!flag_no_inline
+ || lookup_attribute ("always_inline",
+ DECL_ATTRIBUTES (callee))))
{
mce_value manifestly_const_eval = mce_unknown;
if (flags & ff_mce_false)
@@ -3875,7 +3893,6 @@ struct source_location_table_entry_hash
static GTY(()) hash_table <source_location_table_entry_hash>
*source_location_table;
-static GTY(()) unsigned int source_location_id;
/* Fold the __builtin_source_location () call T. */
@@ -3908,9 +3925,7 @@ fold_builtin_source_location (const_tree t)
var = entryp->var;
else
{
- char tmp_name[32];
- ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++);
- var = build_decl (loc, VAR_DECL, get_identifier (tmp_name),
+ var = build_decl (loc, VAR_DECL, generate_internal_label ("Lsrc_loc"),
source_location_impl);
TREE_STATIC (var) = 1;
TREE_PUBLIC (var) = 0;
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 8336d0b..7665b94 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -614,6 +614,8 @@ cp_register_dumps (gcc::dump_manager *dumps)
(".raw", "lang-raw", "lang-raw", DK_lang, OPTGROUP_NONE, false);
coro_dump_id = dumps->dump_register
(".coro", "lang-coro", "lang-coro", DK_lang, OPTGROUP_NONE, false);
+ tinst_dump_id = dumps->dump_register
+ (".tinst", "lang-tinst", "lang-tinst", DK_lang, OPTGROUP_NONE, false);
}
void
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 13fb80c..ff35428 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -190,6 +190,15 @@ static const scoped_attribute_specs *const cp_objcp_attribute_table[] =
#define LANG_HOOKS_OMP_CLAUSE_DTOR cxx_omp_clause_dtor
#undef LANG_HOOKS_OMP_FINISH_CLAUSE
#define LANG_HOOKS_OMP_FINISH_CLAUSE cxx_omp_finish_clause
+#undef LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES
+#define LANG_HOOKS_OMP_FINISH_MAPPER_CLAUSES cxx_omp_finish_mapper_clauses
+#undef LANG_HOOKS_OMP_MAPPER_LOOKUP
+#define LANG_HOOKS_OMP_MAPPER_LOOKUP cxx_omp_mapper_lookup
+#undef LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE
+#define LANG_HOOKS_OMP_EXTRACT_MAPPER_DIRECTIVE \
+ cxx_omp_extract_mapper_directive
+#undef LANG_HOOKS_OMP_MAP_ARRAY_SECTION
+#define LANG_HOOKS_OMP_MAP_ARRAY_SECTION cxx_omp_map_array_section
#undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
#define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE cxx_omp_privatize_by_reference
#undef LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6aaca13..e71b28c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
+DEFTRAIT_EXPR (IS_DESTRUCTIBLE, "__is_destructible", 1)
DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
@@ -84,6 +85,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
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_OBJECT, "__is_object", 1)
DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
@@ -98,6 +100,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
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_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)
@@ -111,6 +114,7 @@ DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1)
DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
+DEFTRAIT_EXPR (TYPE_ORDER, "__builtin_type_order", 2)
DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 927f51b..9081628 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -452,6 +452,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR)
PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*)
+ MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR)
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -472,6 +473,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
BIND_EXPR_VEC_DTOR (in BIND_EXPR)
ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
+ MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -493,6 +495,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
STATIC_INIT_DECOMP_NONBASE_P (in the TREE_LIST
for {static,tls}_aggregates)
+ MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR)
3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -506,6 +509,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
+ TYPENAME_IS_UNION_P (in TYPENAME_TYPE)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
CALL_EXPR, or FIELD_DECL).
@@ -2206,6 +2210,8 @@ struct GTY(()) language_function {
BOOL_BITFIELD invalid_constexpr : 1;
BOOL_BITFIELD throwing_cleanup : 1;
+ /* True if we gave any errors in this function. */
+ BOOL_BITFIELD erroneous : 1;
hash_table<named_label_hash> *x_named_labels;
@@ -2352,6 +2358,10 @@ enum languages { lang_c, lang_cplusplus };
#define NON_UNION_CLASS_TYPE_P(T) \
(TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T))
+/* Nonzero if T is a class type and is a union. */
+#define UNION_TYPE_P(T) \
+ (TREE_CODE (T) == UNION_TYPE && TYPE_LANG_FLAG_5 (T))
+
/* Keep these checks in ascending code order. */
#define RECORD_OR_UNION_CODE_P(T) \
((T) == RECORD_TYPE || (T) == UNION_TYPE)
@@ -2489,6 +2499,7 @@ struct GTY(()) lang_type {
unsigned unique_obj_representations_set : 1;
bool erroneous : 1;
bool non_pod_aggregate : 1;
+ bool non_aggregate_pod : 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
@@ -2497,7 +2508,7 @@ struct GTY(()) lang_type {
/* 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 : 3;
+ unsigned dummy : 2;
tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2508,15 +2519,19 @@ 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;
- /* In a RECORD_TYPE, information specific to Objective-C++, such
- as a list of adopted protocols or a pointer to a corresponding
- @interface. See objc/objc-act.h for details. */
- tree objc_info;
- /* 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;
+ /* In a RECORD_TYPE, information specific to Objective-C, such
+ as a list of adopted protocols or a pointer to a corresponding
+ @interface. See objc/objc-act.h for details. */
+ tree GTY((tag ("1"))) objc_info;
+ } GTY ((desc ("c_dialect_objc ()"))) info;
};
/* We used to have a variant type for lang_type. Keep the name of the
@@ -2631,7 +2646,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
@@ -2763,7 +2784,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)))
@@ -2824,6 +2850,11 @@ struct GTY(()) lang_type {
with a hash_set only filled in when abi_version_crosses (17). */
#define CLASSTYPE_NON_POD_AGGREGATE(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->non_pod_aggregate)
+
+/* True if this class is layout-POD though it's not an aggregate in C++20 and
+ above (c++/120012). This could also be a hash_set. */
+#define CLASSTYPE_NON_AGGREGATE_POD(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->non_aggregate_pod)
/* Additional macros for inheritance information. */
@@ -2967,7 +2998,10 @@ struct GTY(()) lang_decl_base {
unsigned module_keyed_decls_p : 1; /* has keys, applies to all decls */
- /* 11 spare bits. */
+ /* VAR_DECL being used to represent an OpenMP declared mapper. */
+ unsigned omp_declare_mapper_p : 1;
+
+ /* 10 spare bits. */
};
/* True for DECL codes which have template info and access. */
@@ -2996,6 +3030,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;
@@ -4450,6 +4486,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
@@ -4470,11 +4523,14 @@ get_vec_init_expr (tree t)
#define TYPENAME_IS_ENUM_P(NODE) \
(TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE)))
-/* True if a TYPENAME_TYPE was declared as a "class", "struct", or
- "union". */
+/* True if a TYPENAME_TYPE was declared as a "class" or "struct". */
#define TYPENAME_IS_CLASS_P(NODE) \
(TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE)))
+/* True if a TYPENAME_TYPE was declared as a "union". */
+#define TYPENAME_IS_UNION_P(NODE) \
+ (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE)))
+
/* True if a TYPENAME_TYPE is in the process of being resolved. */
#define TYPENAME_IS_RESOLVING_P(NODE) \
(TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE)))
@@ -4489,7 +4545,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))
@@ -4522,6 +4578,11 @@ get_vec_init_expr (tree t)
#define DECL_OMP_DECLARE_REDUCTION_P(NODE) \
(LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->omp_declare_reduction_p)
+/* Nonzero if NODE is an artificial FUNCTION_DECL for
+ #pragma omp declare mapper. */
+#define DECL_OMP_DECLARE_MAPPER_P(NODE) \
+ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.omp_declare_mapper_p)
+
/* Nonzero if DECL has been declared threadprivate by
#pragma omp threadprivate. */
#define CP_DECL_THREADPRIVATE_P(DECL) \
@@ -5125,6 +5186,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)
@@ -5514,6 +5579,10 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn)
#define DECL_RAMP_FN(NODE) \
(coro_get_ramp_function (NODE))
+/* For a FUNCTION_DECL this is true if it is a coroutine ramp. */
+#define DECL_RAMP_P(NODE) \
+ DECL_COROUTINE_P (NODE) && !DECL_RAMP_FN (NODE)
+
/* True for an OMP_ATOMIC that has dependent parameters. These are stored
as an expr in operand 1, and integer_zero_node or clauses in operand 0. */
#define OMP_ATOMIC_DEPENDENT_P(NODE) \
@@ -6753,8 +6822,14 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
/* The location where the template is instantiated. */
location_t locus;
- /* errorcount + sorrycount when we pushed this level. */
- unsigned short errors;
+ /* errorcount + sorrycount when we pushed this level. If the value
+ overflows, it will always seem like we currently have more errors, so we
+ will limit template recursion even from non-erroneous templates. In a TU
+ with over 32k errors, that's fine. */
+ unsigned short errors : 15;
+
+ /* set in pop_tinst_level if there have been errors since we pushed. */
+ bool had_errors : 1;
/* Count references to this object. If refcount reaches
refcount_infinity value, we don't increment or decrement the
@@ -6775,6 +6850,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
};
@@ -6808,6 +6884,7 @@ extern int class_dump_id;
extern int module_dump_id;
extern int raw_dump_id;
extern int coro_dump_id;
+extern int tinst_dump_id;
/* Whether the current context is manifestly constant-evaluated.
Used by the constexpr machinery to control folding of
@@ -6954,6 +7031,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);
@@ -7042,6 +7120,7 @@ extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree);
extern bool type_has_non_user_provided_default_constructor (tree);
+extern bool type_has_converting_constructor (tree);
extern bool vbase_has_user_provided_move_assign (tree);
extern tree default_init_uninitialized_part (tree);
extern bool trivial_default_constructor_is_constexpr (tree);
@@ -7072,6 +7151,7 @@ extern void adjust_clone_args (tree);
extern void deduce_noexcept_on_destructor (tree);
extern bool uniquely_derived_from_p (tree, tree);
extern bool publicly_uniquely_derived_p (tree, tree);
+extern bool publicly_virtually_derived_p (tree, tree);
extern tree common_enclosing_class (tree, tree);
/* in cvt.cc */
@@ -7307,6 +7387,29 @@ extern void cp_check_const_attributes (tree);
extern void maybe_propagate_warmth_attributes (tree, tree);
/* in error.cc */
+/* A class for pretty-printing to -flang-dump-XXX files. Used like
+
+ if (cxx_dump_pretty_printer pp {foo_dump_id})
+ {
+ pp_printf (&pp, ...);
+ }
+
+ If the dump is enabled, the pretty printer will open the dump file and
+ attach to it, and flush and close the file on destruction. */
+
+class cxx_dump_pretty_printer: public pretty_printer
+{
+ int phase;
+ FILE *outf;
+ dump_flags_t flags;
+
+public:
+ cxx_dump_pretty_printer (int phase);
+ operator bool() { return outf != nullptr; }
+ bool has_flag (dump_flags_t f) { return (flags & f); }
+ ~cxx_dump_pretty_printer ();
+};
+
extern const char *type_as_string (tree, int);
extern const char *type_as_string_translate (tree, int);
extern const char *decl_as_string (tree, int);
@@ -7502,6 +7605,8 @@ extern bool ctor_omit_inherited_parms (tree);
extern tree locate_ctor (tree);
extern tree implicitly_declare_fn (special_function_kind, tree,
bool, tree, tree);
+extern tree type_order_value (tree, tree);
+
/* In module.cc */
class module_state; /* Forward declare. */
inline bool modules_p () { return flag_modules != 0; }
@@ -7618,7 +7723,6 @@ extern void cp_finish_omp_range_for (tree, tree);
extern bool cp_maybe_parse_omp_decl (tree, tree);
extern bool parsing_nsdmi (void);
extern bool parsing_function_declarator ();
-extern bool parsing_default_capturing_generic_lambda_in_template (void);
extern void inject_this_parameter (tree, cp_cv_quals);
extern location_t defparse_location (tree);
extern void maybe_show_extern_c_location (void);
@@ -7759,6 +7863,7 @@ extern bool type_dependent_expression_p_push (tree);
extern bool value_dependent_expression_p (tree);
extern bool instantiation_dependent_uneval_expression_p (tree);
extern bool any_value_dependent_elements_p (const_tree);
+extern bool dependent_template_arg_p (tree);
extern bool dependent_omp_for_p (tree, tree, tree, tree, tree);
extern tree resolve_typename_type (tree, bool);
extern tree template_for_substitution (tree);
@@ -7906,6 +8011,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t);
extern bool perform_or_defer_access_check (tree, tree, tree,
tsubst_flags_t,
access_failure_info *afi = NULL);
+extern tree maybe_convert_cond (tree);
/* RAII sentinel to ensures that deferred access checks are popped before
a function returns. */
@@ -8054,11 +8160,14 @@ extern tree finish_qualified_id_expr (tree, tree, bool, bool,
extern void simplify_aggr_init_expr (tree *);
extern void finalize_nrv (tree, tree);
extern tree omp_reduction_id (enum tree_code, tree, tree);
+extern tree omp_mapper_id (tree, tree);
extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *);
extern bool cp_check_omp_declare_reduction (tree);
+extern bool cp_check_omp_declare_mapper (tree);
extern void finish_omp_declare_simd_methods (tree);
extern tree cp_finish_omp_init_prefer_type (tree);
extern tree finish_omp_clauses (tree, enum c_omp_region_type);
+extern tree omp_instantiate_mappers (tree);
extern tree push_omp_privatization_clauses (bool);
extern void pop_omp_privatization_clauses (tree);
extern void save_omp_privatization_clauses (vec<tree> &);
@@ -8654,6 +8763,10 @@ extern tree cxx_omp_clause_copy_ctor (tree, tree, tree);
extern tree cxx_omp_clause_assign_op (tree, tree, tree);
extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree, gimple_seq *, bool);
+extern tree cxx_omp_finish_mapper_clauses (tree);
+extern tree cxx_omp_mapper_lookup (tree, tree);
+extern tree cxx_omp_extract_mapper_directive (tree);
+extern tree cxx_omp_map_array_section (location_t, tree);
extern bool cxx_omp_privatize_by_reference (const_tree);
extern bool cxx_omp_disregard_value_expr (tree, bool);
extern void cp_fold_function (tree);
@@ -8780,7 +8893,8 @@ extern hashval_t iterative_hash_constraint (tree, hashval_t);
extern hashval_t hash_atomic_constraint (tree);
extern void diagnose_constraints (location_t, tree, tree);
-extern void note_failed_type_completion_for_satisfaction (tree);
+extern void note_failed_type_completion (tree, tsubst_flags_t);
+extern location_t failed_completion_location (tree);
/* in logic.cc */
extern bool subsumes (tree, tree);
@@ -8837,6 +8951,7 @@ extern void cxx_constant_dtor (tree, tree);
extern tree cxx_constant_init (tree, tree = NULL_TREE);
extern tree maybe_constant_value (tree, tree = NULL_TREE, mce_value = mce_unknown);
extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false);
+extern tree maybe_constant_init (tree, tree, mce_value);
extern tree fold_non_dependent_expr (tree,
tsubst_flags_t = tf_warning_or_error,
bool = false, tree = NULL_TREE);
@@ -8847,7 +8962,7 @@ extern tree fold_non_dependent_init (tree,
bool = false, tree = NULL_TREE);
extern tree fold_simple (tree);
extern tree fold_to_constant (tree);
-extern bool reduced_constant_expression_p (tree);
+extern bool reduced_constant_expression_p (tree, tree = NULL_TREE);
extern bool is_instantiation_of_constexpr (tree);
extern bool var_in_constexpr_fn (tree);
extern bool var_in_maybe_constexpr_fn (tree);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index cf301bd..5f24015 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "cp-tree.h"
#include "cxx-pretty-print.h"
#include "tree-pretty-print.h"
-#include "make-unique.h"
static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree);
static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree);
@@ -2954,5 +2953,5 @@ cxx_pretty_printer::cxx_pretty_printer ()
std::unique_ptr<pretty_printer>
cxx_pretty_printer::clone () const
{
- return ::make_unique<cxx_pretty_printer> (*this);
+ return std::make_unique<cxx_pretty_printer> (*this);
}
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 2ed94fd..843f0e4 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -846,11 +846,9 @@ poplevel (int keep, int reverse, int functionbody)
DECL_INITIAL (current_function_decl) = block ? block : subblocks;
if (subblocks)
{
- if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl))
- {
- if (BLOCK_SUBBLOCKS (subblocks))
- BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1;
- }
+ if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)
+ && BLOCK_SUBBLOCKS (subblocks))
+ BLOCK_OUTER_CURLY_BRACE_P (BLOCK_SUBBLOCKS (subblocks)) = 1;
else
BLOCK_OUTER_CURLY_BRACE_P (subblocks) = 1;
}
@@ -1313,7 +1311,15 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record)
}
if (record)
- cgraph_node::record_function_versions (olddecl, newdecl);
+ {
+ /* 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);
+ }
return true;
}
@@ -2008,8 +2014,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
}
/* For function versions, params and types match, but they
are not ambiguous. */
- else if ((!DECL_FUNCTION_VERSIONED (newdecl)
- && !DECL_FUNCTION_VERSIONED (olddecl))
+ else if (((!DECL_FUNCTION_VERSIONED (newdecl)
+ && !DECL_FUNCTION_VERSIONED (olddecl))
+ || !same_type_p (fndecl_declared_return_type (newdecl),
+ fndecl_declared_return_type (olddecl)))
/* Let constrained hidden friends coexist for now, we'll
check satisfaction later. */
&& !member_like_constrained_friend_p (newdecl)
@@ -4362,6 +4370,7 @@ struct typename_info {
tree template_id;
bool enum_p;
bool class_p;
+ bool union_p;
};
struct typename_hasher : ggc_ptr_hash<tree_node>
@@ -4400,7 +4409,8 @@ struct typename_hasher : ggc_ptr_hash<tree_node>
&& TYPE_CONTEXT (t1) == t2->scope
&& TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
&& TYPENAME_IS_ENUM_P (t1) == t2->enum_p
- && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
+ && TYPENAME_IS_CLASS_P (t1) == t2->class_p
+ && TYPENAME_IS_UNION_P (t1) == t2->union_p);
}
};
@@ -4424,9 +4434,8 @@ build_typename_type (tree context, tree name, tree fullname,
ti.name = name;
ti.template_id = fullname;
ti.enum_p = tag_type == enum_type;
- ti.class_p = (tag_type == class_type
- || tag_type == record_type
- || tag_type == union_type);
+ ti.class_p = (tag_type == class_type || tag_type == record_type);
+ ti.union_p = tag_type == union_type;
hashval_t hash = typename_hasher::hash (&ti);
/* See if we already have this type. */
@@ -4442,6 +4451,7 @@ build_typename_type (tree context, tree name, tree fullname,
TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
TYPENAME_IS_ENUM_P (t) = ti.enum_p;
TYPENAME_IS_CLASS_P (t) = ti.class_p;
+ TYPENAME_IS_UNION_P (t) = ti.union_p;
/* Build the corresponding TYPE_DECL. */
tree d = build_decl (input_location, TYPE_DECL, name, t);
@@ -5072,6 +5082,18 @@ cxx_init_decl_processing (void)
BUILT_IN_FRONTEND, NULL, NULL_TREE);
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+ if (cxx_dialect >= cxx26)
+ {
+ tree void_ptrintftype
+ = build_function_type_list (void_type_node, ptr_type_node,
+ integer_type_node, NULL_TREE);
+ decl = add_builtin_function ("__builtin_eh_ptr_adjust_ref",
+ void_ptrintftype,
+ CP_BUILT_IN_EH_PTR_ADJUST_REF,
+ BUILT_IN_FRONTEND, NULL, NULL_TREE);
+ set_call_expr_flags (decl, ECF_NOTHROW | ECF_LEAF);
+ }
+
integer_two_node = build_int_cst (NULL_TREE, 2);
/* Guess at the initial static decls size. */
@@ -5339,6 +5361,8 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep)
decl = pushdecl_outermost_localscope (decl);
if (decl != error_mark_node)
add_decl_expr (decl);
+ else
+ gcc_assert (seen_error ());
}
else
{
@@ -6198,22 +6222,28 @@ start_decl (const cp_declarator *declarator,
}
if (current_function_decl && VAR_P (decl)
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && maybe_constexpr_fn (current_function_decl)
&& cxx_dialect < cxx23)
{
bool ok = false;
if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl))
- error_at (DECL_SOURCE_LOCATION (decl),
- "%qD defined %<thread_local%> in %qs function only "
- "available with %<-std=c++23%> or %<-std=gnu++23%>", decl,
- DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
- ? "consteval" : "constexpr");
+ {
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD defined %<thread_local%> in %qs function only "
+ "available with %<-std=c++23%> or %<-std=gnu++23%>", decl,
+ DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+ ? "consteval" : "constexpr");
+ }
else if (TREE_STATIC (decl))
- error_at (DECL_SOURCE_LOCATION (decl),
- "%qD defined %<static%> in %qs function only available "
- "with %<-std=c++23%> or %<-std=gnu++23%>", decl,
- DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
- ? "consteval" : "constexpr");
+ {
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD defined %<static%> in %qs function only available "
+ "with %<-std=c++23%> or %<-std=gnu++23%>", decl,
+ DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+ ? "consteval" : "constexpr");
+ }
else
ok = true;
if (!ok)
@@ -7871,6 +7901,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
}
else if (!init && DECL_REALLY_EXTERN (decl))
;
+ else if (flag_openmp
+ && VAR_P (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_DECLARE_MAPPER_P (decl)
+ && TREE_CODE (init) == OMP_DECLARE_MAPPER)
+ return NULL_TREE;
else if (init || type_build_ctor_call (type)
|| TYPE_REF_P (type))
{
@@ -8897,13 +8933,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
TREE_TYPE (decl) = error_mark_node;
return;
}
+
+ /* Now that we have a type, try these again. */
+ layout_decl (decl, 0);
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
/* Update the type of the corresponding TEMPLATE_DECL to match. */
- if (DECL_LANG_SPECIFIC (decl)
- && DECL_TEMPLATE_INFO (decl)
- && DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (decl)) == decl)
- TREE_TYPE (DECL_TI_TEMPLATE (decl)) = type;
+ if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
+ {
+ tree tmpl = template_for_substitution (decl);
+ if (DECL_TEMPLATE_RESULT (tmpl) == decl)
+ TREE_TYPE (tmpl) = type;
+ }
}
if (ensure_literal_type_for_constexpr_object (decl) == error_mark_node)
@@ -9147,6 +9188,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (decomp)
{
+ if (DECL_DECLARED_CONSTINIT_P (decl) && cxx_dialect < cxx26)
+ pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+ "%<constinit%> can be applied to structured binding "
+ "only with %<-std=c++2c%> or %<-std=gnu++2c%>");
cp_maybe_mangle_decomp (decl, decomp);
if (TREE_STATIC (decl) && !DECL_FUNCTION_SCOPE_P (decl))
{
@@ -9188,14 +9233,23 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
varpool_node::get_create (decl);
}
+ if (flag_openmp
+ && VAR_P (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_DECLARE_MAPPER_P (decl)
+ && init)
+ {
+ gcc_assert (TREE_CODE (init) == OMP_DECLARE_MAPPER);
+ DECL_INITIAL (decl) = init;
+ }
/* Convert the initializer to the type of DECL, if we have not
already initialized DECL. */
- if (!DECL_INITIALIZED_P (decl)
- /* If !DECL_EXTERNAL then DECL is being defined. In the
- case of a static data member initialized inside the
- class-specifier, there can be an initializer even if DECL
- is *not* defined. */
- && (!DECL_EXTERNAL (decl) || init))
+ else if (!DECL_INITIALIZED_P (decl)
+ /* If !DECL_EXTERNAL then DECL is being defined. In the
+ case of a static data member initialized inside the
+ class-specifier, there can be an initializer even if DECL
+ is *not* defined. */
+ && (!DECL_EXTERNAL (decl) || init))
{
cleanups = make_tree_vector ();
init = check_initializer (decl, init, flags, &cleanups);
@@ -11294,11 +11348,16 @@ grokfndecl (tree ctype,
"cannot declare %<::main%> to be %qs", "consteval");
if (!publicp)
error_at (location, "cannot declare %<::main%> to be static");
- if (current_lang_depth () != 0)
+ if (current_lang_name != lang_name_cplusplus)
pedwarn (location, OPT_Wpedantic, "cannot declare %<::main%> with a"
- " linkage specification");
+ " linkage specification other than %<extern \"C++\"%>");
if (module_attach_p ())
- error_at (location, "cannot attach %<::main%> to a named module");
+ {
+ auto_diagnostic_group adg;
+ error_at (location, "cannot attach %<::main%> to a named module");
+ inform (location, "use %<extern \"C++\"%> to attach it to the "
+ "global module instead");
+ }
inlinep = 0;
publicp = 1;
}
@@ -13580,9 +13639,10 @@ grokdeclarator (const cp_declarator *declarator,
if (typedef_p)
error_at (declspecs->locations[ds_typedef],
"structured binding declaration cannot be %qs", "typedef");
- if (constexpr_p && !concept_p)
- error_at (declspecs->locations[ds_constexpr], "structured "
- "binding declaration cannot be %qs", "constexpr");
+ if (constexpr_p && !concept_p && cxx_dialect < cxx26)
+ pedwarn (declspecs->locations[ds_constexpr], OPT_Wc__26_extensions,
+ "structured binding declaration can be %qs only with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", "constexpr");
if (consteval_p)
error_at (declspecs->locations[ds_consteval], "structured "
"binding declaration cannot be %qs", "consteval");
@@ -13593,8 +13653,11 @@ grokdeclarator (const cp_declarator *declarator,
declspecs->gnu_thread_keyword_p
? "__thread" : "thread_local");
if (concept_p)
- error_at (declspecs->locations[ds_concept],
- "structured binding declaration cannot be %qs", "concept");
+ {
+ error_at (declspecs->locations[ds_concept],
+ "structured binding declaration cannot be %qs", "concept");
+ constexpr_p = 0;
+ }
/* [dcl.struct.bind] "A cv that includes volatile is deprecated." */
if (type_quals & TYPE_QUAL_VOLATILE)
warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile,
@@ -13649,7 +13712,6 @@ grokdeclarator (const cp_declarator *declarator,
"%<auto%> type %qT", type);
inlinep = 0;
typedef_p = 0;
- constexpr_p = 0;
consteval_p = 0;
concept_p = 0;
if (storage_class != sc_static)
@@ -17227,7 +17289,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
@@ -19304,6 +19366,19 @@ finish_function (bool inline_p)
}
}
+ if (FNDECL_USED_AUTO (fndecl)
+ && TREE_TYPE (fntype) != DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
+ if (location_t fcloc = failed_completion_location (fndecl))
+ {
+ auto_diagnostic_group adg;
+ if (warning (OPT_Wsfinae_incomplete_,
+ "defining %qD, which previously failed to be deduced "
+ "in a SFINAE context", fndecl)
+ && warn_sfinae_incomplete == 1)
+ inform (fcloc, "here. Use %qs for a diagnostic at that point",
+ "-Wsfinae-incomplete=2");
+ }
+
/* Remember that we were in class scope. */
if (current_class_name)
ctype = current_class_type;
@@ -19834,14 +19909,14 @@ cp_tree_node_structure (union lang_tree_node * t)
{
switch (TREE_CODE (&t->generic))
{
- case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT;
+ case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT;
case BASELINK: return TS_CP_BASELINK;
- case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO;
+ case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO;
case DEFERRED_NOEXCEPT: return TS_CP_DEFERRED_NOEXCEPT;
case DEFERRED_PARSE: return TS_CP_DEFERRED_PARSE;
case IDENTIFIER_NODE: return TS_CP_IDENTIFIER;
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
- case BINDING_VECTOR: return TS_CP_BINDING_VECTOR;
+ case BINDING_VECTOR: return TS_CP_BINDING_VECTOR;
case OVERLOAD: return TS_CP_OVERLOAD;
case PTRMEM_CST: return TS_CP_PTRMEM;
case STATIC_ASSERT: return TS_CP_STATIC_ASSERT;
@@ -19849,6 +19924,7 @@ cp_tree_node_structure (union lang_tree_node * t)
case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO;
case TEMPLATE_PARM_INDEX: return TS_CP_TPI;
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
+ case TU_LOCAL_ENTITY: return TS_CP_TU_LOCAL_ENTITY;
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
default: return TS_CP_GENERIC;
}
@@ -19956,7 +20032,7 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
/* We probably already complained about deduction failure. */;
else if (complain & tf_error)
error ("use of %qD before deduction of %<auto%>", decl);
- note_failed_type_completion_for_satisfaction (decl);
+ note_failed_type_completion (decl, complain);
return false;
}
return true;
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 21156f1..2bbc618 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -3160,7 +3160,9 @@ determine_visibility (tree decl)
&& !attr)
{
int depth = TMPL_ARGS_DEPTH (args);
- if (DECL_VISIBILITY_SPECIFIED (decl))
+ if (DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (TI_TEMPLATE (tinfo)))
+ /* Class template args don't affect template friends. */;
+ else if (DECL_VISIBILITY_SPECIFIED (decl))
{
/* A class template member with explicit visibility
overrides the class visibility, so we need to apply
@@ -4026,6 +4028,7 @@ get_tls_init_fn (tree var)
SET_DECL_LANGUAGE (fn, lang_c);
TREE_PUBLIC (fn) = TREE_PUBLIC (var);
DECL_ARTIFICIAL (fn) = true;
+ DECL_CONTEXT (fn) = FROB_CONTEXT (global_namespace);
DECL_COMDAT (fn) = DECL_COMDAT (var);
DECL_EXTERNAL (fn) = DECL_EXTERNAL (var);
if (DECL_ONE_ONLY (var))
@@ -4085,7 +4088,7 @@ get_tls_wrapper_fn (tree var)
TREE_PUBLIC (fn) = TREE_PUBLIC (var);
DECL_ARTIFICIAL (fn) = true;
DECL_IGNORED_P (fn) = 1;
- DECL_CONTEXT (fn) = DECL_CONTEXT (var);
+ DECL_CONTEXT (fn) = FROB_CONTEXT (global_namespace);
/* The wrapper is inline and emitted everywhere var is used. */
DECL_DECLARED_INLINE_P (fn) = true;
if (TREE_PUBLIC (var))
@@ -4184,7 +4187,11 @@ start_objects (bool initp, unsigned priority, bool has_body,
bool omp_target = false)
{
bool default_init = initp && priority == DEFAULT_INIT_PRIORITY;
- bool is_module_init = default_init && module_global_init_needed ();
+ /* FIXME: We may eventually want to treat OpenMP offload initializers
+ in modules specially as well. */
+ bool is_module_init = (default_init
+ && !omp_target
+ && module_global_init_needed ());
tree name = NULL_TREE;
if (is_module_init)
@@ -5876,12 +5883,8 @@ c_parse_final_cleanups (void)
if (static_init_fini_fns[true]->get_or_insert (DEFAULT_INIT_PRIORITY))
has_module_inits = true;
- if (flag_openmp)
- {
- if (!static_init_fini_fns[2 + true])
- static_init_fini_fns[2 + true] = priority_map_t::create_ggc ();
- static_init_fini_fns[2 + true]->get_or_insert (DEFAULT_INIT_PRIORITY);
- }
+ /* FIXME: We need to work out what static constructors on OpenMP offload
+ target in modules will look like. */
}
/* Generate initialization and destruction functions for all
@@ -6266,6 +6269,33 @@ mark_single_function (tree expr, tsubst_flags_t complain)
return true;
}
+/* True iff we have started, but not finished, defining FUNCTION_DECL DECL. */
+
+bool
+fn_being_defined (tree decl)
+{
+ /* DECL_INITIAL is set to error_mark_node in grokfndecl for a definition, and
+ changed to BLOCK by poplevel at the end of the function. */
+ return (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_INITIAL (decl) == error_mark_node);
+}
+
+/* True if DECL is an instantiation of a function template currently being
+ defined. */
+
+bool
+fn_template_being_defined (tree decl)
+{
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ || !DECL_LANG_SPECIFIC (decl)
+ || !DECL_TEMPLOID_INSTANTIATION (decl)
+ || DECL_TEMPLATE_INSTANTIATED (decl))
+ return false;
+ tree tinfo = DECL_TEMPLATE_INFO (decl);
+ tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
+ return fn_being_defined (pattern);
+}
+
/* Mark DECL (either a _DECL or a BASELINK) as "used" in the program.
If DECL is a specialization or implicitly declared class member,
generate the actual definition. Return false if something goes
@@ -6405,15 +6435,23 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
/* If DECL has a deduced return type, we need to instantiate it now to
find out its type. For OpenMP user defined reductions, we need them
- instantiated for reduction clauses which inline them by hand directly. */
+ instantiated for reduction clauses which inline them by hand directly.
+ OpenMP declared mappers are used implicitly so must be instantiated
+ before they can be detected. */
if (undeduced_auto_decl (decl)
|| (VAR_P (decl)
&& VAR_HAD_UNKNOWN_BOUND (decl))
|| (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_OMP_DECLARE_REDUCTION_P (decl)))
+ && DECL_OMP_DECLARE_REDUCTION_P (decl))
+ || (TREE_CODE (decl) == VAR_DECL
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_DECLARE_MAPPER_P (decl)))
maybe_instantiate_decl (decl);
if (!decl_dependent_p (decl)
+ /* Don't require this yet for an instantiation of a function template
+ we're currently defining (c++/120555). */
+ && !fn_template_being_defined (decl)
&& !require_deduced_type (decl, complain))
return false;
@@ -6428,9 +6466,6 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
&& uses_template_parms (DECL_TI_ARGS (decl)))
return true;
- if (!require_deduced_type (decl, complain))
- return false;
-
if (builtin_pack_fn_p (decl))
{
error ("use of built-in parameter pack %qD outside of a template",
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index ec7527e..eb2ff33 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -38,7 +38,6 @@ 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 "make-unique.h"
#include "diagnostic-format-text.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
@@ -183,9 +182,10 @@ class cxx_format_postprocessor : public format_postprocessor
: m_type_a (), m_type_b ()
{}
- format_postprocessor *clone() const final override
+ std::unique_ptr<format_postprocessor>
+ clone() const final override
{
- return new cxx_format_postprocessor ();
+ return std::make_unique<cxx_format_postprocessor> ();
}
void handle (pretty_printer *pp) final override;
@@ -194,6 +194,32 @@ class cxx_format_postprocessor : public format_postprocessor
deferred_printed_type m_type_b;
};
+/* Constructor and destructor for cxx_dump_pretty_printer, defined here to
+ avoid needing to move cxx_format_postprocessor into the header as well. */
+
+cxx_dump_pretty_printer::
+cxx_dump_pretty_printer (int phase)
+ : phase (phase)
+{
+ outf = dump_begin (phase, &flags);
+ if (outf)
+ {
+ pp_format_decoder (this) = cp_printer;
+ set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ());
+ set_output_stream (outf);
+ }
+}
+
+cxx_dump_pretty_printer::
+~cxx_dump_pretty_printer ()
+{
+ if (outf)
+ {
+ pp_flush (this);
+ dump_end (phase, outf);
+ }
+}
+
/* Return the in-scope template that's currently being parsed, or
NULL_TREE otherwise. */
@@ -275,14 +301,14 @@ void
cxx_initialize_diagnostics (diagnostic_context *context)
{
cxx_pretty_printer *pp = new cxx_pretty_printer ();
- pp_format_postprocessor (pp) = new cxx_format_postprocessor ();
+ 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;
/* diagnostic_finalizer is already c_diagnostic_text_finalizer. */
context->set_format_decoder (cp_printer);
- context->m_adjust_diagnostic_info = cp_adjust_diagnostic_info;
+ context->set_adjust_diagnostic_info_callback (cp_adjust_diagnostic_info);
}
/* Dump an '@module' name suffix for DECL, if it's attached to an import. */
@@ -542,12 +568,13 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
/* If the template argument repeats the template parameter (T = T),
skip the parameter.*/
if (arg && TREE_CODE (arg) == TEMPLATE_TYPE_PARM
- && TREE_CODE (parm_i) == TREE_LIST
- && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL
- && TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i)))
- == TEMPLATE_TYPE_PARM
- && DECL_NAME (TREE_VALUE (parm_i))
- == DECL_NAME (TREE_CHAIN (arg)))
+ && arg == TYPE_MAIN_VARIANT (arg)
+ && TREE_CODE (parm_i) == TREE_LIST
+ && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL
+ && (TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i)))
+ == TEMPLATE_TYPE_PARM)
+ && (DECL_NAME (TREE_VALUE (parm_i))
+ == DECL_NAME (TYPE_STUB_DECL (arg))))
continue;
semicolon_or_introducer ();
@@ -783,6 +810,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_ws_string (pp,
TYPENAME_IS_ENUM_P (t) ? "enum"
: TYPENAME_IS_CLASS_P (t) ? "class"
+ : TYPENAME_IS_UNION_P (t) ? "union"
: "typename");
dump_typename (pp, t, flags);
break;
@@ -1255,12 +1283,37 @@ dump_global_iord (cxx_pretty_printer *pp, tree t)
pp_printf (pp, p, DECL_SOURCE_FILE (t));
}
+/* Write a representation of OpenMP "declare mapper" T to PP in a manner
+ suitable for error messages. */
+
+static void
+dump_omp_declare_mapper (cxx_pretty_printer *pp, tree t, int flags)
+{
+ pp_string (pp, "#pragma omp declare mapper");
+ if (t == NULL_TREE || t == error_mark_node)
+ return;
+ pp_space (pp);
+ pp_cxx_left_paren (pp);
+ if (OMP_DECLARE_MAPPER_ID (t))
+ {
+ pp_cxx_tree_identifier (pp, OMP_DECLARE_MAPPER_ID (t));
+ pp_colon (pp);
+ }
+ dump_type (pp, TREE_TYPE (t), flags);
+ pp_cxx_right_paren (pp);
+}
+
static void
dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
{
if (VAR_P (t) && DECL_NTTP_OBJECT_P (t))
return dump_expr (pp, DECL_INITIAL (t), flags);
+ if (TREE_CODE (t) == VAR_DECL
+ && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_DECLARE_MAPPER_P (t))
+ return dump_omp_declare_mapper (pp, DECL_INITIAL (t), flags);
+
if (flags & TFF_DECL_SPECIFIERS)
{
if (concept_definition_p (t))
@@ -3217,6 +3270,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break;
}
+ case CO_AWAIT_EXPR:
+ pp_cxx_ws_string (pp, "co_await");
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ break;
+
+ case CO_YIELD_EXPR:
+ pp_cxx_ws_string (pp, "co_yield");
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ break;
+
+ case CO_RETURN_EXPR:
+ pp_cxx_ws_string (pp, "co_return");
+ if (TREE_OPERAND (t, 0))
+ {
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ }
+ break;
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
@@ -3788,18 +3862,18 @@ cp_print_error_function (diagnostic_text_output_format &text_output,
{
if (text_output.show_column_p () && s.column != 0)
pp_printf (pp,
- _(" inlined from %qD at %r%s:%d:%d%R"),
+ G_(" inlined from %qD at %r%s:%d:%d%R"),
fndecl,
"locus", s.file, s.line, s.column);
else
pp_printf (pp,
- _(" inlined from %qD at %r%s:%d%R"),
+ G_(" inlined from %qD at %r%s:%d%R"),
fndecl,
"locus", s.file, s.line);
}
else
- pp_printf (pp, _(" inlined from %qD"),
+ pp_printf (pp, G_(" inlined from %qD"),
fndecl);
}
}
@@ -3825,22 +3899,22 @@ function_category (tree fn)
&& DECL_FUNCTION_MEMBER_P (fn))
{
if (DECL_STATIC_FUNCTION_P (fn))
- return _("In static member function %qD");
+ return G_("In static member function %qD");
else if (DECL_COPY_CONSTRUCTOR_P (fn))
- return _("In copy constructor %qD");
+ return G_("In copy constructor %qD");
else if (DECL_CONSTRUCTOR_P (fn))
- return _("In constructor %qD");
+ return G_("In constructor %qD");
else if (DECL_DESTRUCTOR_P (fn))
- return _("In destructor %qD");
+ return G_("In destructor %qD");
else if (LAMBDA_FUNCTION_P (fn))
- return _("In lambda function");
+ return G_("In lambda function");
else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn))
- return _("In explicit object member function %qD");
+ return G_("In explicit object member function %qD");
else
- return _("In member function %qD");
+ return G_("In member function %qD");
}
else
- return _("In function %qD");
+ return G_("In function %qD");
}
/* Disable warnings about missing quoting in GCC diagnostics for
@@ -3867,8 +3941,8 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output)
char *indent = text_output.build_indent_prefix (true);
pp_verbatim (text_output.get_printer (),
p->list_p ()
- ? _("%s%s%sIn substitution of %qS:\n")
- : _("%s%s%sIn instantiation of %q#D:\n"),
+ ? G_("%s%s%sIn substitution of %qS:\n")
+ : G_("%s%s%sIn instantiation of %q#D:\n"),
indent,
show_file ? LOCATION_FILE (location) : "",
show_file ? ": " : "",
@@ -3888,10 +3962,10 @@ print_location (diagnostic_text_output_format &text_output,
expanded_location xloc = expand_location (loc);
pretty_printer *const pp = text_output.get_printer ();
if (text_output.show_column_p ())
- pp_verbatim (pp, _("%r%s:%d:%d:%R "),
+ pp_verbatim (pp, G_("%r%s:%d:%d:%R "),
"locus", xloc.file, xloc.line, xloc.column);
else
- pp_verbatim (pp, _("%r%s:%d:%R "),
+ pp_verbatim (pp, G_("%r%s:%d:%R "),
"locus", xloc.file, xloc.line);
}
@@ -3984,22 +4058,22 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou
if (t->list_p ())
pp_verbatim (pp,
recursive_p
- ? _("recursively required by substitution of %qS\n")
- : _("required by substitution of %qS\n"),
+ ? G_("recursively required by substitution of %qS\n")
+ : G_("required by substitution of %qS\n"),
t->get_node ());
else
pp_verbatim (pp,
recursive_p
- ? _("recursively required from %q#D\n")
- : _("required from %q#D\n"),
+ ? G_("recursively required from %q#D\n")
+ : G_("required from %q#D\n"),
t->get_node ());
}
else
{
pp_verbatim (pp,
recursive_p
- ? _("recursively required from here\n")
- : _("required from here\n"));
+ ? G_("recursively required from here\n")
+ : G_("required from here\n"));
}
}
@@ -4049,8 +4123,8 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output,
{
auto_context_line sentinel (text_output, loc);
pp_verbatim (text_output.get_printer (),
- _("[ skipping %d instantiation contexts,"
- " use -ftemplate-backtrace-limit=0 to disable ]\n"),
+ G_("[ skipping %d instantiation contexts,"
+ " use -ftemplate-backtrace-limit=0 to disable ]\n"),
skip);
do {
loc = t->locus;
@@ -4101,7 +4175,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output)
pretty_printer *const pp = text_output.get_printer ();
auto_context_line sentinel (text_output, EXPR_LOCATION (t));
pp_verbatim (pp,
- _("in %<constexpr%> expansion of %qs"),
+ G_("in %<constexpr%> expansion of %qs"),
s);
pp_newline (pp);
}
@@ -4114,7 +4188,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output,
{
auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl));
pretty_printer *const pp = text_output.get_printer ();
- pp_verbatim (pp, "required by the constraints of %q#D\n", decl);
+ pp_verbatim (pp, G_("required by the constraints of %q#D\n"), decl);
}
static void
@@ -4129,7 +4203,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output,
cxx_pretty_printer *const pp
= (cxx_pretty_printer *)text_output.get_printer ();
- pp_verbatim (pp, "required for the satisfaction of %qE", expr);
+ pp_verbatim (pp, G_("required for the satisfaction of %qE"), expr);
if (map && map != error_mark_node)
{
tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE);
@@ -4151,7 +4225,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output,
{
auto_context_line sentinel (text_output, input_location);
pretty_printer *const pp = text_output.get_printer ();
- pp_verbatim (pp, "required for constraint satisfaction\n");
+ pp_verbatim (pp, G_("required for constraint satisfaction\n"));
return NULL_TREE;
}
if (DECL_P (src))
@@ -4180,11 +4254,10 @@ print_requires_expression_info (diagnostic_text_output_format &text_output,
auto_context_line sentinel (text_output, cp_expr_loc_or_input_loc (expr));
cxx_pretty_printer *const pp
= static_cast <cxx_pretty_printer *> (text_output.get_printer ());
- pp_verbatim (pp, "in requirements ");
tree parms = TREE_OPERAND (expr, 0);
- if (parms)
- pp_verbatim (pp, "with ");
+ pp_verbatim (pp, parms ? G_("in requirements with ")
+ : G_("in requirements "));
while (parms)
{
pp_verbatim (pp, "%q#D", parms);
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index a9d8e2f..a7f35e4 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;
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e589e45..0a389fb 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3010,7 +3010,6 @@ build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree itype2)
tree atype1 = build_cplus_array_type (sizetype, itype1);
tree atype2 = build_cplus_array_type (elt_type, itype2);
tree rtype = cxx_make_type (RECORD_TYPE);
- TYPE_NAME (rtype) = heap_identifier;
tree fld1 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype1);
tree fld2 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype2);
DECL_FIELD_CONTEXT (fld1) = rtype;
@@ -3019,7 +3018,16 @@ build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree itype2)
DECL_ARTIFICIAL (fld2) = true;
TYPE_FIELDS (rtype) = fld1;
DECL_CHAIN (fld1) = fld2;
+ TYPE_ARTIFICIAL (rtype) = true;
layout_type (rtype);
+
+ tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, heap_identifier, rtype);
+ TYPE_NAME (rtype) = decl;
+ TYPE_STUB_DECL (rtype) = decl;
+ DECL_CONTEXT (decl) = NULL_TREE;
+ DECL_ARTIFICIAL (decl) = true;
+ layout_decl (decl, 0);
+
return rtype;
}
@@ -3405,7 +3413,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
errval = throw_bad_array_new_length ();
if (outer_nelts_check != NULL_TREE)
size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval);
- size = cp_fully_fold (size);
+ size = fold_to_constant (size);
/* Create the argument list. */
vec_safe_insert (*placement, 0, size);
/* Do name-lookup to find the appropriate operator. */
@@ -3462,7 +3470,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
outer_nelts_check = NULL_TREE;
}
- size = cp_fully_fold (size);
+ size = fold_to_constant (size);
/* If size is zero e.g. due to type having zero size, try to
preserve outer_nelts for constant expression evaluation
purposes. */
@@ -4747,7 +4755,8 @@ build_vec_init (tree base, tree maxindex, tree init,
itself. But that breaks when gimplify_target_expr adds a clobber
cleanup that runs before the build_vec_init cleanup. */
if (cleanup_flags)
- vec_safe_push (*cleanup_flags, build_tree_list (iterator, maxindex));
+ vec_safe_push (*cleanup_flags,
+ build_tree_list (rval, build_zero_cst (ptype)));
}
/* Should we try to create a constant initializer? */
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index ed70bb0..525e8ef 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -59,7 +59,13 @@ build_lambda_object (tree lambda_expr)
vec<constructor_elt, va_gc> *elts = NULL;
tree node, expr, type;
- if (processing_template_decl || lambda_expr == error_mark_node)
+ if (processing_template_decl && !in_template_context
+ && current_binding_level->requires_expression)
+ /* As in cp_parser_lambda_expression, don't get confused by
+ cp_parser_requires_expression setting processing_template_decl. In that
+ case we want to return the result of finish_compound_literal, to avoid
+ tsubst_lambda_expr. */;
+ else if (processing_template_decl || lambda_expr == error_mark_node)
return lambda_expr;
/* Make sure any error messages refer to the lambda-introducer. */
@@ -144,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. */
@@ -212,9 +218,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
tree type;
bool is_this = is_this_parameter (tree_strip_nop_conversions (expr));
- if (is_this)
- type = TREE_TYPE (expr);
- else if (explicit_init_p)
+ if (explicit_init_p)
{
tree auto_node = make_auto ();
@@ -253,7 +257,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
type = non_reference (unlowered_expr_type (expr));
- if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE)
+ if ((by_reference_p && !is_this) || TREE_CODE (type) == FUNCTION_TYPE)
type = build_reference_type (type);
}
@@ -342,7 +346,11 @@ insert_capture_proxy (tree var)
/* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */
var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
- tree stmt_list = (*stmt_list_stack)[1];
+ /* The first stmt_list is from start_preparsed_function. Then there's a
+ possible stmt_list from begin_eh_spec_block, then the one from the
+ lambda's outer {}. */
+ unsigned index = 1 + use_eh_spec_block (current_function_decl);
+ tree stmt_list = (*stmt_list_stack)[index];
gcc_assert (stmt_list);
append_to_statement_list_force (var, &stmt_list);
}
@@ -430,13 +438,21 @@ build_capture_proxy (tree member, tree init)
else
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
- type = lambda_proxy_type (object);
-
- if (name == this_identifier && !INDIRECT_TYPE_P (type))
+ if (name == this_identifier && TYPE_PTR_P (TREE_TYPE (member)))
+ /* Avoid DECLTYPE_TYPE for by-ref 'this' capture in an xobj lambda; the
+ constness of the closure doesn't matter just like it doesn't matter to
+ other by-ref capture. It's simpler to handle this special case here
+ than in lambda_proxy_type. */
+ type = TREE_TYPE (member);
+ else
{
- type = build_pointer_type (type);
- type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
- object = build_fold_addr_expr_with_type (object, type);
+ type = lambda_proxy_type (object);
+ if (name == this_identifier)
+ {
+ type = build_pointer_type (type);
+ type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+ object = build_fold_addr_expr_with_type (object, type);
+ }
}
if (DECL_VLA_CAPTURE_P (member))
@@ -807,6 +823,14 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
if (cp_unevaluated_operand)
add_capture_p = false;
+ /* If we captured 'this' but don't have a capture proxy yet, look up the
+ captured 'this' again. */
+ if (this_capture && TREE_CODE (this_capture) == FIELD_DECL)
+ {
+ gcc_assert (!add_capture_p);
+ this_capture = NULL_TREE;
+ }
+
/* Try to default capture 'this' if we can. */
if (!this_capture)
{
@@ -911,8 +935,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
else
{
/* To make sure that current_class_ref is for the lambda. */
- gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
- == LAMBDA_EXPR_CLOSURE (lambda));
+ gcc_assert (!current_class_ref
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
+ == LAMBDA_EXPR_CLOSURE (lambda)));
result = this_capture;
@@ -923,6 +948,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
result = rvalue (result);
}
+ gcc_checking_assert (!result || result == error_mark_node
+ || TYPE_PTR_P (TREE_TYPE (result)));
+
return result;
}
@@ -1027,12 +1055,9 @@ current_nonlambda_function (void)
tree
nonlambda_method_basetype (void)
{
- if (!current_class_ref)
- return NULL_TREE;
-
tree type = current_class_type;
if (!type || !LAMBDA_TYPE_P (type))
- return type;
+ return current_class_ref ? type : NULL_TREE;
while (true)
{
@@ -1044,7 +1069,7 @@ nonlambda_method_basetype (void)
tree fn = TYPE_CONTEXT (type);
if (!fn || TREE_CODE (fn) != FUNCTION_DECL
- || !DECL_IOBJ_MEMBER_FUNCTION_P (fn))
+ || !DECL_OBJECT_MEMBER_FUNCTION_P (fn))
/* No enclosing non-lambda method. */
return NULL_TREE;
if (!LAMBDA_FUNCTION_P (fn))
@@ -1852,6 +1877,12 @@ prune_lambda_captures (tree body)
cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars);
+ tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam)));
+ bool noexcept_p = (bind_expr
+ && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR);
+ if (noexcept_p)
+ bind_expr = expr_single (TREE_OPERAND (bind_expr, 0));
+
tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam));
for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; )
{
@@ -1859,11 +1890,23 @@ prune_lambda_captures (tree body)
if (tree var = var_to_maybe_prune (cap))
{
tree **use = const_vars.get (var);
- if (use && TREE_CODE (**use) == DECL_EXPR)
+ if (TREE_CODE (**use) == DECL_EXPR)
{
/* All uses of this capture were folded away, leaving only the
proxy declaration. */
+ if (noexcept_p)
+ {
+ /* We didn't handle noexcept lambda captures correctly before
+ the fix for PR c++/119764. */
+ if (abi_version_crosses (21))
+ warning_at (location_of (lam), OPT_Wabi, "%qD is no longer"
+ " captured in noexcept lambda in ABI v21 "
+ "(GCC 16)", var);
+ if (!abi_version_at_least (21))
+ goto next;
+ }
+
/* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST. */
*capp = TREE_CHAIN (cap);
@@ -1873,12 +1916,27 @@ prune_lambda_captures (tree body)
fieldp = &DECL_CHAIN (*fieldp);
*fieldp = DECL_CHAIN (*fieldp);
+ /* And out of the bindings for the function. */
+ tree *blockp = &BLOCK_VARS (current_binding_level->blocks);
+ while (*blockp != DECL_EXPR_DECL (**use))
+ blockp = &DECL_CHAIN (*blockp);
+ *blockp = DECL_CHAIN (*blockp);
+
+ /* And maybe out of the vars declared in the containing
+ BIND_EXPR, if it's listed there. */
+ tree *bindp = &BIND_EXPR_VARS (bind_expr);
+ while (*bindp && *bindp != DECL_EXPR_DECL (**use))
+ bindp = &DECL_CHAIN (*bindp);
+ if (*bindp)
+ *bindp = DECL_CHAIN (*bindp);
+
/* And remove the capture proxy declaration. */
**use = void_node;
continue;
}
}
+ next:
capp = &TREE_CHAIN (cap);
}
}
@@ -1892,7 +1950,7 @@ finish_lambda_function (tree body)
{
finish_function_body (body);
- prune_lambda_captures (body);
+ prune_lambda_captures (cur_stmt_list);
/* Finish the function and generate code for it if necessary. */
tree fn = finish_function (/*inline_p=*/true);
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index c12b084..08a6348 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -749,6 +749,9 @@ unqualified_name_lookup_error (tree name, location_t loc)
if (IDENTIFIER_ANY_OP_P (name))
error_at (loc, "%qD not defined", name);
+ else if (!flag_concepts && name == ridpointers[(int)RID_REQUIRES])
+ error_at (loc, "%<requires%> only available with %<-std=c++20%> or "
+ "%<-fconcepts%>");
else
{
if (!objc_diagnose_private_ivar (name))
@@ -1079,15 +1082,17 @@ copy_lang_type (tree node)
if (! TYPE_LANG_SPECIFIC (node))
return;
- auto *lt = (struct lang_type *) ggc_internal_alloc (sizeof (struct lang_type));
+ size_t sz = (c_dialect_objc () ? sizeof (struct lang_type)
+ : offsetof (struct lang_type, info));
+ auto *lt = (struct lang_type *) ggc_internal_alloc (sz);
- memcpy (lt, TYPE_LANG_SPECIFIC (node), (sizeof (struct lang_type)));
+ memcpy (lt, TYPE_LANG_SPECIFIC (node), sz);
TYPE_LANG_SPECIFIC (node) = lt;
if (GATHER_STATISTICS)
{
tree_node_counts[(int)lang_type] += 1;
- tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
+ tree_node_sizes[(int)lang_type] += sz;
}
}
@@ -1111,14 +1116,15 @@ maybe_add_lang_type_raw (tree t)
if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t)))
return false;
- auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc
- (sizeof (struct lang_type)));
+ size_t sz = (c_dialect_objc () ? sizeof (struct lang_type)
+ : offsetof (struct lang_type, info));
+ auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc (sz));
TYPE_LANG_SPECIFIC (t) = lt;
if (GATHER_STATISTICS)
{
tree_node_counts[(int)lang_type] += 1;
- tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
+ tree_node_sizes[(int)lang_type] += sz;
}
return true;
@@ -1132,8 +1138,8 @@ cxx_make_type (enum tree_code code MEM_STAT_DECL)
if (maybe_add_lang_type_raw (t))
{
/* Set up some flags that give proper default behavior. */
- struct c_fileinfo *finfo =
- get_fileinfo (LOCATION_FILE (input_location));
+ struct c_fileinfo *finfo
+ = get_fileinfo (LOCATION_FILE (input_location));
SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown);
CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
}
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 02129c6..13d5ded 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -1048,6 +1048,12 @@ decl_mangling_context (tree decl)
tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl));
if (extra)
return extra;
+ tcontext = CP_DECL_CONTEXT (decl);
+ if (LAMBDA_TYPE_P (tcontext))
+ /* Lambda type context means this lambda appears between the
+ lambda-introducer and the open brace of another lambda (c++/119175).
+ That isn't a real scope; look further into the enclosing scope. */
+ return decl_mangling_context (TYPE_NAME (tcontext));
}
else if (template_type_parameter_p (decl))
/* template type parms have no mangling context. */
@@ -4446,23 +4452,12 @@ static tree
mangle_decl_string (const tree decl)
{
tree result;
- tree saved_fn = NULL_TREE;
- bool template_p = false;
+ tree saved_fn = current_function_decl;
/* We shouldn't be trying to mangle an uninstantiated template. */
gcc_assert (!type_dependent_expression_p (decl));
- if (DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
- {
- struct tinst_level *tl = current_instantiation ();
- if ((!tl || tl->maybe_get_node () != decl)
- && push_tinst_level (decl))
- {
- template_p = true;
- saved_fn = current_function_decl;
- current_function_decl = NULL_TREE;
- }
- }
+ current_function_decl = NULL_TREE;
iloc_sentinel ils (DECL_SOURCE_LOCATION (decl));
start_mangling (decl);
@@ -4477,12 +4472,7 @@ mangle_decl_string (const tree decl)
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
IDENTIFIER_POINTER (result));
- if (template_p)
- {
- pop_tinst_level ();
- current_function_decl = saved_fn;
- }
-
+ current_function_decl = saved_fn;
return result;
}
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 05c19cf..a4089c5 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from)
const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
+ if (ABSTRACT_CLASS_TYPE_P (to))
+ return error_mark_node;
tree ctype = to;
vec<tree, va_gc> *args = NULL;
if (!TYPE_REF_P (to))
@@ -2330,6 +2332,37 @@ constructible_expr (tree to, tree from)
return expr;
}
+/* Valid if "Either T is a reference type, or T is a complete object type for
+ which the expression declval<U&>().~U() is well-formed when treated as an
+ unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>."
+
+ For a class U, return the destructor call; otherwise return void_node if
+ valid or error_mark_node if not. */
+
+static tree
+destructible_expr (tree to)
+{
+ cp_unevaluated cp_uneval_guard;
+ 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;
+ to = strip_array_types (to);
+ if (CLASS_TYPE_P (to))
+ {
+ to = build_trait_object (to);
+ return build_delete (input_location, TREE_TYPE (to), to,
+ sfk_complete_destructor, flags, 0, tf_none);
+ }
+ /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
+ shall be a scalar type.... */
+ else if (scalarish_type_p (to))
+ return void_node;
+ else
+ return error_mark_node;
+}
+
/* 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. */
@@ -2339,13 +2372,15 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
{
to = complete_type (to);
deferring_access_check_sentinel acs (dk_no_deferred);
- if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+ if (VOID_TYPE_P (to)
|| (from && FUNC_OR_METHOD_TYPE_P (from)
&& (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
return error_mark_node;
tree expr;
if (code == MODIFY_EXPR)
expr = assignable_expr (to, from);
+ 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
@@ -2949,7 +2984,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
&& BINFO_VIRTUAL_P (base_binfo)
&& fn && TREE_CODE (fn) == FUNCTION_DECL
&& move_fn_p (fn) && !trivial_fn_p (fn)
- && vbase_has_user_provided_move_assign (BINFO_TYPE (base_binfo)))
+ && vbase_has_user_provided_move_assign (BINFO_TYPE (base_binfo))
+ && warning_enabled_at (DECL_SOURCE_LOCATION (fn),
+ OPT_Wvirtual_move_assign))
warning (OPT_Wvirtual_move_assign,
"defaulted move assignment for %qT calls a non-trivial "
"move assignment operator for virtual base %qT",
@@ -2987,7 +3024,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
/* Vbase cdtors are not relevant. */;
else
{
- if (constexpr_p)
+ if (constexpr_p && cxx_dialect < cxx26)
*constexpr_p = false;
FOR_EACH_VEC_ELT (*vbases, i, base_binfo)
@@ -3914,5 +3951,26 @@ num_artificial_parms_for (const_tree fn)
return count;
}
+/* Return value of the __builtin_type_order trait. */
+
+tree
+type_order_value (tree type1, tree type2)
+{
+ tree rettype = lookup_comparison_category (cc_strong_ordering);
+ if (rettype == error_mark_node)
+ return rettype;
+ int ret;
+ if (type1 == type2)
+ ret = 0;
+ else
+ {
+ const char *name1 = ASTRDUP (mangle_type_string (type1));
+ const char *name2 = mangle_type_string (type2);
+ ret = strcmp (name1, name2);
+ }
+ return lookup_comparison_result (cc_strong_ordering, rettype,
+ ret == 0 ? 0 : ret > 0 ? 1 : 2);
+}
+
#include "gt-cp-method.h"
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 894c70f..689319a 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2811,12 +2811,13 @@ enum tree_tag {
tt_decl, /* By-value mergeable decl. */
tt_tpl_parm, /* Template parm. */
- /* The ordering of the following 4 is relied upon in
+ /* The ordering of the following 5 is relied upon in
trees_out::tree_node. */
tt_id, /* Identifier node. */
tt_conv_id, /* Conversion operator name. */
tt_anon_id, /* Anonymous name. */
tt_lambda_id, /* Lambda name. */
+ tt_internal_id, /* Internal name. */
tt_typedef_type, /* A (possibly implicit) typedefed type. */
tt_derived_type, /* A type derived from another type. */
@@ -3096,6 +3097,9 @@ private:
unsigned section;
bool writing_local_entities; /* Whether we might walk into a TU-local
entity we need to emit placeholders for. */
+ bool walking_bit_field_unit; /* Whether we're walking the underlying
+ storage for a bit field. There's no other
+ great way to detect this. */
#if CHECKING_P
int importedness; /* Checker that imports not occurring
inappropriately. +ve imports ok,
@@ -3262,7 +3266,7 @@ trees_out::trees_out (allocator *mem, module_state *state, depset::hash &deps,
unsigned section)
:parent (mem), state (state), tree_map (500),
dep_hash (&deps), ref_num (0), section (section),
- writing_local_entities (false)
+ writing_local_entities (false), walking_bit_field_unit (false)
{
#if CHECKING_P
importedness = 0;
@@ -3879,6 +3883,10 @@ 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 *,
+ unsigned *);
+ bool read_diagnostic_classification (diagnostic_context *);
+
private:
void write_define (bytes_out &, const cpp_macro *);
cpp_macro *read_define (bytes_in &, cpp_reader *) const;
@@ -5546,8 +5554,10 @@ trees_in::start (unsigned code)
enum class importer_interface {
unknown, /* The definition may or may not need to be emitted. */
- always_import, /* The definition can always be found in another TU. */
- always_emit, /* The definition must be emitted in the importer's TU. */
+ external, /* The definition can always be found in another TU. */
+ internal, /* The definition should be emitted in the importer's TU. */
+ always_emit, /* The definition must be emitted in the importer's TU,
+ regardless of if it's used or not. */
};
/* Returns what kind of interface an importer will have of DECL. */
@@ -5558,13 +5568,13 @@ get_importer_interface (tree decl)
/* Internal linkage entities must be emitted in each importer if
there is a definition available. */
if (!TREE_PUBLIC (decl))
- return importer_interface::always_emit;
+ return importer_interface::internal;
- /* Entities that aren't vague linkage are either not definitions or
- will be emitted in this TU, so importers can just refer to an
- external definition. */
+ /* Other entities that aren't vague linkage are either not definitions
+ or will be publicly emitted in this TU, so importers can just refer
+ to an external definition. */
if (!vague_linkage_p (decl))
- return importer_interface::always_import;
+ return importer_interface::external;
/* For explicit instantiations, importers can always rely on there
being a definition in another TU, unless this is a definition
@@ -5574,13 +5584,13 @@ get_importer_interface (tree decl)
&& DECL_EXPLICIT_INSTANTIATION (decl))
return (header_module_p () && !DECL_EXTERNAL (decl)
? importer_interface::always_emit
- : importer_interface::always_import);
+ : importer_interface::external);
/* A gnu_inline function is never emitted in any TU. */
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)
&& lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
- return importer_interface::always_import;
+ return importer_interface::external;
/* Everything else has vague linkage. */
return importer_interface::unknown;
@@ -5723,28 +5733,16 @@ trees_out::core_bools (tree t, bits_out& bits)
== that was a lie, it is here */
bool is_external = t->decl_common.decl_flag_1;
- if (!is_external)
- /* decl_flag_1 is DECL_EXTERNAL. Things we emit here, might
- well be external from the POV of an importer. */
- // FIXME: Do we need to know if this is a TEMPLATE_RESULT --
- // a flag from the caller?
- switch (code)
- {
- default:
- break;
-
- case VAR_DECL:
- if (TREE_PUBLIC (t)
- && DECL_VTABLE_OR_VTT_P (t))
- /* We handle vtable linkage specially. */
- is_external = true;
- gcc_fallthrough ();
- case FUNCTION_DECL:
- if (get_importer_interface (t)
- == importer_interface::always_import)
- is_external = true;
- break;
- }
+ /* maybe_emit_vtables relies on vtables being marked as
+ DECL_EXTERNAL and DECL_NOT_REALLY_EXTERN before processing. */
+ if (!is_external && VAR_P (t) && DECL_VTABLE_OR_VTT_P (t))
+ is_external = true;
+ /* Things we emit here might well be external from the POV of an
+ importer. */
+ if (!is_external
+ && VAR_OR_FUNCTION_DECL_P (t)
+ && get_importer_interface (t) == importer_interface::external)
+ is_external = true;
WB (is_external);
}
@@ -6024,7 +6022,7 @@ trees_out::lang_decl_bools (tree t, bits_out& bits)
WB (lang->u.fn.has_dependent_explicit_spec_p);
WB (lang->u.fn.immediate_fn_p);
WB (lang->u.fn.maybe_deleted);
- /* We do not stream lang->u.fn.implicit_constexpr. */
+ WB (lang->u.fn.implicit_constexpr);
WB (lang->u.fn.escalated_p);
WB (lang->u.fn.xobj_func);
goto lds_min;
@@ -6095,7 +6093,7 @@ trees_in::lang_decl_bools (tree t, bits_in& bits)
RB (lang->u.fn.has_dependent_explicit_spec_p);
RB (lang->u.fn.immediate_fn_p);
RB (lang->u.fn.maybe_deleted);
- /* We do not stream lang->u.fn.implicit_constexpr. */
+ RB (lang->u.fn.implicit_constexpr);
RB (lang->u.fn.escalated_p);
RB (lang->u.fn.xobj_func);
goto lds_min;
@@ -6517,7 +6515,10 @@ trees_out::core_vals (tree t)
case FIELD_DECL:
WT (t->field_decl.offset);
WT (t->field_decl.bit_field_type);
- WT (t->field_decl.qualifier); /* bitfield unit. */
+ {
+ auto ovr = make_temp_override (walking_bit_field_unit, true);
+ WT (t->field_decl.qualifier); /* bitfield unit. */
+ }
WT (t->field_decl.bit_offset);
WT (t->field_decl.fcontext);
WT (t->decl_common.initial);
@@ -7386,7 +7387,7 @@ trees_out::lang_decl_vals (tree t)
WU (lang->u.fn.ovl_op_code);
}
- if (DECL_CLASS_SCOPE_P (t))
+ if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t))
WT (lang->u.fn.context);
if (lang->u.fn.thunk_p)
@@ -7470,7 +7471,7 @@ trees_in::lang_decl_vals (tree t)
lang->u.fn.ovl_op_code = code;
}
- if (DECL_CLASS_SCOPE_P (t))
+ if (DECL_CLASS_SCOPE_P (t) || DECL_UNIQUE_FRIEND_P (t))
RT (lang->u.fn.context);
if (lang->u.fn.thunk_p)
@@ -8097,18 +8098,37 @@ trees_in::install_entity (tree decl)
gcc_checking_assert (!existed);
slot = ident;
}
- else if (state->is_partition ())
+ else
{
- /* The decl is already in the entity map, but we see it again now from a
- partition: we want to overwrite if the original decl wasn't also from
- a (possibly different) partition. Otherwise, for things like template
- instantiations, make_dependency might not realise that this is also
- provided from a partition and should be considered part of this module
- (and thus always emitted into the primary interface's CMI). */
unsigned *slot = entity_map->get (DECL_UID (decl));
- module_state *imp = import_entity_module (*slot);
- if (!imp->is_partition ())
- *slot = ident;
+
+ /* The entity must be in the entity map already. However, DECL may
+ be the DECL_TEMPLATE_RESULT of an existing partial specialisation
+ if we matched it while streaming another instantiation; in this
+ case we already registered that TEMPLATE_DECL. */
+ if (!slot)
+ {
+ tree type = TREE_TYPE (decl);
+ gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL
+ && CLASS_TYPE_P (type)
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (type));
+ slot = entity_map->get (DECL_UID (CLASSTYPE_TI_TEMPLATE (type)));
+ }
+ gcc_checking_assert (slot);
+
+ if (state->is_partition ())
+ {
+ /* The decl is already in the entity map, but we see it again now
+ from a partition: we want to overwrite if the original decl
+ wasn't also from a (possibly different) partition. Otherwise,
+ for things like template instantiations, make_dependency might
+ not realise that this is also provided from a partition and
+ should be considered part of this module (and thus always
+ emitted into the primary interface's CMI). */
+ module_state *imp = import_entity_module (*slot);
+ if (!imp->is_partition ())
+ *slot = ident;
+ }
}
return true;
@@ -8199,6 +8219,10 @@ trees_out::decl_value (tree decl, depset *dep)
inner = DECL_TEMPLATE_RESULT (decl);
inner_tag = insert (inner, WK_value);
+ /* On stream-in we assume that a template and its result will
+ have the same type. */
+ gcc_checking_assert (TREE_TYPE (decl) == TREE_TYPE (inner));
+
if (streaming_p ())
{
int code = TREE_CODE (inner);
@@ -9004,25 +9028,28 @@ trees_out::decl_node (tree decl, walk_kind ref)
if (streaming_p ())
i (tt_parm);
tree_node (DECL_CONTEXT (decl));
- if (streaming_p ())
- {
- /* That must have put this in the map. */
- walk_kind ref = ref_node (decl);
- if (ref != WK_none)
- // FIXME:OPTIMIZATION We can wander into bits of the
- // template this was instantiated from. For instance
- // deferred noexcept and default parms. Currently we'll
- // end up cloning those bits of tree. It would be nice
- // to reference those specific nodes. I think putting
- // those things in the map when we reference their
- // template by name. See the note in add_indirects.
- return true;
- dump (dumper::TREE)
- && dump ("Wrote %s reference %N",
- TREE_CODE (decl) == PARM_DECL ? "parameter" : "result",
- decl);
- }
+ /* That must have put this in the map. */
+ walk_kind ref = ref_node (decl);
+ if (ref != WK_none)
+ // FIXME:OPTIMIZATION We can wander into bits of the
+ // template this was instantiated from, for instance
+ // deferred noexcept and default parms, or references
+ // to parms from earlier forward-decls (PR c++/119608).
+ //
+ // Currently we'll end up cloning those bits of tree.
+ // It would be nice to reference those specific nodes.
+ // I think putting those things in the map when we
+ // reference their template by name.
+ //
+ // See the note in add_indirects.
+ return true;
+
+ if (streaming_p ())
+ dump (dumper::TREE)
+ && dump ("Wrote %s reference %N",
+ TREE_CODE (decl) == PARM_DECL ? "parameter" : "result",
+ decl);
}
return false;
@@ -9350,6 +9377,7 @@ trees_out::type_node (tree type)
tree root = (TYPE_NAME (type)
? TREE_TYPE (TYPE_NAME (type)) : TYPE_MAIN_VARIANT (type));
+ gcc_checking_assert (root);
if (type != root)
{
@@ -9428,6 +9456,8 @@ trees_out::type_node (tree type)
|| TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
{
+ gcc_checking_assert (DECL_P (name));
+
/* We can meet template parms that we didn't meet in the
tpl_parms walk, because we're referring to a derived type
that was previously constructed from equivalent template
@@ -9589,6 +9619,8 @@ trees_out::type_node (tree type)
tag_type = enum_type;
else if (TYPENAME_IS_CLASS_P (type))
tag_type = class_type;
+ else if (TYPENAME_IS_UNION_P (type))
+ tag_type = union_type;
u (int (tag_type));
}
}
@@ -9642,11 +9674,14 @@ trees_out::tree_value (tree t)
if (DECL_P (t))
/* No template, type, var or function, except anonymous
- non-context vars. */
+ non-context vars and types. */
gcc_checking_assert ((TREE_CODE (t) != TEMPLATE_DECL
- && TREE_CODE (t) != TYPE_DECL
+ && (TREE_CODE (t) != TYPE_DECL
+ || (DECL_ARTIFICIAL (t) && !DECL_CONTEXT (t)))
&& (TREE_CODE (t) != VAR_DECL
- || (!DECL_NAME (t) && !DECL_CONTEXT (t)))
+ || ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
+ && !DECL_CONTEXT (t)))
&& TREE_CODE (t) != FUNCTION_DECL));
if (streaming_p ())
@@ -9658,7 +9693,7 @@ trees_out::tree_value (tree t)
tree_node_bools (t);
}
- if (TREE_CODE (t) == TREE_BINFO)
+ if (TREE_CODE (t) == TREE_BINFO)
/* Binfos are decl-like and need merging information. */
binfo_mergeable (t);
@@ -9667,8 +9702,57 @@ trees_out::tree_value (tree t)
dump (dumper::TREE)
&& dump ("Writing tree:%d %C:%N", tag, TREE_CODE (t), t);
+ int type_tag = 0;
+ tree type = NULL_TREE;
+ if (TREE_CODE (t) == TYPE_DECL)
+ {
+ type = TREE_TYPE (t);
+
+ /* We only support a limited set of features for uncontexted types;
+ these are typically types created in the language-independent
+ parts of the frontend (such as ubsan). */
+ gcc_checking_assert (RECORD_OR_UNION_TYPE_P (type)
+ && TYPE_MAIN_VARIANT (type) == type
+ && TYPE_NAME (type) == t
+ && TYPE_STUB_DECL (type) == t
+ && !TYPE_VFIELD (type)
+ && !TYPE_BINFO (type)
+ && !CLASS_TYPE_P (type));
+
+ if (streaming_p ())
+ {
+ start (type);
+ tree_node_bools (type);
+ }
+
+ type_tag = insert (type, WK_value);
+ if (streaming_p ())
+ dump (dumper::TREE)
+ && dump ("Writing type: %d %C:%N", type_tag,
+ TREE_CODE (type), type);
+ }
+
tree_node_vals (t);
+ if (type)
+ {
+ tree_node_vals (type);
+ tree_node (TYPE_SIZE (type));
+ tree_node (TYPE_SIZE_UNIT (type));
+ chained_decls (TYPE_FIELDS (type));
+ if (streaming_p ())
+ dump (dumper::TREE)
+ && dump ("Written type:%d %C:%N", type_tag, TREE_CODE (type), type);
+ }
+
+ /* For uncontexted VAR_DECLs we need to stream the definition so that
+ importers can recreate their value. */
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ gcc_checking_assert (!DECL_NONTRIVIALLY_INITIALIZED_P (t));
+ tree_node (DECL_INITIAL (t));
+ }
+
if (streaming_p ())
dump (dumper::TREE) && dump ("Written tree:%d %C:%N", tag, TREE_CODE (t), t);
}
@@ -9707,14 +9791,55 @@ trees_in::tree_value ()
dump (dumper::TREE)
&& dump ("Reading tree:%d %C", tag, TREE_CODE (t));
- if (!tree_node_vals (t))
+ int type_tag = 0;
+ tree type = NULL_TREE;
+ if (TREE_CODE (t) == TYPE_DECL)
{
+ type = start ();
+ if (!type || !tree_node_bools (type))
+ t = NULL_TREE;
+
+ type_tag = insert (type);
+ if (t)
+ dump (dumper::TREE)
+ && dump ("Reading type:%d %C", type_tag, TREE_CODE (type));
+ }
+
+ if (!t)
+ {
+bail:
back_refs[~tag] = NULL_TREE;
+ if (type_tag)
+ back_refs[~type_tag] = NULL_TREE;
set_overrun ();
- /* Bail. */
return NULL_TREE;
}
+ if (!tree_node_vals (t))
+ goto bail;
+
+ if (type)
+ {
+ if (!tree_node_vals (type))
+ goto bail;
+
+ TYPE_SIZE (type) = tree_node ();
+ TYPE_SIZE_UNIT (type) = tree_node ();
+ TYPE_FIELDS (type) = chained_decls ();
+ if (get_overrun ())
+ goto bail;
+
+ dump (dumper::TREE)
+ && dump ("Read type:%d %C:%N", type_tag, TREE_CODE (type), type);
+ }
+
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ DECL_INITIAL (t) = tree_node ();
+ if (TREE_STATIC (t))
+ varpool_node::finalize_decl (t);
+ }
+
if (TREE_CODE (t) == LAMBDA_EXPR
&& CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t)))
{
@@ -9857,10 +9982,13 @@ trees_out::tree_node (tree t)
if (TREE_CODE (t) == IDENTIFIER_NODE)
{
- /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id. */
+ /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id,
+ tt_internal_id. */
int code = tt_id;
if (IDENTIFIER_ANON_P (t))
code = IDENTIFIER_LAMBDA_P (t) ? tt_lambda_id : tt_anon_id;
+ else if (IDENTIFIER_INTERNAL_P (t))
+ code = tt_internal_id;
else if (IDENTIFIER_CONV_OP_P (t))
code = tt_conv_id;
@@ -9875,13 +10003,15 @@ trees_out::tree_node (tree t)
}
else if (code == tt_id && streaming_p ())
str (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
+ else if (code == tt_internal_id && streaming_p ())
+ str (prefix_for_internal_label (t));
int tag = insert (t);
if (streaming_p ())
{
- /* We know the ordering of the 4 id tags. */
+ /* We know the ordering of the 5 id tags. */
static const char *const kinds[] =
- {"", "conv_op ", "anon ", "lambda "};
+ {"", "conv_op ", "anon ", "lambda ", "internal "};
dump (dumper::TREE)
&& dump ("Written:%d %sidentifier:%N", tag,
kinds[code - tt_id],
@@ -9958,8 +10088,11 @@ trees_out::tree_node (tree t)
break;
case VAR_DECL:
- /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs. */
- gcc_checking_assert (!DECL_NAME (t)
+ /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs,
+ and internal vars are created by sanitizers and
+ __builtin_source_location. */
+ gcc_checking_assert ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
&& DECL_ARTIFICIAL (t));
break;
@@ -9968,7 +10101,18 @@ trees_out::tree_node (tree t)
PARM_DECLS. It'd be nice if they had a
distinguishing flag to double check. */
break;
+
+ case TYPE_DECL:
+ /* Some parts of the compiler need internal struct types;
+ these types may not have an appropriate context to use.
+ Walk the whole type (including its definition) by value. */
+ gcc_checking_assert (DECL_ARTIFICIAL (t)
+ && TYPE_ARTIFICIAL (TREE_TYPE (t))
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))
+ && !CLASS_TYPE_P (TREE_TYPE (t)));
+ break;
}
+ mark_declaration (t, has_definition (t));
goto by_value;
}
}
@@ -10105,6 +10249,17 @@ trees_in::tree_node (bool is_use)
}
break;
+ case tt_internal_id:
+ /* An internal label. */
+ {
+ const char *prefix = str ();
+ res = generate_internal_label (prefix);
+ int tag = insert (res);
+ dump (dumper::TREE)
+ && dump ("Read internal identifier:%d %N", tag, res);
+ }
+ break;
+
case tt_typedef_type:
res = tree_node ();
if (res)
@@ -10500,7 +10655,8 @@ trees_in::tree_node (bool is_use)
res = lookup_field_ident (ctx, u ());
if (!res
- || TREE_CODE (res) != FIELD_DECL
+ || (TREE_CODE (res) != FIELD_DECL
+ && TREE_CODE (res) != USING_DECL)
|| DECL_CONTEXT (res) != ctx)
res = NULL_TREE;
}
@@ -11107,6 +11263,11 @@ trees_out::get_merge_kind (tree decl, depset *dep)
return MK_local_friend;
gcc_checking_assert (TYPE_P (ctx));
+
+ /* Internal-only types will not need to dedup their members. */
+ if (!DECL_CONTEXT (TYPE_NAME (ctx)))
+ return MK_unique;
+
if (TREE_CODE (decl) == USING_DECL)
return MK_field;
@@ -11119,15 +11280,16 @@ trees_out::get_merge_kind (tree decl, depset *dep)
return MK_named;
}
- if (!DECL_NAME (decl)
- && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
- && !DECL_BIT_FIELD_REPRESENTATIVE (decl))
+ if (walking_bit_field_unit)
{
/* The underlying storage unit for a bitfield. We do not
need to dedup it, because it's only reachable through
the bitfields it represents. And those are deduped. */
// FIXME: Is that assertion correct -- do we ever fish it
// out and put it in an expr?
+ gcc_checking_assert (!DECL_NAME (decl)
+ && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
+ && !DECL_BIT_FIELD_REPRESENTATIVE (decl));
gcc_checking_assert ((TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
? TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
: TREE_CODE (TREE_TYPE (decl)))
@@ -12087,6 +12249,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
}
+ // FIXME: do more precise errors at point of mismatch
+ const char *mismatch_msg = nullptr;
if (TREE_CODE (d_inner) == FUNCTION_DECL)
{
tree e_ret = fndecl_declared_return_type (existing);
@@ -12096,13 +12260,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
&& LAMBDA_TYPE_P (DECL_CONTEXT (d_inner)))
/* This has a recursive type that will compare different. */;
else if (!same_type_p (d_ret, e_ret))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting type for imported declaration %#qD");
+ goto mismatch;
+ }
tree e_type = TREE_TYPE (e_inner);
tree d_type = TREE_TYPE (d_inner);
if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting language linkage for imported "
+ "declaration %#qD");
+ goto mismatch;
+ }
for (tree e_args = TYPE_ARG_TYPES (e_type),
d_args = TYPE_ARG_TYPES (d_type);
@@ -12110,10 +12281,18 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args))
{
if (!(e_args && d_args))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting argument list for imported "
+ "declaration %#qD");
+ goto mismatch;
+ }
if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args)))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting argument types for imported "
+ "declaration %#qD");
+ goto mismatch;
+ }
}
/* If EXISTING has an undeduced or uninstantiated exception
@@ -12122,7 +12301,7 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
instantiate it in the middle of loading. */
tree e_spec = TYPE_RAISES_EXCEPTIONS (e_type);
tree d_spec = TYPE_RAISES_EXCEPTIONS (d_type);
- if (DEFERRED_NOEXCEPT_SPEC_P (e_spec))
+ if (DECL_MAYBE_DELETED (e_inner) || DEFERRED_NOEXCEPT_SPEC_P (e_spec))
{
if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
|| (UNEVALUATED_NOEXCEPT_SPEC_P (e_spec)
@@ -12144,9 +12323,14 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
}
}
}
- else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
+ else if (!DECL_MAYBE_DELETED (d_inner)
+ && !DEFERRED_NOEXCEPT_SPEC_P (d_spec)
&& !comp_except_specs (d_spec, e_spec, ce_type))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting %<noexcept%> specifier for "
+ "imported declaration %#qD");
+ goto mismatch;
+ }
/* Similarly if EXISTING has an undeduced return type, but DECL's
is already deduced. */
@@ -12154,26 +12338,65 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
{
dump (dumper::MERGE)
&& dump ("Propagating deduced return type to %N", existing);
- FNDECL_USED_AUTO (e_inner) = true;
+ gcc_checking_assert (existing == e_inner);
+ FNDECL_USED_AUTO (existing) = true;
DECL_SAVED_AUTO_RETURN_TYPE (existing) = TREE_TYPE (e_type);
TREE_TYPE (existing) = change_return_type (TREE_TYPE (d_type), e_type);
}
else if (type_uses_auto (d_ret)
&& !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type)))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting deduced return type for "
+ "imported declaration %#qD");
+ goto mismatch;
+ }
+
+ /* Similarly if EXISTING has undeduced constexpr, but DECL's
+ is already deduced. */
+ if (DECL_DECLARED_CONSTEXPR_P (e_inner)
+ == DECL_DECLARED_CONSTEXPR_P (d_inner))
+ /* Already matches. */;
+ else if (DECL_DECLARED_CONSTEXPR_P (d_inner)
+ && (DECL_MAYBE_DELETED (e_inner)
+ || decl_implicit_constexpr_p (d_inner)))
+ /* DECL was deduced, copy to EXISTING. */
+ {
+ DECL_DECLARED_CONSTEXPR_P (e_inner) = true;
+ if (decl_implicit_constexpr_p (d_inner))
+ DECL_LANG_SPECIFIC (e_inner)->u.fn.implicit_constexpr = true;
+ }
+ else if (DECL_DECLARED_CONSTEXPR_P (e_inner)
+ && (DECL_MAYBE_DELETED (d_inner)
+ || decl_implicit_constexpr_p (e_inner)))
+ /* EXISTING was deduced, leave it alone. */;
+ else
+ {
+ mismatch_msg = G_("conflicting %<constexpr%> for imported "
+ "declaration %#qD");
+ goto mismatch;
+ }
+
+ /* Don't synthesize a defaulted function if we're importing one
+ we've already determined. */
+ if (!DECL_MAYBE_DELETED (d_inner))
+ DECL_MAYBE_DELETED (e_inner) = false;
}
else if (is_typedef)
{
if (!DECL_ORIGINAL_TYPE (e_inner)
|| !same_type_p (DECL_ORIGINAL_TYPE (d_inner),
DECL_ORIGINAL_TYPE (e_inner)))
- goto mismatch;
+ {
+ mismatch_msg = G_("conflicting imported declaration %q#D");
+ goto mismatch;
+ }
}
/* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs
here. I suspect the entities that directly do that are things
that shouldn't go to duplicate_decls (FIELD_DECLs etc). */
else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing)))
{
+ mismatch_msg = G_("conflicting type for imported declaration %#qD");
mismatch:
if (DECL_IS_UNDECLARED_BUILTIN (existing))
/* Just like duplicate_decls, presum the user knows what
@@ -12186,11 +12409,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
equality isn't feasible in general for local entities. */;
else
{
- // FIXME:QOI Might be template specialization from a module,
- // not necessarily global module
+ gcc_checking_assert (mismatch_msg);
auto_diagnostic_group d;
- error_at (DECL_SOURCE_LOCATION (decl),
- "conflicting global module declaration %#qD", decl);
+ error_at (DECL_SOURCE_LOCATION (decl), mismatch_msg, decl);
inform (DECL_SOURCE_LOCATION (existing),
"existing declaration %#qD", existing);
return false;
@@ -12587,7 +12808,11 @@ trees_out::write_function_def (tree decl)
{
unsigned flags = 0;
- flags |= 1 * DECL_NOT_REALLY_EXTERN (decl);
+ /* Whether the importer should emit this definition, if used. */
+ flags |= 1 * (DECL_NOT_REALLY_EXTERN (decl)
+ && (get_importer_interface (decl)
+ != importer_interface::external));
+
if (f)
{
flags |= 2;
@@ -12679,9 +12904,10 @@ trees_in::read_function_def (tree decl, tree maybe_template)
void
trees_out::write_var_def (tree decl)
{
- /* The initializer of a variable or variable template is ignored for
- determining exposures. */
- auto ovr = make_temp_override (dep_hash->ignore_tu_local, VAR_P (decl));
+ /* The initializer of a non-inline variable or variable template is
+ ignored for determining exposures. */
+ auto ovr = make_temp_override (dep_hash->ignore_tu_local,
+ VAR_P (decl) && !DECL_INLINE_VAR_P (decl));
tree init = DECL_INITIAL (decl);
tree_node (init);
@@ -13167,13 +13393,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;
@@ -14010,9 +14242,10 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
streaming the definition in such cases. */
dep->clear_flag_bit<DB_DEFN_BIT> ();
- if (DECL_DECLARED_CONSTEXPR_P (decl))
- /* Also, a constexpr variable initialized to a TU-local
- value is an exposure. */
+ if (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_INLINE_VAR_P (decl))
+ /* A constexpr variable initialized to a TU-local value,
+ or an inline value (PR c++/119996), is an exposure. */
dep->set_flag_bit<DB_EXPOSURE_BIT> ();
}
}
@@ -14770,9 +15003,16 @@ depset::hash::find_dependencies (module_state *module)
}
walker.end ();
+ /* If we see either a class template or a deduction guide, make
+ sure to add all visible deduction guides. We need to check
+ both in case they have been added in separate modules, or
+ one is in the GMF and would have otherwise been discarded. */
if (!is_key_order ()
&& DECL_CLASS_TEMPLATE_P (decl))
add_deduction_guides (decl);
+ if (!is_key_order ()
+ && deduction_guide_p (decl))
+ add_deduction_guides (TYPE_NAME (TREE_TYPE (TREE_TYPE (decl))));
if (!is_key_order ()
&& TREE_CODE (decl) == TEMPLATE_DECL
@@ -14973,12 +15213,24 @@ depset::hash::finalize_dependencies ()
break;
}
- if (!explained && VAR_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
+ if (!explained
+ && VAR_P (decl)
+ && (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_INLINE_VAR_P (decl)))
{
auto_diagnostic_group d;
- error_at (DECL_SOURCE_LOCATION (decl),
- "%qD is declared %<constexpr%> and is initialized to "
- "a TU-local value", decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD is declared %<constexpr%> and is initialized to "
+ "a TU-local value", decl);
+ else
+ {
+ /* This can only occur with references. */
+ gcc_checking_assert (TYPE_REF_P (TREE_TYPE (decl)));
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%qD is a reference declared %<inline%> and is "
+ "constant-initialized to a TU-local value", decl);
+ }
bool informed = is_tu_local_value (decl, DECL_INITIAL (decl),
/*explain=*/true);
gcc_checking_assert (informed);
@@ -16678,6 +16930,15 @@ module_state::read_cluster (unsigned snum)
#endif
cfun->returns_struct = aggr;
expand_or_defer_fn (decl);
+
+ /* If we first see this function after at_eof, it doesn't get
+ note_vague_linkage_fn from tentative_decl_linkage, so the loop in
+ c_parse_final_cleanups won't consider it. But with DECL_COMDAT we
+ can just clear DECL_EXTERNAL and let cgraph decide.
+ FIXME handle this outside module.cc after GCC 15. */
+ if (at_eof && DECL_COMDAT (decl) && DECL_EXTERNAL (decl)
+ && DECL_NOT_REALLY_EXTERN (decl))
+ DECL_EXTERNAL (decl) = false;
}
}
@@ -16760,11 +17021,15 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
bytes_out sec (to);
sec.begin ();
+ hash_map<tree, unsigned> ns_map;
+
for (unsigned ix = 0; ix != num; ix++)
{
depset *b = spaces[ix];
tree ns = b->get_entity ();
+ ns_map.put (ns, ix);
+
/* This could be an anonymous namespace even for a named module,
since we can still emit no-linkage decls. */
gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL);
@@ -16806,6 +17071,31 @@ module_state::write_namespaces (elf_out *to, vec<depset *> spaces,
}
}
+ /* Now write exported using-directives, as a sequence of 1-origin indices in
+ the spaces array (not entity indices): First the using namespace, then the
+ used namespaces. And then a zero terminating the list. :: is
+ represented as index -1. */
+ auto emit_one_ns = [&](unsigned ix, tree ns) {
+ for (auto udir: NAMESPACE_LEVEL (ns)->using_directives)
+ {
+ if (TREE_CODE (udir) != USING_DECL || !DECL_MODULE_EXPORT_P (udir))
+ continue;
+ tree ns2 = USING_DECL_DECLS (udir);
+ dump() && dump ("Writing using-directive in %N for %N",
+ ns, ns2);
+ sec.u (ix);
+ sec.u (*ns_map.get (ns2) + 1);
+ }
+ };
+ emit_one_ns (-1, global_namespace);
+ for (unsigned ix = 0; ix != num; ix++)
+ {
+ depset *b = spaces[ix];
+ tree ns = b->get_entity ();
+ emit_one_ns (ix + 1, ns);
+ }
+ sec.u (0);
+
sec.end (to, to->name (MOD_SNAME_PFX ".nms"), crc_p);
dump.outdent ();
}
@@ -16824,6 +17114,8 @@ module_state::read_namespaces (unsigned num)
dump () && dump ("Reading namespaces");
dump.indent ();
+ tree *ns_map = XALLOCAVEC (tree, num);
+
for (unsigned ix = 0; ix != num; ix++)
{
unsigned entity_index = sec.u ();
@@ -16885,6 +17177,8 @@ module_state::read_namespaces (unsigned num)
DECL_ATTRIBUTES (inner)
= tree_cons (get_identifier ("abi_tag"), tags, DECL_ATTRIBUTES (inner));
+ ns_map[ix] = inner;
+
/* Install the namespace. */
(*entity_ary)[entity_lwm + entity_index] = inner;
if (DECL_MODULE_IMPORT_P (inner))
@@ -16899,6 +17193,44 @@ module_state::read_namespaces (unsigned num)
*slot = entity_lwm + entity_index;
}
}
+
+ /* Read the exported using-directives. */
+ while (unsigned ix = sec.u ())
+ {
+ tree ns;
+ if (ix == (unsigned)-1)
+ ns = global_namespace;
+ else
+ {
+ if (--ix >= num)
+ {
+ sec.set_overrun ();
+ break;
+ }
+ ns = ns_map [ix];
+ }
+ unsigned ix2 = sec.u ();
+ if (--ix2 >= num)
+ {
+ sec.set_overrun ();
+ break;
+ }
+ tree ns2 = ns_map [ix2];
+ if (directness)
+ {
+ dump() && dump ("Reading using-directive in %N for %N",
+ ns, ns2);
+ /* In an export import this will mark the using-directive as
+ exported, so it will be emitted again. */
+ add_using_namespace (ns, ns2);
+ }
+ else
+ /* Ignore using-directives from indirect imports, we only want them
+ from our own imports. */
+ dump() && dump ("Ignoring using-directive in %N for %N",
+ ns, ns2);
+ }
+
dump.outdent ();
if (!sec.end (from ()))
return false;
@@ -17991,6 +18323,168 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
dump.outdent ();
}
+/* Return the prefix to use for dumping a #pragma diagnostic change to DK. */
+
+static const char *
+dk_string (diagnostic_t dk)
+{
+ gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND);
+ if (dk == DK_IGNORED)
+ /* diagnostic.def has an empty string for ignored. */
+ return "ignored: ";
+ else
+ return get_diagnostic_kind_text (dk);
+}
+
+/* Dump one #pragma GCC diagnostic entry. */
+
+static bool
+dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
+{
+ if (dk == DK_POP)
+ return dump (" Index %u: pop from %d", index, opt);
+ else
+ return dump (" Index %u: %s%s", index, dk_string (dk),
+ cl_options[opt].opt_text);
+}
+
+/* Write out any #pragma GCC diagnostic info to the .dgc section. */
+
+void
+module_state::write_diagnostic_classification (elf_out *to,
+ diagnostic_context *dc,
+ unsigned *crc_p)
+{
+ auto &changes = dc->get_classification_history ();
+
+ bytes_out sec (to);
+ if (sec.streaming_p ())
+ {
+ sec.begin ();
+ dump () && dump ("Writing diagnostic change locations");
+ dump.indent ();
+ }
+
+ 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. */
+ int skips = 0;
+ auto_vec<int> skips_at (len);
+ skips_at.safe_grow (len);
+
+ for (unsigned i = 0; i < len; ++i)
+ {
+ const auto &c = changes[i];
+ skips_at[i] = skips;
+ if (linemap_location_from_module_p (line_table, c.location))
+ {
+ ++skips;
+ skips_at[i] = -1;
+ continue;
+ }
+ }
+
+ if (sec.streaming_p ())
+ {
+ sec.u (len - skips);
+ dump () && dump ("Diagnostic changes: %u", len - skips);
+ }
+
+ for (unsigned i = 0; i < len; ++i)
+ {
+ if (skips_at[i] == -1)
+ continue;
+
+ const auto &c = changes[i];
+ write_location (sec, c.location);
+ if (sec.streaming_p ())
+ {
+ unsigned opt = c.option;
+ if (c.kind == DK_POP)
+ opt -= skips_at[opt];
+ sec.u (opt);
+ sec.u (c.kind);
+ dump () && dump_dc_change (i - skips_at[i], opt, c.kind);
+ }
+ }
+
+ if (sec.streaming_p ())
+ {
+ sec.end (to, to->name (MOD_SNAME_PFX ".dgc"), crc_p);
+ dump.outdent ();
+ }
+}
+
+/* Read any #pragma GCC diagnostic info from the .dgc section. */
+
+bool
+module_state::read_diagnostic_classification (diagnostic_context *dc)
+{
+ bytes_in sec;
+
+ if (!sec.begin (loc, from (), MOD_SNAME_PFX ".dgc"))
+ return false;
+
+ dump () && dump ("Reading diagnostic change locations");
+ dump.indent ();
+
+ unsigned len = sec.u ();
+ dump () && dump ("Diagnostic changes: %u", len);
+
+ auto &changes = dc->get_classification_history ();
+ int offset = changes.length ();
+ changes.reserve (len + 1);
+ for (unsigned i = 0; i < len; ++i)
+ {
+ location_t loc = read_location (sec);
+ int opt = sec.u ();
+ diagnostic_t kind = (diagnostic_t) sec.u ();
+ if (kind == DK_POP)
+ /* For a pop, opt is the 'changes' index to return to. */
+ opt += offset;
+ changes.quick_push ({ loc, opt, kind });
+ dump () && dump_dc_change (changes.length () - 1, opt, kind);
+ }
+
+ /* Did the import pop all its diagnostic changes? */
+ bool last_was_reset = (len == 0);
+ if (len)
+ for (int i = changes.length () - 1; ; --i)
+ {
+ gcc_checking_assert (i >= offset);
+
+ const auto &c = changes[i];
+ if (c.kind != DK_POP)
+ break;
+ else if (c.option == offset)
+ {
+ last_was_reset = true;
+ break;
+ }
+ else
+ /* As in update_effective_level_from_pragmas, the loop will decrement
+ i so we actually jump to c.option - 1. */
+ i = c.option;
+ }
+ if (!last_was_reset)
+ {
+ /* 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 });
+ dump () && dump (" Adding final pop from index %d", offset);
+ }
+
+ dump.outdent ();
+ if (!sec.end (from ()))
+ return false;
+
+ return true;
+}
+
void
module_state::write_macro_maps (elf_out *to, range_t &info, unsigned *crc_p)
{
@@ -19158,6 +19652,10 @@ post_load_processing ()
gcc_checking_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl));
expand_or_defer_fn (decl);
+ /* As in module_state::read_cluster. */
+ if (at_eof && DECL_COMDAT (decl) && DECL_EXTERNAL (decl)
+ && DECL_NOT_REALLY_EXTERN (decl))
+ DECL_EXTERNAL (decl) = false;
}
cfun = old_cfun;
@@ -19673,6 +20171,8 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
}
ool->qsort (ool_cmp);
+ write_diagnostic_classification (nullptr, global_dc, nullptr);
+
vec<cpp_hashnode *> *macros = nullptr;
if (is_header ())
macros = prepare_macros (reader);
@@ -19818,7 +20318,10 @@ module_state::write_begin (elf_out *to, cpp_reader *reader,
/* Write the line maps. */
if (config.ordinary_locs)
- write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+ {
+ write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+ write_diagnostic_classification (to, global_dc, &crc);
+ }
if (config.macro_locs)
write_macro_maps (to, map_info, &crc);
@@ -19891,6 +20394,10 @@ module_state::read_initial (cpp_reader *reader)
else if (!read_ordinary_maps (config.ordinary_locs, config.loc_range_bits))
ok = false;
+ if (ok && have_locs && config.ordinary_locs
+ && !read_diagnostic_classification (global_dc))
+ ok = false;
+
/* Allocate the REMAP vector. */
slurp->alloc_remap (config.num_imports);
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 7fadbcc..9aa7c16 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -583,7 +583,7 @@ name_lookup::preserve_state ()
if (previous)
{
unsigned length = vec_safe_length (previous->scopes);
- vec_safe_reserve (previous->scopes, length * 2);
+ vec_safe_reserve (previous->scopes, length);
for (unsigned ix = length; ix--;)
{
tree decl = (*previous->scopes)[ix];
@@ -1049,7 +1049,7 @@ name_lookup::search_usings (tree scope)
bool found = false;
if (vec<tree, va_gc> *usings = NAMESPACE_LEVEL (scope)->using_directives)
for (unsigned ix = usings->length (); ix--;)
- found |= search_qualified ((*usings)[ix], true);
+ found |= search_qualified (strip_using_decl ((*usings)[ix]), true);
/* Look in its inline children. */
if (vec<tree, va_gc> *inlinees = DECL_NAMESPACE_INLINEES (scope))
@@ -1121,7 +1121,7 @@ name_lookup::queue_usings (using_queue& queue, int depth, vec<tree, va_gc> *usin
{
if (usings)
for (unsigned ix = usings->length (); ix--;)
- queue_namespace (queue, depth, (*usings)[ix]);
+ queue_namespace (queue, depth, strip_using_decl ((*usings)[ix]));
}
/* Unqualified namespace lookup in SCOPE.
@@ -4178,22 +4178,6 @@ mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *vec)
return vslot;
}
-/* Retrieve the bindings for an existing mergeable entity in namespace
- NS slot NAME. Returns NULL if no such bindings exists. */
-
-static tree
-get_mergeable_namespace_binding (tree ns, tree name, bool is_attached)
-{
- tree *mslot = find_namespace_slot (ns, name, false);
- if (!mslot || !*mslot || TREE_CODE (*mslot) != BINDING_VECTOR)
- return NULL_TREE;
-
- tree *vslot = get_fixed_binding_slot
- (mslot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL,
- false);
- return vslot ? *vslot : NULL_TREE;
-}
-
/* DECL is a new mergeable namespace-scope decl. Add it to the
mergeable entities on GSLOT. */
@@ -4572,11 +4556,12 @@ lookup_imported_hidden_friend (tree friend_tmpl)
|| !DECL_MODULE_ENTITY_P (inner))
return NULL_TREE;
+ /* Load any templates matching FRIEND_TMPL from importers. */
lazy_load_pendings (friend_tmpl);
- tree bind = get_mergeable_namespace_binding
- (current_namespace, DECL_NAME (inner), DECL_MODULE_ATTACH_P (inner));
- if (!bind)
+ tree name = DECL_NAME (inner);
+ tree *slot = find_namespace_slot (current_namespace, name, false);
+ if (!slot || !*slot || TREE_CODE (*slot) != BINDING_VECTOR)
return NULL_TREE;
/* We're only interested in declarations attached to the same module
@@ -4584,9 +4569,28 @@ lookup_imported_hidden_friend (tree friend_tmpl)
int m = get_originating_module (friend_tmpl, /*global=-1*/true);
gcc_assert (m != 0);
+ /* First check whether there's a reachable declaration attached to the module
+ we're looking for. */
+ if (m > 0)
+ if (binding_slot *mslot = search_imported_binding_slot (slot, m))
+ {
+ if (mslot->is_lazy ())
+ lazy_load_binding (m, current_namespace, name, mslot);
+ for (ovl_iterator iter (*mslot); iter; ++iter)
+ if (DECL_CLASS_TEMPLATE_P (*iter))
+ return *iter;
+ }
+
+ /* Otherwise, look in the mergeable slots for this name, in case an importer
+ has already instantiated this declaration. */
+ tree *vslot = get_fixed_binding_slot
+ (slot, name, m > 0 ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, false);
+ if (!vslot || !*vslot)
+ return NULL_TREE;
+
/* There should be at most one class template from the module we're
looking for, return it. */
- for (ovl_iterator iter (bind); iter; ++iter)
+ for (ovl_iterator iter (*vslot); iter; ++iter)
if (DECL_CLASS_TEMPLATE_P (*iter)
&& get_originating_module (*iter, true) == m)
return *iter;
@@ -5204,9 +5208,11 @@ pushdecl_outermost_localscope (tree x)
cp_binding_level *b = NULL;
auto_cond_timevar tv (TV_NAME_LOOKUP);
- /* Find the scope just inside the function parms. */
- for (cp_binding_level *n = current_binding_level;
- n->kind != sk_function_parms; n = b->level_chain)
+ /* Find the block scope just inside the function parms. */
+ cp_binding_level *n = current_binding_level;
+ while (n && n->kind != sk_block)
+ n = n->level_chain;
+ for (; n && n->kind != sk_function_parms; n = b->level_chain)
b = n;
return b ? do_pushdecl_with_scope (x, b) : error_mark_node;
@@ -6862,7 +6868,7 @@ using_directives_contain_std_p (vec<tree, va_gc> *usings)
return false;
for (unsigned ix = usings->length (); ix--;)
- if ((*usings)[ix] == std_node)
+ if (strip_using_decl ((*usings)[ix]) == std_node)
return true;
return false;
@@ -7082,13 +7088,16 @@ namespace_hints::convert_candidates_to_name_hint ()
/* Clean up CANDIDATES. */
m_candidates.release ();
return name_hint (expr_to_string (candidate),
- new show_candidate_location (m_loc, candidate));
+ std::make_unique<show_candidate_location> (m_loc,
+ candidate));
}
else if (m_candidates.length () > 1)
/* If we have more than one candidate, issue a name_hint without a single
"suggestion", but with a deferred diagnostic that lists the
various candidates. This takes ownership of m_candidates. */
- return name_hint (NULL, new suggest_alternatives (m_loc, m_candidates));
+ return name_hint (NULL,
+ std::make_unique<suggest_alternatives> (m_loc,
+ m_candidates));
/* Otherwise, m_candidates ought to be empty, so no cleanup is necessary. */
gcc_assert (m_candidates.length () == 0);
@@ -7108,10 +7117,11 @@ name_hint
namespace_hints::maybe_decorate_with_limit (name_hint hint)
{
if (m_limited)
- return name_hint (hint.suggestion (),
- new namespace_limit_reached (m_loc, m_limit,
- m_name,
- hint.take_deferred ()));
+ return name_hint
+ (hint.suggestion (),
+ std::make_unique<namespace_limit_reached> (m_loc, m_limit,
+ m_name,
+ hint.take_deferred ()));
else
return hint;
}
@@ -7188,10 +7198,11 @@ suggest_alternatives_for_1 (location_t location, tree name,
diagnostic_option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
- return name_hint (nullptr,
- new suggest_missing_option (location,
- IDENTIFIER_POINTER (name),
- option_id));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_option> (location,
+ IDENTIFIER_POINTER (name),
+ option_id));
/* Otherwise, consider misspellings. */
if (!suggest_misspellings)
@@ -7319,8 +7330,9 @@ maybe_suggest_missing_std_header (location_t location, tree name)
if (!header_hint)
return name_hint ();
- return name_hint (NULL, new missing_std_header (location, name_str,
- header_hint));
+ return name_hint (nullptr,
+ std::make_unique<missing_std_header> (location, name_str,
+ header_hint));
}
/* Attempt to generate a name_hint that suggests a missing header file
@@ -7702,12 +7714,12 @@ class macro_use_before_def : public deferred_diagnostic
public:
/* Factory function. Return a new macro_use_before_def instance if
appropriate, or return NULL. */
- static macro_use_before_def *
+ static std::unique_ptr<macro_use_before_def>
maybe_make (location_t use_loc, cpp_hashnode *macro)
{
location_t def_loc = cpp_macro_definition_location (macro);
if (def_loc == UNKNOWN_LOCATION)
- return NULL;
+ return nullptr;
/* We only want to issue a note if the macro was used *before* it was
defined.
@@ -7715,12 +7727,11 @@ class macro_use_before_def : public deferred_diagnostic
used, leaving it unexpanded (e.g. by using the wrong argument
count). */
if (!linemap_location_before_p (line_table, use_loc, def_loc))
- return NULL;
+ return nullptr;
- return new macro_use_before_def (use_loc, macro);
+ return std::make_unique<macro_use_before_def> (use_loc, macro);
}
- private:
/* Ctor. LOC is the location of the usage. MACRO is the
macro that was used. */
macro_use_before_def (location_t loc, cpp_hashnode *macro)
@@ -7787,10 +7798,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
const char *header_hint
= get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name));
if (header_hint)
- return name_hint (NULL,
- new suggest_missing_header (loc,
- IDENTIFIER_POINTER (name),
- header_hint));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_header> (loc,
+ IDENTIFIER_POINTER (name),
+ header_hint));
best_match <tree, const char *> bm (name);
@@ -8931,9 +8943,27 @@ add_using_namespace (vec<tree, va_gc> *&usings, tree target)
if ((*usings)[ix] == target)
return;
+ if (modules_p ())
+ {
+ tree u = build_lang_decl (USING_DECL, NULL_TREE, NULL_TREE);
+ USING_DECL_DECLS (u) = target;
+ DECL_MODULE_EXPORT_P (u) = module_exporting_p ();
+ DECL_MODULE_PURVIEW_P (u) = module_purview_p ();
+ target = u;
+ }
vec_safe_push (usings, target);
}
+/* Convenience overload for the above, taking the user as its first
+ parameter. */
+
+void
+add_using_namespace (tree ns, tree target)
+{
+ add_using_namespace (NAMESPACE_LEVEL (ns)->using_directives,
+ ORIGINAL_NAMESPACE (target));
+}
+
/* Tell the debug system of a using directive. */
static void
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index f1596c6..2fa736b 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -462,6 +462,7 @@ extern cxx_binding *outer_binding (tree, cxx_binding *, bool);
extern void cp_emit_debug_info_for_using (tree, tree);
extern void finish_nonmember_using_decl (tree scope, tree name);
+extern void add_using_namespace (tree, tree);
extern void finish_using_directive (tree target, tree attribs);
void push_local_extern_decl_alias (tree decl);
extern tree pushdecl (tree, bool hiding = false);
@@ -500,6 +501,10 @@ enum WMB_Flags
WMB_Hidden = 1 << 3,
WMB_Purview = 1 << 4,
};
+inline WMB_Flags operator|(WMB_Flags x, WMB_Flags y)
+{ return WMB_Flags(+x|y); }
+inline WMB_Flags& operator|=(WMB_Flags& x, WMB_Flags y)
+{ return x = x|y; }
extern unsigned walk_module_binding (tree binding, bitmap partitions,
bool (*)(tree decl, WMB_Flags, void *data),
diff --git a/gcc/cp/optimize.cc b/gcc/cp/optimize.cc
index 6f9a77f..fc4d6c2 100644
--- a/gcc/cp/optimize.cc
+++ b/gcc/cp/optimize.cc
@@ -309,8 +309,8 @@ maybe_thunk_body (tree fn, bool force)
defer_mangling_aliases = save_defer_mangling_aliases;
cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
cgraph_node::get_create (fns[1])->add_to_same_comdat_group
- (cgraph_node::get_create (fns[0]));
- symtab_node::get (fn)->add_to_same_comdat_group
+ (cgraph_node::get (fns[0]));
+ symtab_node::get_create (fn)->add_to_same_comdat_group
(symtab_node::get (fns[0]));
if (fns[2])
/* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 88e722d..21bec72c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "contracts.h"
#include "bitmap.h"
#include "builtins.h"
+#include "analyzer/analyzer-language.h"
/* The lexer. */
@@ -286,6 +287,37 @@ static FILE *cp_lexer_debug_stream;
sizeof, typeof, or alignof. */
int cp_unevaluated_operand;
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Concrete implementation of ana::translation_unit for the C++ frontend. */
+
+class cp_translation_unit : public translation_unit
+{
+public:
+ tree lookup_constant_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_type_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_global_var_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+};
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
+
/* Dump up to NUM tokens in BUFFER to FILE starting with token
START_TOKEN. If START_TOKEN is NULL, the dump starts with the
first token in BUFFER. If NUM is 0, dump all the tokens. If
@@ -2487,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
@@ -3059,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
@@ -3434,9 +3466,11 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
const char *header_hint
= get_cp_stdlib_header_for_string_macro_name (token_name);
if (header_hint != NULL)
- h = name_hint (NULL, new suggest_missing_header (token->location,
- token_name,
- header_hint));
+ h = name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_header> (token->location,
+ token_name,
+ header_hint));
}
/* Actually emit the error. */
@@ -3901,10 +3935,10 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
inform (location, "%qE is not recognized as a module control-line",
id);
else if (cxx_dialect < cxx20)
- inform (location, "C++20 %qE only available with %<-fmodules-ts%>",
+ inform (location, "C++20 %qE only available with %<-fmodules%>",
id);
else
- inform (location, "C++20 %qE only available with %<-fmodules-ts%>"
+ inform (location, "C++20 %qE only available with %<-fmodules%>"
", which is not yet enabled with %<-std=c++20%>", id);
}
else if (cxx_dialect < cxx11
@@ -5469,6 +5503,14 @@ cp_parser_translation_unit (cp_parser* parser)
cp_parser_toplevel_declaration (parser);
}
+#if ENABLE_ANALYZER
+ if (flag_analyzer)
+ {
+ ana::cp_translation_unit tu;
+ ana::on_finish_translation_unit (tu);
+ }
+#endif
+
/* Get rid of the token array; we don't need it any more. */
cp_lexer_destroy (parser->lexer);
parser->lexer = NULL;
@@ -6265,7 +6307,10 @@ cp_parser_primary_expression (cp_parser *parser,
/* Recognize the `this' keyword. */
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
- if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
+ if ((parser->local_variables_forbidden_p & THIS_FORBIDDEN)
+ /* It's OK to refer to 'this' in an unevaluated operand in a
+ lambda default argument (lambda-targ16.C). */
+ && !cp_unevaluated_operand)
{
error_at (token->location,
"%<this%> may not be used in this context");
@@ -7197,18 +7242,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
@@ -7217,7 +7266,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;
@@ -7265,8 +7315,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)
@@ -7314,8 +7365,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
@@ -10793,6 +10847,14 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
goto pop;
}
+ /* If we skipped build_cplus_new in build_cxx_call because of decltype_p,
+ call it now that we know current.lhs is a subexpression. */
+ if (decltype_p && !processing_template_decl
+ && TREE_CODE (current.lhs) == CALL_EXPR
+ && CLASS_TYPE_P (TREE_TYPE (current.lhs)))
+ current.lhs = build_cplus_new (TREE_TYPE (current.lhs), current.lhs,
+ tf_warning_or_error);
+
get_rhs:
current.tree_type = binops_by_token[token->type].tree_type;
current.loc = token->location;
@@ -11736,21 +11798,34 @@ cp_parser_lambda_expression (cp_parser* parser)
if (cp_parser_error_occurred (parser))
return error_mark_node;
- type = begin_lambda_type (lambda_expr);
- if (type == error_mark_node)
- return error_mark_node;
+ {
+ /* OK, this is a bit tricksy. cp_parser_requires_expression sets
+ processing_template_decl to make checking more normal, but that confuses
+ lambda parsing terribly. In non-template context, we want to parse the
+ lambda once and not tsubst_lambda_expr. So in that case, clear
+ processing_template_decl now, and restore it before the call to
+ build_lambda_object; that way we end up with what looks like a templatey
+ functional cast to the closure type, which is suitable for the
+ requires-expression tsubst_expr. This is PR99546 and friends. */
+ processing_template_decl_sentinel ptds (/*reset*/false);
+ if (processing_template_decl && !in_template_context
+ && current_binding_level->requires_expression)
+ processing_template_decl = 0;
+
+ type = begin_lambda_type (lambda_expr);
+ if (type == error_mark_node)
+ return error_mark_node;
- record_lambda_scope (lambda_expr);
- record_lambda_scope_discriminator (lambda_expr);
+ record_lambda_scope (lambda_expr);
+ record_lambda_scope_discriminator (lambda_expr);
- /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
- determine_visibility (TYPE_NAME (type));
+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
+ determine_visibility (TYPE_NAME (type));
- /* Now that we've started the type, add the capture fields for any
- explicit captures. */
- register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr));
+ /* Now that we've started the type, add the capture fields for any
+ explicit captures. */
+ register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr));
- {
/* Inside the class, surrounding template-parameter-lists do not apply. */
unsigned int saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
@@ -11763,6 +11838,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;
@@ -11772,6 +11848,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;
@@ -11826,6 +11903,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. */
@@ -15376,11 +15454,12 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
case RID_GOTO:
if (parser->in_function_body
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+ && maybe_constexpr_fn (current_function_decl)
&& cxx_dialect < cxx23)
{
- error ("%<goto%> in %<constexpr%> function only available with "
- "%<-std=c++23%> or %<-std=gnu++23%>");
+ if (DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ error ("%<goto%> in %<constexpr%> function only available with "
+ "%<-std=c++23%> or %<-std=gnu++23%>");
cp_function_chain->invalid_constexpr = true;
}
@@ -15772,7 +15851,13 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state,
" must not be from header inclusion");
}
+ auto mk = module_kind;
+ if (exporting)
+ module_kind |= MK_EXPORTING;
+
import_module (mod, token->location, exporting, attrs, parse_in);
+
+ module_kind = mk;
}
}
@@ -16797,7 +16882,11 @@ cp_parser_decomposition_declaration (cp_parser *parser,
decl = error_mark_node;
}
else
- prev = decl2;
+ {
+ prev = decl2;
+ DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl);
+ DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl);
+ }
if (elt_pushed_scope)
pop_scope (elt_pushed_scope);
}
@@ -16846,6 +16935,15 @@ cp_parser_decomposition_declaration (cp_parser *parser,
/* Ensure DECL_VALUE_EXPR is created for all the decls but
the underlying DECL. */
cp_finish_decomp (decl, &decomp);
+ if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+ pedwarn (decl_specifiers->locations[ds_thread],
+ 0, "for-range-declaration cannot be %qs",
+ decl_specifiers->gnu_thread_keyword_p
+ ? "__thread" : "thread_local");
+ else if (decl_specifiers->storage_class == sc_static)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "static");
}
if (pushed_scope)
@@ -18845,7 +18943,7 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p)
else if (cxx_dialect < cxx20)
warning (0, "keyword %<export%> is deprecated, and is ignored");
else
- warning (0, "keyword %<export%> is enabled with %<-fmodules-ts%>");
+ warning (0, "keyword %<export%> is enabled with %<-fmodules%>");
}
cp_parser_template_declaration_after_export (parser, member_p);
@@ -20939,9 +21037,6 @@ cp_parser_simple_type_specifier (cp_parser* parser,
"only available with "
"%<-std=c++14%> or %<-std=gnu++14%>");
}
- else if (parser->in_template_argument_list_p)
- error_at (token->location,
- "use of %<auto%> in template argument");
else if (!flag_concepts)
pedwarn (token->location, OPT_Wc__20_extensions,
"use of %<auto%> in parameter declaration "
@@ -20951,6 +21046,11 @@ cp_parser_simple_type_specifier (cp_parser* parser,
"use of %<auto%> in parameter declaration "
"only available with "
"%<-std=c++14%> or %<-std=gnu++14%>");
+
+ if (parser->in_template_argument_list_p)
+ permerror_opt (token->location,
+ OPT_Wabbreviated_auto_in_template_arg,
+ "use of %<auto%> in template argument");
}
else
type = make_auto ();
@@ -21079,7 +21179,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. */
@@ -21397,6 +21499,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
error_at (loc, "cannot declare a parameter with %<decltype(auto)%>");
return error_mark_node;
}
+ if (parser->in_template_argument_list_p)
+ permerror_opt (placeholder->location,
+ OPT_Wabbreviated_auto_in_template_arg,
+ "use of %<auto%> in template argument");
tree parm = build_constrained_parameter (con, proto, args);
return synthesize_implicit_template_parm (parser, parm);
}
@@ -21925,7 +22031,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. */
@@ -24089,7 +24195,26 @@ cp_parser_init_declarator (cp_parser* parser,
&& token->type != CPP_SEMICOLON)
{
if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node)
- range_for_decl_p = true;
+ {
+ range_for_decl_p = true;
+ if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+ pedwarn (decl_specifiers->locations[ds_thread],
+ 0, "for-range-declaration cannot be %qs",
+ decl_specifiers->gnu_thread_keyword_p
+ ? "__thread" : "thread_local");
+ else if (decl_specifiers->storage_class == sc_static)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "static");
+ else if (decl_specifiers->storage_class == sc_extern)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "extern");
+ else if (decl_specifiers->storage_class == sc_register)
+ pedwarn (decl_specifiers->locations[ds_storage_class],
+ 0, "for-range-declaration cannot be %qs",
+ "register");
+ }
else
{
if (!maybe_range_for_decl)
@@ -27943,6 +28068,64 @@ 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
+
+ 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
+ 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:
@@ -28133,18 +28316,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;
@@ -28154,13 +28335,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)
{
@@ -30359,6 +30533,9 @@ cp_parser_asm_operand_list (cp_parser* parser)
parens.require_open (parser);
/* Parse the expression. */
tree expression = cp_parser_expression (parser);
+ if (check_for_bare_parameter_packs (expression))
+ expression = error_mark_node;
+
/* Look for the `)'. */
parens.require_close (parser);
@@ -33621,6 +33798,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ int errs = errorcount + sorrycount;
+
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
or function-transaction-block. Note that all of these include the
@@ -33640,6 +33819,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
fn = finish_function (inline_p);
check_module_decl_linkage (fn);
+ if ((errorcount + sorrycount) > errs)
+ DECL_STRUCT_FUNCTION (fn)->language->erroneous = true;
+
if (modules_p ()
&& !inline_p
&& TYPE_P (DECL_CONTEXT (fn))
@@ -35521,15 +35703,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));
@@ -35809,7 +35991,9 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc,
return;
bool seen_as_union = TREE_CODE (type) == UNION_TYPE;
- if (seen_as_union != (class_key == union_type))
+ if (class_key != typename_type
+ && TREE_CODE (type) != TYPENAME_TYPE
+ && seen_as_union != (class_key == union_type))
{
auto_diagnostic_group d;
if (permerror (input_location, "%qs tag used in naming %q#T",
@@ -36583,7 +36767,7 @@ static void
cp_parser_abort_tentative_parse (cp_parser* parser)
{
gcc_assert (parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED
- || errorcount > 0);
+ || seen_error ());
cp_parser_simulate_error (parser);
/* Now, pretend that we want to see if the construct was
successfully parsed. */
@@ -42357,13 +42541,13 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
map ( [map-type-modifier[,] ...] map-kind: variable-list )
map-type-modifier:
- always | close */
+ always | close | mapper ( mapper-name ) */
static tree
-cp_parser_omp_clause_map (cp_parser *parser, tree list)
+cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
{
tree nlist, c;
- enum gomp_map_kind kind = GOMP_MAP_TOFROM;
+ enum gomp_map_kind kind = declare_mapper_p ? GOMP_MAP_UNSET : GOMP_MAP_TOFROM;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
@@ -42381,12 +42565,17 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA)
pos++;
+ else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type
+ == CPP_OPEN_PAREN)
+ pos = cp_parser_skip_balanced_tokens (parser, pos + 1);
pos++;
}
bool always_modifier = false;
bool close_modifier = false;
bool present_modifier = false;
+ bool mapper_modifier = false;
+ tree mapper_name = NULL_TREE;
for (int pos = 1; pos < map_kind_pos; ++pos)
{
cp_token *tok = cp_lexer_peek_token (parser->lexer);
@@ -42409,6 +42598,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
always_modifier = true;
+ cp_lexer_consume_token (parser->lexer);
}
else if (strcmp ("close", p) == 0)
{
@@ -42422,6 +42612,77 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
close_modifier = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (strcmp ("mapper", p) == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (mapper_modifier)
+ {
+ cp_parser_error (parser, "too many %<mapper%> modifiers");
+ /* Assume it's a well-formed mapper modifier, even if it
+ seems to be in the wrong place. */
+ cp_lexer_consume_token (parser->lexer);
+ parens.require_close (parser);
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return list;
+ }
+
+ tok = cp_lexer_peek_token (parser->lexer);
+ switch (tok->type)
+ {
+ case CPP_NAME:
+ {
+ cp_expr e = cp_parser_identifier (parser);
+ if (e != error_mark_node)
+ mapper_name = e;
+ else
+ goto err;
+ if (declare_mapper_p)
+ {
+ error_at (e.get_location (),
+ "in %<declare mapper%> directives, parameter "
+ "to %<mapper%> modifier must be %<default%>");
+ }
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (tok->keyword == RID_DEFAULT)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ err:
+ cp_parser_error (parser,
+ "expected identifier or %<default%>");
+ return list;
+ }
+
+ if (!parens.require_close (parser))
+ {
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return list;
+ }
+
+ mapper_modifier = true;
+ pos += 3;
+ }
}
else if (strcmp ("present", p) == 0)
{
@@ -42435,19 +42696,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
return list;
}
present_modifier = true;
- }
+ cp_lexer_consume_token (parser->lexer);
+ }
else
{
- cp_parser_error (parser, "%<map%> clause with map-type modifier other"
- " than %<always%>, %<close%> or %<present%>");
+ cp_parser_error (parser, "%<map%> clause with map-type modifier "
+ "other than %<always%>, %<close%>, "
+ "%<mapper%> or %<present%>");
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/true);
return list;
}
-
- cp_lexer_consume_token (parser->lexer);
}
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
@@ -42503,8 +42764,30 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
NULL, true);
finish_scope ();
+ tree last_new = NULL_TREE;
+
for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
- OMP_CLAUSE_SET_MAP_KIND (c, kind);
+ {
+ OMP_CLAUSE_SET_MAP_KIND (c, kind);
+ last_new = c;
+ }
+
+ if (mapper_name)
+ {
+ tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = mapper_name;
+ OMP_CLAUSE_CHAIN (name) = nlist;
+ nlist = name;
+
+ gcc_assert (last_new);
+
+ name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = null_pointer_node;
+ OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new);
+ OMP_CLAUSE_CHAIN (last_new) = name;
+ }
return nlist;
}
@@ -43121,8 +43404,8 @@ cp_parser_omp_clause_init_modifiers (cp_parser *parser, bool *target,
while (true);
fail:
- cp_parser_error (parser, "%<init%> clause with modifier other than "
- "%<prefer_type%>, %<target%> or %<targetsync%>");
+ cp_parser_error (parser,
+ "expected %<prefer_type%>, %<target%>, or %<targetsync%>");
return false;
}
@@ -43140,39 +43423,14 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list)
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
- unsigned raw_pos = 1;
- while (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type == CPP_NAME)
- {
- raw_pos++;
- if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type
- == CPP_OPEN_PAREN)
- {
- unsigned n = cp_parser_skip_balanced_tokens (parser, raw_pos);
- if (n == raw_pos)
- {
- raw_pos = 0;
- break;
- }
- raw_pos = n;
- }
- if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type == CPP_COLON)
- break;
- if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type != CPP_COMMA)
- {
- raw_pos = 0;
- break;
- }
- raw_pos++;
- }
-
bool target = false;
bool targetsync = false;
tree prefer_type_tree = NULL_TREE;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
- if (raw_pos > 1
- && (!cp_parser_omp_clause_init_modifiers (parser, &target, &targetsync,
- &prefer_type_tree)
- || !cp_parser_require (parser, CPP_COLON, RT_COLON)))
+ if (!cp_parser_omp_clause_init_modifiers (parser, &target, &targetsync,
+ &prefer_type_tree)
+ || !cp_parser_require (parser, CPP_COLON, RT_COLON))
{
if (prefer_type_tree == error_mark_node)
return error_mark_node;
@@ -43182,6 +43440,10 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list)
return list;
}
+ if (!target && !targetsync)
+ error_at (loc,
+ "missing required %<target%> and/or %<targetsync%> modifier");
+
tree nl = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_INIT, list,
NULL, false);
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
@@ -43853,7 +44115,8 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
c_name = "detach";
break;
case PRAGMA_OMP_CLAUSE_MAP:
- clauses = cp_parser_omp_clause_map (parser, clauses);
+ clauses = cp_parser_omp_clause_map (parser, clauses,
+ /*mapper=*/false);
c_name = "map";
break;
case PRAGMA_OMP_CLAUSE_DEVICE:
@@ -48859,6 +49122,8 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = nc;
}
+ if (!processing_template_decl)
+ clauses = c_omp_instantiate_mappers (clauses);
clauses = finish_omp_clauses (clauses, C_ORT_OMP_TARGET);
c_omp_adjust_map_clauses (clauses, true);
@@ -49553,7 +49818,8 @@ cp_parser_oacc_update (cp_parser *parser, cp_token *pragma_tok)
*/
#define OACC_WAIT_CLAUSE_MASK \
- ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC))
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF))
static tree
cp_parser_oacc_wait (cp_parser *parser, cp_token *pragma_tok)
@@ -49838,12 +50104,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
&& !value_dependent_expression_p (t))
{
t = fold_non_dependent_expr (t);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
{
- error_at (token->location,
- "property must be integer expression");
- return error_mark_node;
+ t = maybe_convert_cond (t);
+ if (t == error_mark_node)
+ return error_mark_node;
}
+ else
+ {
+ t = convert_from_reference (t);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (token->location,
+ "property must be integer expression");
+ return error_mark_node;
+ }
+ }
+ if (!processing_template_decl
+ && TREE_CODE (t) != CLEANUP_POINT_EXPR)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
properties = make_trait_property (NULL_TREE, t, properties);
break;
@@ -50581,6 +50860,10 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
&targetsync,
&prefer_type_tree))
goto fail;
+ if (!target && !targetsync)
+ error_at (loc,
+ "missing required %<target%> and/or "
+ "%<targetsync%> modifier");
tree t = build_tree_list (target ? boolean_true_node
: boolean_false_node,
targetsync ? boolean_true_node
@@ -51408,7 +51691,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
{
error_at (match_loc, "too many %<otherwise%> or %<default%> "
"clauses in %<metadirective%>");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
else
@@ -51418,14 +51700,12 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
{
error_at (match_loc, "%<otherwise%> or %<default%> clause "
"must appear last in %<metadirective%>");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
if (!default_p && strcmp (p, "when") != 0)
{
error_at (match_loc, "%qs is not valid for %qs",
p, "metadirective");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
@@ -51494,7 +51774,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
if (i == 0)
{
error_at (loc, "expected directive name");
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
goto fail;
}
@@ -51567,7 +51846,10 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
goto add;
case CPP_CLOSE_PAREN:
if (nesting_depth-- == 0)
- break;
+ {
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
goto add;
default:
add:
@@ -51579,8 +51861,6 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
break;
}
- cp_lexer_consume_token (parser->lexer);
-
if (!skip)
{
cp_token eol_token = {};
@@ -51712,11 +51992,8 @@ cp_parser_omp_metadirective (cp_parser *parser, cp_token *pragma_tok,
return;
fail:
- /* Skip the metadirective pragma. */
+ /* Skip the metadirective pragma. Do not skip the metadirective body. */
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
-
- /* Skip the metadirective body. */
- cp_parser_skip_to_end_of_block_or_statement (parser, true);
}
@@ -52135,6 +52412,175 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
obstack_free (&declarator_obstack, p);
}
+/* OpenMP 5.0
+ #pragma omp declare mapper([mapper-identifier:]type var) \
+ [clause[[,] clause] ... ] new-line */
+
+static void
+cp_parser_omp_declare_mapper (cp_parser *parser, cp_token *pragma_tok,
+ enum pragma_context)
+{
+ cp_token *token = NULL;
+ tree type = NULL_TREE, vardecl = NULL_TREE, block = NULL_TREE;
+ bool block_scope = false;
+ /* Don't create location wrapper nodes within "declare mapper"
+ directives. */
+ auto_suppress_location_wrappers sentinel;
+ tree mapper_name = NULL_TREE;
+ tree mapper_id, id, placeholder, mapper, maplist = NULL_TREE;
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ goto fail;
+
+ if (current_function_decl)
+ block_scope = true;
+
+ token = cp_lexer_peek_token (parser->lexer);
+
+ if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ {
+ switch (token->type)
+ {
+ case CPP_NAME:
+ {
+ cp_expr e = cp_parser_identifier (parser);
+ if (e != error_mark_node)
+ mapper_name = e;
+ else
+ goto fail;
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (token->keyword == RID_DEFAULT)
+ {
+ mapper_name = NULL_TREE;
+ cp_lexer_consume_token (parser->lexer);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ cp_parser_error (parser, "expected identifier or %<default%>");
+ }
+
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ goto fail;
+ }
+
+ {
+ const char *saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined within %<declare mapper%>");
+ type_id_in_expr_sentinel s (parser);
+ type = cp_parser_type_id (parser);
+ parser->type_definition_forbidden_message = saved_message;
+ }
+
+ if (type == error_mark_node)
+ goto fail;
+ if (dependent_type_p (type))
+ mapper_id = omp_mapper_id (mapper_name, NULL_TREE);
+ else
+ mapper_id = omp_mapper_id (mapper_name, type);
+
+ vardecl = build_lang_decl (VAR_DECL, mapper_id, type);
+ DECL_ARTIFICIAL (vardecl) = 1;
+ TREE_STATIC (vardecl) = 1;
+ TREE_PUBLIC (vardecl) = 0;
+ DECL_EXTERNAL (vardecl) = 0;
+ DECL_DECLARED_CONSTEXPR_P (vardecl) = 1;
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (vardecl) = 1;
+ DECL_OMP_DECLARE_MAPPER_P (vardecl) = 1;
+
+ keep_next_level (true);
+ block = begin_omp_structured_block ();
+
+ if (block_scope)
+ DECL_CONTEXT (vardecl) = current_function_decl;
+ else if (current_class_type)
+ DECL_CONTEXT (vardecl) = current_class_type;
+ else
+ DECL_CONTEXT (vardecl) = current_namespace;
+
+ if (processing_template_decl)
+ vardecl = push_template_decl (vardecl);
+
+ if ((id = cp_parser_declarator_id (parser, false)) == error_mark_node)
+ goto fail;
+
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ {
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+
+ placeholder = build_lang_decl (VAR_DECL, id, type);
+ DECL_CONTEXT (placeholder) = DECL_CONTEXT (vardecl);
+ if (processing_template_decl)
+ placeholder = push_template_decl (placeholder);
+ pushdecl (placeholder);
+ cp_finish_decl (placeholder, NULL_TREE, 0, NULL_TREE, 0);
+ DECL_ARTIFICIAL (placeholder) = 1;
+ TREE_USED (placeholder) = 1;
+
+ while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+ {
+ pragma_omp_clause c_kind = cp_parser_omp_clause_name (parser);
+ if (c_kind != PRAGMA_OMP_CLAUSE_MAP)
+ {
+ if (c_kind != PRAGMA_OMP_CLAUSE_NONE)
+ cp_parser_error (parser, "unexpected clause");
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+ maplist = cp_parser_omp_clause_map (parser, maplist, /*mapper=*/true);
+ if (maplist == NULL_TREE)
+ break;
+ }
+
+ if (maplist == NULL_TREE)
+ {
+ cp_parser_error (parser, "missing %<map%> clause");
+ finish_omp_structured_block (block);
+ goto fail;
+ }
+
+ mapper = make_node (OMP_DECLARE_MAPPER);
+ TREE_TYPE (mapper) = type;
+ OMP_DECLARE_MAPPER_ID (mapper) = mapper_name;
+ OMP_DECLARE_MAPPER_DECL (mapper) = placeholder;
+ OMP_DECLARE_MAPPER_CLAUSES (mapper) = maplist;
+
+ finish_omp_structured_block (block);
+
+ DECL_INITIAL (vardecl) = mapper;
+
+ if (current_class_type)
+ {
+ if (processing_template_decl)
+ {
+ retrofit_lang_decl (vardecl);
+ SET_DECL_VAR_DECLARED_INLINE_P (vardecl);
+ }
+ finish_static_data_member_decl (vardecl, mapper,
+ /*init_const_expr_p=*/true, NULL_TREE, 0);
+ finish_member_declaration (vardecl);
+ }
+ else if (processing_template_decl && block_scope)
+ add_decl_expr (vardecl);
+ else
+ pushdecl (vardecl);
+
+ cp_check_omp_declare_mapper (vardecl);
+
+ cp_parser_require_pragma_eol (parser, pragma_tok);
+ return;
+
+fail:
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+}
+
/* OpenMP 4.0
#pragma omp declare simd declare-simd-clauses[optseq] new-line
#pragma omp declare reduction (reduction-id : typename-list : expression) \
@@ -52179,6 +52625,12 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
context);
return false;
}
+ if (strcmp (p, "mapper") == 0)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_omp_declare_mapper (parser, pragma_tok, context);
+ return false;
+ }
if (!flag_openmp) /* flag_openmp_simd */
{
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
@@ -52192,7 +52644,7 @@ cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
}
}
cp_parser_error (parser, "expected %<simd%>, %<reduction%>, "
- "%<target%> or %<variant%>");
+ "%<target%>, %<mapper%> or %<variant%>");
cp_parser_require_pragma_eol (parser, pragma_tok);
return false;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f7c56a1..8f3822c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -202,7 +202,6 @@ static tree for_each_template_parm_r (tree *, int *, void *);
static tree copy_default_args_to_explicit_spec_1 (tree, tree);
static void copy_default_args_to_explicit_spec (tree);
static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t);
-static bool dependent_template_arg_p (tree);
static bool dependent_type_p_r (tree);
static tree tsubst_stmt (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t, bool = true);
@@ -7492,8 +7491,13 @@ get_template_parm_object (tree expr, tree name, bool check_init/*=true*/)
{
/* The EXPR is the already processed initializer, set it on the NTTP
object now so that cp_finish_decl doesn't do it again later. */
+ gcc_checking_assert (reduced_constant_expression_p (expr));
DECL_INITIAL (decl) = expr;
- DECL_INITIALIZED_P (decl) = 1;
+ DECL_INITIALIZED_P (decl) = true;
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
+ /* FIXME setting TREE_CONSTANT on refs breaks the back end. */
+ if (!TYPE_REF_P (type))
+ TREE_CONSTANT (decl) = true;
}
pushdecl_top_level_and_finish (decl, expr);
@@ -10047,15 +10051,20 @@ tsubst_entering_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
D1 is the PTYPENAME terminal, and ARGLIST is the list of arguments.
+ If D1 is an identifier and CONTEXT is non-NULL, then the lookup is
+ carried out in CONTEXT. Currently, only namespaces are supported for
+ CONTEXT.
+
+ If D1 is an identifier and CONTEXT is NULL, the lookup is performed
+ in the innermost non-namespace binding.
+
+ Otherwise CONTEXT is ignored and no lookup is carried out.
+
IN_DECL, if non-NULL, is the template declaration we are trying to
instantiate.
Issue error and warning messages under control of COMPLAIN.
- If the template class is really a local class in a template
- function, then the FUNCTION_CONTEXT is the function in which it is
- being instantiated.
-
??? Note that this function is currently called *twice* for each
template-id: the first time from the parser, while creating the
incomplete type (finish_template_type), and the second type during the
@@ -10074,20 +10083,23 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
spec_entry **slot;
spec_entry *entry;
- if (identifier_p (d1))
+ if (identifier_p (d1) && context)
+ {
+ gcc_checking_assert (TREE_CODE (context) == NAMESPACE_DECL);
+ push_decl_namespace (context);
+ templ = lookup_name (d1, LOOK_where::NAMESPACE, LOOK_want::NORMAL);
+ pop_decl_namespace ();
+ }
+ else if (identifier_p (d1))
{
tree value = innermost_non_namespace_value (d1);
if (value && DECL_TEMPLATE_TEMPLATE_PARM_P (value))
templ = value;
else
- {
- if (context)
- push_decl_namespace (context);
+ {
templ = lookup_name (d1);
templ = maybe_get_template_decl_from_type_decl (templ);
- if (context)
- pop_decl_namespace ();
- }
+ }
}
else if (TREE_CODE (d1) == TYPE_DECL && MAYBE_CLASS_TYPE_P (TREE_TYPE (d1)))
{
@@ -11117,6 +11129,18 @@ any_template_parm_r (tree t, void *data)
case LAMBDA_EXPR:
{
+ /* TREE_STATIC on LAMBDA_EXPR_EXTRA_ARGS means a full set of
+ arguments, so we can just look there; they will replace
+ any template parms in the rest of the LAMBDA_EXPR. */
+ if (tree args = LAMBDA_EXPR_EXTRA_ARGS (t))
+ {
+ WALK_SUBTREE (args);
+ /* Without TREE_STATIC the args are just outer levels, so we'd
+ still need to look through the lambda for just inner
+ parameters. Hopefully that's not necessary. */
+ gcc_checking_assert (TREE_STATIC (args));
+ return 0;
+ }
/* Look in the parms and body. */
tree fn = lambda_function (t);
WALK_SUBTREE (TREE_TYPE (fn));
@@ -11361,6 +11385,7 @@ limit_bad_template_recursion (tree decl)
static int tinst_depth;
extern int max_tinst_depth;
int depth_reached;
+int tinst_dump_id;
static GTY(()) struct tinst_level *last_error_tinst_level;
@@ -11406,12 +11431,47 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
new_level->targs = targs;
new_level->locus = loc;
new_level->errors = errorcount + sorrycount;
+ new_level->had_errors = false;
new_level->next = NULL;
new_level->refcount = 0;
new_level->path = new_level->visible = nullptr;
set_refcount_ptr (new_level->next, current_tinst_level);
set_refcount_ptr (current_tinst_level, new_level);
+ if (cxx_dump_pretty_printer pp {tinst_dump_id})
+ {
+#if __GNUC__ >= 10
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+ bool list_p = new_level->list_p ();
+ if (list_p && !pp.has_flag (TDF_DETAILS))
+ /* Skip non-instantiations unless -details. */;
+ else
+ {
+ if (tinst_depth == 0)
+ pp_newline (&pp);
+ if (loc && pp.has_flag (TDF_LINENO))
+ {
+ for (int i = 0; i < tinst_depth; ++i)
+ pp_space (&pp);
+ const expanded_location el = expand_location (loc);
+ pp_printf (&pp, "%s:%d:%d", el.file, el.line, el.column);
+ pp_newline (&pp);
+ }
+ for (int i = 0; i < tinst_depth; ++i)
+ pp_space (&pp);
+ if (list_p)
+ pp_printf (&pp, "S %S", new_level->get_node ());
+ else
+ pp_printf (&pp, "I %D", tldcl);
+ pp_newline (&pp);
+ }
+#if __GNUC__ >= 10
+#pragma GCC diagnostic pop
+#endif
+ }
+
++tinst_depth;
if (GATHER_STATISTICS && (tinst_depth > depth_reached))
depth_reached = tinst_depth;
@@ -11456,10 +11516,27 @@ pop_tinst_level (void)
/* Restore the filename and line number stashed away when we started
this instantiation. */
input_location = current_tinst_level->locus;
+ if (unsigned errs = errorcount + sorrycount)
+ if (errs > current_tinst_level->errors)
+ current_tinst_level->had_errors = true;
set_refcount_ptr (current_tinst_level, current_tinst_level->next);
--tinst_depth;
}
+/* True if the instantiation represented by LEVEL is complete. */
+
+static bool
+tinst_complete_p (struct tinst_level *level)
+{
+ gcc_assert (!level->list_p ());
+ tree node = level->get_node ();
+ if (TYPE_P (node))
+ return COMPLETE_TYPE_P (node);
+ else
+ return (DECL_TEMPLATE_INSTANTIATED (node)
+ || DECL_TEMPLATE_SPECIALIZATION (node));
+}
+
/* We're instantiating a deferred template; restore the template
instantiation context in which the instantiation was requested, which
is one step out from LEVEL. Return the corresponding DECL or TYPE. */
@@ -11475,9 +11552,41 @@ reopen_tinst_level (struct tinst_level *level)
set_refcount_ptr (current_tinst_level, level);
pop_tinst_level ();
- if (current_tinst_level)
+ if (current_tinst_level && !current_tinst_level->had_errors)
current_tinst_level->errors = errorcount+sorrycount;
+ if (cxx_dump_pretty_printer pp {tinst_dump_id})
+ {
+#if __GNUC__ >= 10
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+ /* Dump the reopened instantiation context. */
+ t = current_tinst_level;
+ if (!pp.has_flag (TDF_DETAILS))
+ /* Skip non-instantiations unless -details. */
+ while (t && t->list_p ())
+ t = t->next;
+ if (t)
+ {
+ static tree last_ctx = NULL_TREE;
+ tree ctx = t->get_node ();
+ if (ctx != last_ctx)
+ {
+ last_ctx = ctx;
+ pp_newline (&pp);
+ if (t->list_p ())
+ pp_printf (&pp, "RS %S", ctx);
+ else
+ pp_printf (&pp, "RI %D", ctx);
+ pp_newline (&pp);
+ }
+ }
+#if __GNUC__ >= 10
+#pragma GCC diagnostic pop
+#endif
+ }
+
tree decl = level->maybe_get_node ();
if (decl && modules_p ())
{
@@ -11760,6 +11869,10 @@ tsubst_friend_function (tree decl, tree args)
elt.args = DECL_TI_ARGS (spec);
elt.spec = NULL_TREE;
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (DECL_TI_ARGS (spec))
+ && !is_specialization_of_friend (spec, new_template))
+ continue;
+
decl_specializations->remove_elt (&elt);
tree& spec_args = DECL_TI_ARGS (spec);
@@ -12413,6 +12526,8 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute,
NULL);
auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL);
+ auto o6 = make_temp_override (target_option_current_node,
+ target_option_default_node);
cplus_decl_attributes (decl_p, late_attrs, attr_flags);
@@ -13736,11 +13851,12 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)
inst = local;
/* else inst is already a full instantiation of the pack. */
register_local_specialization (inst, gen);
+ if (is_normal_capture_proxy (gen))
+ register_local_specialization (inst, DECL_CAPTURED_VARIABLE (gen));
}
gcc_assert (!TREE_PURPOSE (extra));
extra = TREE_VALUE (extra);
}
- gcc_checking_assert (TREE_STATIC (extra) == uses_template_parms (extra));
if (TREE_STATIC (extra))
/* This is a partial substitution into e.g. a requires-expr or lambda-expr
inside a default template argument; we expect 'extra' to be a full set
@@ -14874,6 +14990,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t))
parms = DECL_CHAIN (parms);
parms = tsubst (parms, args, complain, t);
+ if (parms == error_mark_node)
+ return error_mark_node;
for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
DECL_CONTEXT (parm) = r;
if (closure && DECL_IOBJ_MEMBER_FUNCTION_P (t))
@@ -15446,6 +15564,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
/* We're dealing with a normal parameter. */
type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ if (type == error_mark_node && !(complain & tf_error))
+ RETURN (error_mark_node);
+
type = type_decays_to (type);
TREE_TYPE (r) = type;
cp_apply_type_quals_to_decl (cp_type_quals (type), r);
@@ -15483,8 +15604,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
/* If cp_unevaluated_operand is set, we're just looking for a
single dummy parameter, so don't keep going. */
if (DECL_CHAIN (t) && !cp_unevaluated_operand)
- DECL_CHAIN (r) = tsubst (DECL_CHAIN (t), args,
- complain, DECL_CHAIN (t));
+ {
+ tree chain = tsubst (DECL_CHAIN (t), args,
+ complain, DECL_CHAIN (t));
+ if (chain == error_mark_node)
+ RETURN (error_mark_node);
+ DECL_CHAIN (r) = chain;
+ }
/* FIRST_R contains the start of the chain we've built. */
r = first_r;
@@ -15880,7 +16006,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
= remove_attribute ("visibility", DECL_ATTRIBUTES (r));
}
determine_visibility (r);
- if ((!local_p || TREE_STATIC (t)) && DECL_SECTION_NAME (t))
+ if ((!local_p || TREE_STATIC (t))
+ && !(flag_openmp && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_DECLARE_MAPPER_P (t))
+ && DECL_SECTION_NAME (t))
set_decl_section_name (r, t);
}
@@ -15932,6 +16061,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (r));
}
+ if (flag_openmp
+ && VAR_P (t)
+ && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_DECLARE_MAPPER_P (t)
+ && strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
+ DECL_NAME (r) = omp_mapper_id (DECL_NAME (t), TREE_TYPE (r));
+
layout_decl (r, 0);
}
break;
@@ -17114,13 +17250,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return error_mark_node;
}
- /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' vs 'union'
- tags. TYPENAME_TYPE should probably remember the exact tag that
- was written. */
+ /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags.
+ TYPENAME_TYPE should probably remember the exact tag that
+ was written for -Wmismatched-tags. */
enum tag_types tag_type
- = TYPENAME_IS_CLASS_P (t) ? class_type
- : TYPENAME_IS_ENUM_P (t) ? enum_type
- : typename_type;
+ = (TYPENAME_IS_CLASS_P (t) ? class_type
+ : TYPENAME_IS_UNION_P (t) ? union_type
+ : TYPENAME_IS_ENUM_P (t) ? enum_type
+ : typename_type);
tsubst_flags_t tcomplain = complain | tf_keep_type_decl;
tcomplain |= tst_ok_flag | qualifying_scope_flag;
f = make_typename_type (ctx, f, tag_type, tcomplain);
@@ -17142,10 +17279,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
else
return error_mark_node;
}
- else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f))
+ else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f))
+ {
+ if (complain & tf_error)
+ error ("%qT resolves to %qT, which is not a non-union "
+ "class type", t, f);
+ else
+ return error_mark_node;
+ }
+ else if (TYPENAME_IS_UNION_P (t) && !UNION_TYPE_P (f))
{
if (complain & tf_error)
- error ("%qT resolves to %qT, which is not a class type",
+ error ("%qT resolves to %qT, which is not a union type",
t, f);
else
return error_mark_node;
@@ -17158,18 +17303,24 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case UNBOUND_CLASS_TEMPLATE:
{
- ++processing_template_decl;
- tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args,
- complain, in_decl);
- --processing_template_decl;
tree name = TYPE_IDENTIFIER (t);
+ if (name == error_mark_node)
+ return error_mark_node;
+
tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
+ parm_list = tsubst_template_parms (parm_list, args, complain);
+ if (parm_list == error_mark_node)
+ return error_mark_node;
- if (ctx == error_mark_node || name == error_mark_node)
+ if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1)
+ ++processing_template_decl;
+ tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args,
+ complain, in_decl);
+ if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1)
+ --processing_template_decl;
+ if (ctx == error_mark_node)
return error_mark_node;
- if (parm_list)
- parm_list = tsubst_template_parms (parm_list, args, complain);
return make_unbound_class_template (ctx, name, parm_list, complain);
}
@@ -17443,10 +17594,18 @@ tsubst_baselink (tree baselink, tree object_type,
if (!baselink)
{
- if ((complain & tf_error)
- && constructor_name_p (name, qualifying_scope))
- error ("cannot call constructor %<%T::%D%> directly",
- qualifying_scope, name);
+ if (complain & tf_error)
+ {
+ if (constructor_name_p (name, qualifying_scope))
+ error ("cannot call constructor %<%T::%D%> directly",
+ qualifying_scope, name);
+ else
+ /* Lookup succeeded at parse time, but failed during
+ instantiation; must be because we're trying to refer to it
+ while forming its declaration (c++/120204). */
+ error ("declaration of %<%T::%D%> depends on itself",
+ qualifying_scope, name);
+ }
return error_mark_node;
}
@@ -17741,13 +17900,37 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
if (TYPE_P (t))
{
+ bool stripped = false;
if (typedef_variant_p (t))
- t = strip_typedefs (t);
- tree decl = TYPE_NAME (t);
+ {
+ /* Since this transformation may undesirably turn a deduced context
+ into a non-deduced one, we'd rather strip typedefs than perform
+ the transformation. */
+ tree u = strip_typedefs (t);
+ if (u != t)
+ {
+ stripped = true;
+ t = u;
+ }
+ }
+ decl = TYPE_NAME (t);
if (decl)
decl = maybe_dependent_member_ref (decl, args, complain, in_decl);
if (!decl)
- return NULL_TREE;
+ {
+ if (stripped)
+ /* The original type was an alias from the current instantiation
+ which we stripped to something outside it. At this point we
+ need to commit to using the stripped type rather than deferring
+ to the caller (which would use the original type), to ensure
+ eligible bits of the stripped type get transformed. */
+ return tsubst (t, args, complain, in_decl);
+ else
+ /* The original type wasn't a typedef, and we decided it doesn't
+ need rewriting, so just let the caller (tsubst) substitute it
+ normally. */
+ return NULL_TREE;
+ }
return cp_build_qualified_type (TREE_TYPE (decl), cp_type_quals (t),
complain);
}
@@ -17765,7 +17948,8 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
if (TREE_CODE (t) == TYPE_DECL)
{
- if (TREE_CODE (TREE_TYPE (t)) == TYPENAME_TYPE
+ if (!is_typedef_decl (t)
+ && TREE_CODE (TREE_TYPE (t)) == TYPENAME_TYPE
&& TYPE_NAME (TREE_TYPE (t)) == t)
/* The TYPE_DECL for a typename has DECL_CONTEXT of the typename
scope, but it doesn't need to be rewritten again. */
@@ -18165,8 +18349,10 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
}
new_clauses = nreverse (new_clauses);
- if (ort != C_ORT_OMP_DECLARE_SIMD)
+ if (ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_OMP_DECLARE_MAPPER)
{
+ if (ort == C_ORT_OMP_TARGET)
+ new_clauses = c_omp_instantiate_mappers (new_clauses);
new_clauses = finish_omp_clauses (new_clauses, ort);
if (linear_no_step)
for (nc = new_clauses; nc; nc = OMP_CLAUSE_CHAIN (nc))
@@ -18220,7 +18406,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain,
}
}
- switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type)
+ enum omp_tp_type property_kind
+ = omp_ts_map[OMP_TS_CODE (sel)].tp_type;
+ switch (property_kind)
{
case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR:
case OMP_TRAIT_PROPERTY_BOOL_EXPR:
@@ -18228,12 +18416,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain,
args, complain, in_decl);
t = fold_non_dependent_expr (t);
if (!value_dependent_expression_p (t)
- && !type_dependent_expression_p (t)
- && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
- error_at (cp_expr_loc_or_input_loc (t),
- "property must be integer expression");
- else
- properties = make_trait_property (NULL_TREE, t, NULL_TREE);
+ && !type_dependent_expression_p (t))
+ {
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ t = maybe_convert_cond (t);
+ else
+ {
+ t = convert_from_reference (t);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (cp_expr_loc_or_input_loc (t),
+ "property must be integer expression");
+ t = error_mark_node;
+ }
+ }
+ }
+ if (t != error_mark_node
+ && !processing_template_decl
+ && TREE_CODE (t) != CLEANUP_POINT_EXPR)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ properties = make_trait_property (NULL_TREE, t, NULL_TREE);
break;
case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD)
@@ -19886,6 +20088,22 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
break;
}
+ case OMP_DECLARE_MAPPER:
+ {
+ t = copy_node (t);
+
+ tree decl = OMP_DECLARE_MAPPER_DECL (t);
+ decl = tsubst (decl, args, complain, in_decl);
+ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t);
+ clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args,
+ complain, in_decl);
+ TREE_TYPE (t) = type;
+ OMP_DECLARE_MAPPER_DECL (t) = decl;
+ OMP_DECLARE_MAPPER_CLAUSES (t) = clauses;
+ RETURN (t);
+ }
+
case TRANSACTION_EXPR:
{
int flags = 0;
@@ -19929,7 +20147,14 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
tree op0 = RECUR (TREE_OPERAND (t, 0));
tree cond = RECUR (MUST_NOT_THROW_COND (t));
- RETURN (build_must_not_throw_expr (op0, cond));
+ stmt = build_must_not_throw_expr (op0, cond);
+ if (stmt && TREE_CODE (stmt) == MUST_NOT_THROW_EXPR)
+ {
+ MUST_NOT_THROW_NOEXCEPT_P (stmt) = MUST_NOT_THROW_NOEXCEPT_P (t);
+ MUST_NOT_THROW_THROW_P (stmt) = MUST_NOT_THROW_THROW_P (t);
+ MUST_NOT_THROW_CATCH_P (stmt) = MUST_NOT_THROW_CATCH_P (t);
+ }
+ RETURN (stmt);
}
case EXPR_PACK_EXPANSION:
@@ -20945,6 +21170,23 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
RETURN (build_omp_array_section (EXPR_LOCATION (t), op0, op1, op2));
}
+ case OMP_DECLARE_MAPPER:
+ {
+ t = copy_node (t);
+
+ tree decl = OMP_DECLARE_MAPPER_DECL (t);
+ DECL_OMP_DECLARE_MAPPER_P (decl) = 1;
+ decl = tsubst (decl, args, complain, in_decl);
+ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ tree clauses = OMP_DECLARE_MAPPER_CLAUSES (t);
+ clauses = tsubst_omp_clauses (clauses, C_ORT_OMP_DECLARE_MAPPER, args,
+ complain, in_decl);
+ TREE_TYPE (t) = type;
+ OMP_DECLARE_MAPPER_DECL (t) = decl;
+ OMP_DECLARE_MAPPER_CLAUSES (t) = clauses;
+ RETURN (t);
+ }
+
case SIZEOF_EXPR:
if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
|| ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
@@ -21276,13 +21518,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Avoid error about taking the address of a constructor. */
function = TREE_OPERAND (function, 0);
- tsubst_flags_t subcomplain = complain;
- if (koenig_p && TREE_CODE (function) == FUNCTION_DECL)
- /* When KOENIG_P, we don't want to mark_used the callee before
- augmenting the overload set via ADL, so during this initial
- substitution we disable mark_used by setting tf_conv (68942). */
- subcomplain |= tf_conv;
- function = tsubst_expr (function, args, subcomplain, in_decl);
+ function = tsubst_expr (function, args, complain, in_decl);
if (BASELINK_P (function))
qualified_p = true;
@@ -22650,7 +22886,7 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
FUNCTION_DECL which is the desired context for access checking
is not built yet. We solve this chicken-and-egg problem by
deferring all checks until we have the FUNCTION_DECL. */
- push_deferring_access_checks (dk_deferred);
+ deferring_access_check_sentinel dacs (dk_deferred);
/* Instantiation of the function happens in the context of the function
template, not the context of the overload resolution we're doing. */
@@ -22708,10 +22944,13 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
pop_from_top_level ();
if (fndecl == error_mark_node)
- {
- pop_deferring_access_checks ();
- return error_mark_node;
- }
+ return error_mark_node;
+
+ /* Substituting the type might have recursively instantiated this
+ same alias (c++/117530). */
+ if (DECL_ALIAS_TEMPLATE_P (gen_tmpl)
+ && (spec = retrieve_specialization (gen_tmpl, targ_ptr, hash)))
+ return spec;
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
@@ -22746,7 +22985,6 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
access_ok = false;
pop_access_scope (fndecl);
}
- pop_deferring_access_checks ();
/* If we've just instantiated the main entry point for a function,
instantiate all the alternate entry points as well. We do this
@@ -23199,7 +23437,7 @@ fn_type_unification (tree fn,
conversions that we know are not going to induce template instantiation
(PR99599). */
if (strict == DEDUCE_CALL
- && incomplete
+ && incomplete && flag_concepts
&& check_non_deducible_conversions (parms, args, nargs, fn, strict, flags,
convs, explain_p,
/*noninst_only_p=*/true))
@@ -23446,9 +23684,13 @@ maybe_adjust_types_for_deduction (tree tparms,
return result;
}
-/* Return true if computing a conversion from FROM to TO might induce template
- instantiation. Conversely, if this predicate returns false then computing
- the conversion definitely won't induce template instantiation. */
+/* Return true if computing a conversion from FROM to TO might consider
+ user-defined conversions, which could lead to arbitrary template
+ instantiations (e.g. g++.dg/cpp2a/concepts-nondep1.C). If this predicate
+ returns false then computing the conversion definitely won't try UDCs.
+
+ Note that this restriction parallels LOOKUP_DEFAULTED for CWG1092, but in
+ this case we want the early filter to pass instead of fail. */
static bool
conversion_may_instantiate_p (tree to, tree from)
@@ -23456,45 +23698,23 @@ conversion_may_instantiate_p (tree to, tree from)
to = non_reference (to);
from = non_reference (from);
- bool ptr_conv_p = false;
- if (TYPE_PTR_P (to)
- && TYPE_PTR_P (from))
- {
- to = TREE_TYPE (to);
- from = TREE_TYPE (from);
- ptr_conv_p = true;
- }
-
- /* If one of the types is a not-yet-instantiated class template
- specialization, then computing the conversion might instantiate
- it in order to inspect bases, conversion functions and/or
- converting constructors. */
- if ((CLASS_TYPE_P (to)
- && !COMPLETE_TYPE_P (to)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (to))
- || (CLASS_TYPE_P (from)
- && !COMPLETE_TYPE_P (from)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (from)))
- return true;
-
- /* Converting from one pointer type to another, or between
- reference-related types, always yields a standard conversion. */
- if (ptr_conv_p || reference_related_p (to, from))
+ /* Converting between reference-related types is a standard conversion. */
+ if (reference_related_p (to, from))
return false;
/* Converting to a non-aggregate class type will consider its
user-declared constructors, which might induce instantiation. */
- if (CLASS_TYPE_P (to)
- && CLASSTYPE_NON_AGGREGATE (to))
+ if (CLASS_TYPE_P (complete_type (to))
+ && type_has_converting_constructor (to))
return true;
/* Similarly, converting from a class type will consider its conversion
functions. */
- if (CLASS_TYPE_P (from)
+ if (CLASS_TYPE_P (complete_type (from))
&& TYPE_HAS_CONVERSION (from))
return true;
- /* Otherwise, computing this conversion definitely won't induce
+ /* Otherwise, computing this conversion won't risk arbitrary
template instantiation. */
return false;
}
@@ -24400,7 +24620,8 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
}
if (good == 1)
{
- mark_used (goodfn);
+ if (!mark_used (goodfn, complain) && !(complain & tf_error))
+ return error_mark_node;
expr = goodfn;
if (baselink)
expr = build_baselink (BASELINK_BINFO (baselink),
@@ -25740,10 +25961,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (parm)),
INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (t)),
UNIFY_ALLOW_NONE, explain_p);
- else
- return unify_success (explain_p);
+ gcc_checking_assert (t == arg);
}
- else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
+
+ if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
return unify_type_mismatch (explain_p, parm, arg);
return unify_success (explain_p);
@@ -27332,6 +27553,10 @@ tree
template_for_substitution (tree decl)
{
tree tmpl = DECL_TI_TEMPLATE (decl);
+ if (VAR_P (decl))
+ if (tree partial = most_specialized_partial_spec (decl, tf_none))
+ if (partial != error_mark_node)
+ tmpl = TI_TEMPLATE (partial);
/* Set TMPL to the template whose DECL_TEMPLATE_RESULT is the pattern
for the instantiation. This is not always the most general
@@ -27712,6 +27937,11 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p)
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
cp_check_omp_declare_reduction (d);
+
+ if (int errs = errorcount + sorrycount)
+ if (errs > current_tinst_level->errors)
+ if (function *f = DECL_STRUCT_FUNCTION (d))
+ f->language->erroneous = true;
}
/* We're not deferring instantiation any more. */
@@ -27905,7 +28135,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
|| (external_p && VAR_P (d))
/* Handle here a deleted function too, avoid generating
its body (c++/61080). */
- || deleted_p)
+ || deleted_p
+ /* We need the initializer for an OpenMP declare mapper. */
+ || (VAR_P (d) && DECL_LANG_SPECIFIC (d) && DECL_OMP_DECLARE_MAPPER_P (d)))
{
/* The definition of the static data member is now required so
we must substitute the initializer. */
@@ -28018,12 +28250,16 @@ instantiate_pending_templates (int retries)
reconsider = 0;
while (*t)
{
- tree instantiation = reopen_tinst_level ((*t)->tinst);
- bool complete = false;
+ struct tinst_level *tinst = (*t)->tinst;
+ bool complete = tinst_complete_p (tinst);
- if (TYPE_P (instantiation))
+ if (!complete)
{
- if (!COMPLETE_TYPE_P (instantiation))
+ tree instantiation = reopen_tinst_level (tinst);
+
+ if (limit_bad_template_recursion (instantiation))
+ /* Do nothing. */;
+ else if (TYPE_P (instantiation))
{
instantiate_class_template (instantiation);
if (CLASSTYPE_TEMPLATE_INSTANTIATION (instantiation))
@@ -28040,13 +28276,7 @@ instantiate_pending_templates (int retries)
if (COMPLETE_TYPE_P (instantiation))
reconsider = 1;
}
-
- complete = COMPLETE_TYPE_P (instantiation);
- }
- else
- {
- if (!DECL_TEMPLATE_SPECIALIZATION (instantiation)
- && !DECL_TEMPLATE_INSTANTIATED (instantiation))
+ else
{
instantiation
= instantiate_decl (instantiation,
@@ -28056,8 +28286,10 @@ instantiate_pending_templates (int retries)
reconsider = 1;
}
- complete = (DECL_TEMPLATE_SPECIALIZATION (instantiation)
- || DECL_TEMPLATE_INSTANTIATED (instantiation));
+ complete = tinst_complete_p (tinst);
+
+ tinst_depth = 0;
+ set_refcount_ptr (current_tinst_level);
}
if (complete)
@@ -28074,8 +28306,6 @@ instantiate_pending_templates (int retries)
last = *t;
t = &(*t)->next;
}
- tinst_depth = 0;
- set_refcount_ptr (current_tinst_level);
}
last_pending_template = last;
}
@@ -30898,9 +31128,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
tree aguides = NULL_TREE;
tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms);
unsigned natparms = TREE_VEC_LENGTH (atparms);
- for (ovl_iterator iter (uguides); iter; ++iter)
+ for (tree f : lkp_range (uguides))
{
- tree f = *iter;
tree in_decl = f;
location_t loc = DECL_SOURCE_LOCATION (f);
tree ret = TREE_TYPE (TREE_TYPE (f));
diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc
index 3539962..c06a18b 100644
--- a/gcc/cp/rtti.cc
+++ b/gcc/cp/rtti.cc
@@ -468,6 +468,7 @@ get_tinfo_decl_direct (tree type, tree name, int pseudo_ix)
DECL_IGNORED_P (d) = 1;
TREE_READONLY (d) = 1;
TREE_STATIC (d) = 1;
+ TREE_ADDRESSABLE (d) = 1;
/* Tell equal_address_to that different tinfo decls never
overlap. */
if (vec_safe_is_empty (unemitted_tinfo_decls))
@@ -1318,18 +1319,9 @@ get_pseudo_ti_index (tree type)
static tinfo_s *
get_tinfo_desc (unsigned ix)
{
- unsigned len = tinfo_descs->length ();
-
- if (len <= ix)
- {
- /* too short, extend. */
- len = ix + 1 - len;
- vec_safe_reserve (tinfo_descs, len);
- tinfo_s elt;
- elt.type = elt.vtable = elt.name = NULL_TREE;
- while (len--)
- tinfo_descs->quick_push (elt);
- }
+ if (tinfo_descs->length () <= ix)
+ /* too short, extend. */
+ vec_safe_grow_cleared (tinfo_descs, ix + 1);
tinfo_s *res = &(*tinfo_descs)[ix];
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7d8beb8..b57547c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -45,13 +45,13 @@ along with GCC; see the file COPYING3. If not see
#include "gomp-constants.h"
#include "predict.h"
#include "memmodel.h"
+#include "gimplify.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
during template instantiation, which may be regarded as a
degenerate form of parsing. */
-static tree maybe_convert_cond (tree);
static tree finalize_nrv_r (tree *, int *, void *);
/* Used for OpenMP non-static data member privatization. */
@@ -1116,7 +1116,7 @@ annotate_saver::restore (tree new_inner)
statement. Convert it to a boolean value, if appropriate.
In addition, verify sequence points if -Wsequence-point is enabled. */
-static tree
+tree
maybe_convert_cond (tree cond)
{
/* Empty conditions remain empty. */
@@ -1180,10 +1180,13 @@ finish_expr_stmt (tree expr)
expr = error_mark_node;
/* Simplification of inner statement expressions, compound exprs,
- etc can result in us already having an EXPR_STMT. */
+ etc can result in us already having an EXPR_STMT or other statement
+ tree. Don't wrap them in EXPR_STMT. */
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
{
- if (TREE_CODE (expr) != EXPR_STMT)
+ if (TREE_CODE (expr) != EXPR_STMT
+ && !STATEMENT_CLASS_P (expr)
+ && TREE_CODE (expr) != STATEMENT_LIST)
expr = build_stmt (loc, EXPR_STMT, expr);
expr = maybe_cleanup_point_expr_void (expr);
}
@@ -2767,7 +2770,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope,
else if (PACK_EXPANSION_P (type))
/* Don't bother trying to represent this. */
type = NULL_TREE;
- else if (WILDCARD_TYPE_P (TREE_TYPE (object)))
+ else if (!TREE_TYPE (object) || WILDCARD_TYPE_P (TREE_TYPE (object)))
/* We don't know what the eventual quals will be, so punt until
instantiation time.
@@ -3082,6 +3085,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
}
else if (processing_template_decl)
{
+ /* Not finish_expr_stmt because we don't want convert_to_void. */
expr = build_stmt (input_location, EXPR_STMT, expr);
expr = add_stmt (expr);
/* Mark the last statement so that we can recognize it as such at
@@ -3321,6 +3325,14 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (*args))
{
+ if (koenig_p
+ && TREE_CODE (orig_fn) == FUNCTION_DECL
+ && !fndecl_built_in_p (orig_fn))
+ /* For an ADL-enabled call where unqualified lookup found a
+ single non-template function, wrap it in an OVERLOAD so that
+ later substitution doesn't overeagerly mark the function as
+ used. */
+ orig_fn = ovl_make (orig_fn, NULL_TREE);
result = build_min_nt_call_vec (orig_fn, *args);
SET_EXPR_LOCATION (result, cp_expr_loc_or_input_loc (fn));
KOENIG_LOOKUP_P (result) = koenig_p;
@@ -3593,16 +3605,13 @@ finish_this_expr (void)
{
tree result = NULL_TREE;
- if (current_class_ptr)
- {
- tree type = TREE_TYPE (current_class_ref);
-
- /* In a lambda expression, 'this' refers to the captured 'this'. */
- if (LAMBDA_TYPE_P (type))
- result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type), true);
- else
- result = current_class_ptr;
- }
+ 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
+ gcc_checking_assert (!current_class_ptr);
if (result)
/* The keyword 'this' is a prvalue expression. */
@@ -4755,6 +4764,7 @@ finish_id_expression_1 (tree id_expression,
body, except inside an unevaluated context (i.e. decltype). */
if (TREE_CODE (decl) == PARM_DECL
&& DECL_CONTEXT (decl) == NULL_TREE
+ && !CONSTRAINT_VAR_P (decl)
&& !cp_unevaluated_operand
&& !processing_contract_condition
&& !processing_omp_trait_property_expr)
@@ -5087,22 +5097,32 @@ static tree
finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain)
{
idx = maybe_constant_value (idx, NULL_TREE, mce_true);
- if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx)))
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (idx)))
{
if (complain & tf_error)
- error ("pack index is not an integral constant");
+ error ("pack index has non-integral type %qT", TREE_TYPE (idx));
+ return error_mark_node;
+ }
+ if (TREE_CODE (idx) != INTEGER_CST)
+ {
+ if (complain & tf_error)
+ {
+ error ("pack index is not an integral constant");
+ cxx_constant_value (idx);
+ }
return error_mark_node;
}
if (tree_int_cst_sgn (idx) < 0)
{
if (complain & tf_error)
- error ("pack index is negative");
+ error ("pack index %qE is negative", idx);
return error_mark_node;
}
if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types))
{
if (complain & tf_error)
- error ("pack index is out of range");
+ error ("pack index %qE is out of range for pack of length %qd",
+ idx, TREE_VEC_LENGTH (types));
return error_mark_node;
}
return TREE_VEC_ELT (types, tree_to_shwi (idx));
@@ -6722,6 +6742,97 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp,
return id;
}
+/* Return identifier to look up for omp declare mapper. */
+
+tree
+omp_mapper_id (tree mapper_id, tree type)
+{
+ const char *p = NULL;
+ const char *m = NULL;
+
+ if (mapper_id == NULL_TREE)
+ p = "";
+ else if (TREE_CODE (mapper_id) == IDENTIFIER_NODE)
+ p = IDENTIFIER_POINTER (mapper_id);
+ else
+ return error_mark_node;
+
+ if (type != NULL_TREE)
+ m = mangle_type_string (TYPE_MAIN_VARIANT (type));
+
+ const char prefix[] = "omp declare mapper ";
+ size_t lenp = sizeof (prefix);
+ if (strncmp (p, prefix, lenp - 1) == 0)
+ lenp = 1;
+ size_t len = strlen (p);
+ size_t lenm = m ? strlen (m) + 1 : 0;
+ char *name = XALLOCAVEC (char, lenp + len + lenm);
+ memcpy (name, prefix, lenp - 1);
+ memcpy (name + lenp - 1, p, len + 1);
+ if (m)
+ {
+ name[lenp + len - 1] = '~';
+ memcpy (name + lenp + len, m, lenm);
+ }
+ return get_identifier (name);
+}
+
+tree
+cxx_omp_mapper_lookup (tree id, tree type)
+{
+ if (!RECORD_OR_UNION_TYPE_P (type))
+ return NULL_TREE;
+ id = omp_mapper_id (id, type);
+ return lookup_name (id);
+}
+
+tree
+cxx_omp_extract_mapper_directive (tree vardecl)
+{
+ gcc_assert (TREE_CODE (vardecl) == VAR_DECL);
+
+ /* Instantiate the decl if we haven't already. */
+ mark_used (vardecl);
+ tree body = DECL_INITIAL (vardecl);
+
+ if (TREE_CODE (body) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator tsi = tsi_start (body);
+ gcc_assert (TREE_CODE (tsi_stmt (tsi)) == DECL_EXPR);
+ tsi_next (&tsi);
+ body = tsi_stmt (tsi);
+ }
+
+ gcc_assert (TREE_CODE (body) == OMP_DECLARE_MAPPER);
+
+ return body;
+}
+
+/* For now we can handle singleton OMP_ARRAY_SECTIONs with custom mappers, but
+ nothing more complicated. */
+
+tree
+cxx_omp_map_array_section (location_t loc, tree t)
+{
+ tree low = TREE_OPERAND (t, 1);
+ tree len = TREE_OPERAND (t, 2);
+
+ if (len && integer_onep (len))
+ {
+ t = TREE_OPERAND (t, 0);
+
+ if (!low)
+ low = integer_zero_node;
+
+ if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ t = convert_from_reference (t);
+
+ t = build_array_ref (loc, t, low);
+ }
+
+ return t;
+}
+
/* Helper function for cp_parser_omp_declare_reduction_exprs
and tsubst_omp_udr.
Remove CLEANUP_STMT for data (omp_priv variable).
@@ -7203,6 +7314,33 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
return false;
}
+/* Check an instance of an "omp declare mapper" function. */
+
+bool
+cp_check_omp_declare_mapper (tree udm)
+{
+ tree type = TREE_TYPE (udm);
+ location_t loc = DECL_SOURCE_LOCATION (udm);
+
+ if (type == error_mark_node)
+ return false;
+
+ if (!processing_template_decl && !RECORD_OR_UNION_TYPE_P (type))
+ {
+ error_at (loc, "%qT is not a struct, union or class type in "
+ "%<#pragma omp declare mapper%>", type);
+ return false;
+ }
+ if (!processing_template_decl && CLASSTYPE_VBASECLASSES (type))
+ {
+ error_at (loc, "%qT must not be a virtual base class in "
+ "%<#pragma omp declare mapper%>", type);
+ return false;
+ }
+
+ return true;
+}
+
/* Called from finish_struct_1. linear(this) or linear(this:step)
clauses might not be finalized yet because the class has been incomplete
when parsing #pragma omp declare simd methods. Fix those up now. */
@@ -8847,6 +8985,12 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
case OMP_CLAUSE_MAP:
if (OMP_CLAUSE_MAP_IMPLICIT (c) && !implicit_moved)
goto move_implicit;
+ if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME)
+ {
+ remove = true;
+ break;
+ }
/* FALLTHRU */
case OMP_CLAUSE_TO:
case OMP_CLAUSE_FROM:
@@ -10466,6 +10610,8 @@ struct omp_target_walk_data
/* Local variables declared inside a BIND_EXPR, used to filter out such
variables when recording lambda_objects_accessed. */
hash_set<tree> local_decls;
+
+ omp_mapper_list<tree> *mappers;
};
/* Helper function of finish_omp_target_clauses, called via
@@ -10479,6 +10625,7 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr)
struct omp_target_walk_data *data = (struct omp_target_walk_data *) ptr;
tree current_object = data->current_object;
tree current_closure = data->current_closure;
+ omp_mapper_list<tree> *mlist = data->mappers;
/* References inside of these expression codes shouldn't incur any
form of mapping, so return early. */
@@ -10492,6 +10639,27 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr)
if (TREE_CODE (t) == OMP_CLAUSE)
return NULL_TREE;
+ if (!processing_template_decl)
+ {
+ tree aggr_type = NULL_TREE;
+
+ if (TREE_CODE (t) == COMPONENT_REF
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0))))
+ aggr_type = TREE_TYPE (TREE_OPERAND (t, 0));
+ else if ((TREE_CODE (t) == VAR_DECL
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL)
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t)))
+ aggr_type = TREE_TYPE (t);
+
+ if (aggr_type)
+ {
+ tree mapper_fn = cxx_omp_mapper_lookup (NULL_TREE, aggr_type);
+ if (mapper_fn)
+ mlist->add_mapper (NULL_TREE, aggr_type, mapper_fn);
+ }
+ }
+
if (current_object)
{
tree this_expr = TREE_OPERAND (current_object, 0);
@@ -10542,10 +10710,10 @@ finish_omp_target_clauses_r (tree *tp, int *walk_subtrees, void *ptr)
if (TREE_CODE (t) == BIND_EXPR)
{
- tree block = BIND_EXPR_BLOCK (t);
- for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
- if (!data->local_decls.contains (var))
- data->local_decls.add (var);
+ if (tree block = BIND_EXPR_BLOCK (t))
+ for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
+ if (!data->local_decls.contains (var))
+ data->local_decls.add (var);
return NULL_TREE;
}
@@ -10594,10 +10762,48 @@ finish_omp_target_clauses (location_t loc, tree body, tree *clauses_ptr)
else
data.current_closure = NULL_TREE;
- cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r, &data);
-
auto_vec<tree, 16> new_clauses;
+ if (!processing_template_decl)
+ {
+ hash_set<omp_name_type<tree> > seen_types;
+ auto_vec<tree> mapper_fns;
+ omp_mapper_list<tree> mlist (&seen_types, &mapper_fns);
+ data.mappers = &mlist;
+
+ cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r,
+ &data);
+
+ unsigned int i;
+ tree mapper_fn;
+ FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn)
+ c_omp_find_nested_mappers (&mlist, mapper_fn);
+
+ FOR_EACH_VEC_ELT (mapper_fns, i, mapper_fn)
+ {
+ tree mapper = cxx_omp_extract_mapper_directive (mapper_fn);
+ if (mapper == error_mark_node)
+ continue;
+ tree mapper_name = OMP_DECLARE_MAPPER_ID (mapper);
+ tree decl = OMP_DECLARE_MAPPER_DECL (mapper);
+ if (BASELINK_P (mapper_fn))
+ mapper_fn = BASELINK_FUNCTIONS (mapper_fn);
+
+ tree c = build_omp_clause (loc, OMP_CLAUSE__MAPPER_BINDING_);
+ OMP_CLAUSE__MAPPER_BINDING__ID (c) = mapper_name;
+ OMP_CLAUSE__MAPPER_BINDING__DECL (c) = decl;
+ OMP_CLAUSE__MAPPER_BINDING__MAPPER (c) = mapper_fn;
+
+ new_clauses.safe_push (c);
+ }
+ }
+ else
+ {
+ data.mappers = NULL;
+ cp_walk_tree_without_duplicates (&body, finish_omp_target_clauses_r,
+ &data);
+ }
+
tree omp_target_this_expr = NULL_TREE;
tree *explicit_this_deref_map = NULL;
if (data.this_expr_accessed)
@@ -13212,6 +13418,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
type1 = strip_array_types (type1);
+ if (CLASS_TYPE_P (type1) && type_build_dtor_call (type1))
+ {
+ deferring_access_check_sentinel dacs (dk_no_check);
+ cp_unevaluated un;
+ tree fn = get_dtor (type1, tf_none);
+ if (!fn && !seen_error ())
+ warning (0, "checking %qs for type %qT with a destructor that "
+ "cannot be called", "__has_trivial_destructor", type1);
+ }
return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE
|| (CLASS_TYPE_P (type1)
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
@@ -13267,6 +13482,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_CONVERTIBLE:
return is_convertible (type1, type2);
+ case CPTK_IS_DESTRUCTIBLE:
+ return is_xible (BIT_NOT_EXPR, type1, NULL_TREE);
+
case CPTK_IS_EMPTY:
return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
@@ -13306,6 +13524,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_NOTHROW_CONVERTIBLE:
return is_nothrow_convertible (type1, type2);
+ case CPTK_IS_NOTHROW_DESTRUCTIBLE:
+ return is_nothrow_xible (BIT_NOT_EXPR, type1, NULL_TREE);
+
case CPTK_IS_NOTHROW_INVOCABLE:
return expr_noexcept_p (build_invoke (type1, type2, tf_none), tf_none);
@@ -13348,6 +13569,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_TRIVIALLY_COPYABLE:
return trivially_copyable_p (type1);
+ case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
+ return is_trivially_xible (BIT_NOT_EXPR, type1, NULL_TREE);
+
case CPTK_IS_UNBOUNDED_ARRAY:
return array_of_unknown_bound_p (type1);
@@ -13371,8 +13595,10 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_DEDUCIBLE:
return type_targs_deducible_from (type1, type2);
- /* __array_rank is handled in finish_trait_expr. */
+ /* __array_rank and __builtin_type_order are handled in
+ finish_trait_expr. */
case CPTK_RANK:
+ case CPTK_TYPE_ORDER:
gcc_unreachable ();
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
@@ -13502,6 +13728,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
tree trait_expr = make_node (TRAIT_EXPR);
if (kind == CPTK_RANK)
TREE_TYPE (trait_expr) = size_type_node;
+ else if (kind == CPTK_TYPE_ORDER)
+ {
+ tree val = type_order_value (type1, type1);
+ if (val != error_mark_node)
+ TREE_TYPE (trait_expr) = TREE_TYPE (val);
+ }
else
TREE_TYPE (trait_expr) = boolean_type_node;
TRAIT_EXPR_TYPE1 (trait_expr) = type1;
@@ -13520,6 +13752,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_HAS_NOTHROW_COPY:
case CPTK_HAS_TRIVIAL_COPY:
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+ case CPTK_IS_DESTRUCTIBLE:
+ case CPTK_IS_NOTHROW_DESTRUCTIBLE:
+ case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
if (!check_trait_type (type1))
return error_mark_node;
break;
@@ -13606,6 +13841,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNION:
case CPTK_IS_VOLATILE:
case CPTK_RANK:
+ case CPTK_TYPE_ORDER:
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -13645,6 +13881,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
++rank;
val = build_int_cst (size_type_node, rank);
}
+ else if (kind == CPTK_TYPE_ORDER)
+ val = type_order_value (type1, type2);
else
val = (trait_expr_value (kind, type1, type2)
? boolean_true_node : boolean_false_node);
diff --git a/gcc/cp/std-name-hint.h b/gcc/cp/std-name-hint.h
index dde2f9b..c5f8004 100644
--- a/gcc/cp/std-name-hint.h
+++ b/gcc/cp/std-name-hint.h
@@ -144,979 +144,979 @@ std_name_hint_lookup::find (const char *str, size_t len)
static const struct std_name_hint wordlist[] =
{
-#line 130 "../../src/gcc/cp/std-name-hint.gperf"
+#line 130 "std-name-hint.gperf"
{"regular", "<concepts>", cxx20},
-#line 292 "../../src/gcc/cp/std-name-hint.gperf"
+#line 292 "std-name-hint.gperf"
{"reverse_iterator", "<iterator>", cxx98},
-#line 454 "../../src/gcc/cp/std-name-hint.gperf"
+#line 454 "std-name-hint.gperf"
{"range_error", "<stdexcept>", cxx98},
-#line 408 "../../src/gcc/cp/std-name-hint.gperf"
+#line 408 "std-name-hint.gperf"
{"set", "<set>", cxx98},
-#line 231 "../../src/gcc/cp/std-name-hint.gperf"
+#line 231 "std-name-hint.gperf"
{"setbase", "<iomanip>", cxx98},
-#line 325 "../../src/gcc/cp/std-name-hint.gperf"
+#line 325 "std-name-hint.gperf"
{"reinterpret_pointer_cast", "<memory>", cxx17},
-#line 288 "../../src/gcc/cp/std-name-hint.gperf"
+#line 288 "std-name-hint.gperf"
{"next", "<iterator>", cxx11},
-#line 171 "../../src/gcc/cp/std-name-hint.gperf"
+#line 171 "std-name-hint.gperf"
{"format", "<format>", cxx20},
-#line 181 "../../src/gcc/cp/std-name-hint.gperf"
+#line 181 "std-name-hint.gperf"
{"formatter", "<format>", cxx20},
-#line 196 "../../src/gcc/cp/std-name-hint.gperf"
+#line 196 "std-name-hint.gperf"
{"basic_filebuf", "<fstream>", cxx98},
-#line 575 "../../src/gcc/cp/std-name-hint.gperf"
+#line 575 "std-name-hint.gperf"
{"pair", "<utility>", cxx98},
-#line 276 "../../src/gcc/cp/std-name-hint.gperf"
+#line 276 "std-name-hint.gperf"
{"begin", "<iterator>", cxx11},
-#line 179 "../../src/gcc/cp/std-name-hint.gperf"
+#line 179 "std-name-hint.gperf"
{"formattable", "<format>", cxx23},
-#line 541 "../../src/gcc/cp/std-name-hint.gperf"
+#line 541 "std-name-hint.gperf"
{"bad_cast", "<typeinfo>", cxx98},
-#line 233 "../../src/gcc/cp/std-name-hint.gperf"
+#line 233 "std-name-hint.gperf"
{"setiosflags", "<iomanip>", cxx98},
-#line 393 "../../src/gcc/cp/std-name-hint.gperf"
+#line 393 "std-name-hint.gperf"
{"print", "<print>", cxx23},
-#line 221 "../../src/gcc/cp/std-name-hint.gperf"
+#line 221 "std-name-hint.gperf"
{"promise", "<future>", cxx11},
-#line 581 "../../src/gcc/cp/std-name-hint.gperf"
+#line 581 "std-name-hint.gperf"
{"bad_variant_access", "<variant>", cxx17},
-#line 328 "../../src/gcc/cp/std-name-hint.gperf"
+#line 328 "std-name-hint.gperf"
{"to_address", "<memory>", cxx20},
-#line 420 "../../src/gcc/cp/std-name-hint.gperf"
+#line 420 "std-name-hint.gperf"
{"basic_spanbuf", "<spanstream>", cxx23},
-#line 106 "../../src/gcc/cp/std-name-hint.gperf"
+#line 106 "std-name-hint.gperf"
{"same_as", "<concepts>", cxx20},
-#line 336 "../../src/gcc/cp/std-name-hint.gperf"
+#line 336 "std-name-hint.gperf"
{"pmr", "<memory_resource>", cxx17},
-#line 180 "../../src/gcc/cp/std-name-hint.gperf"
+#line 180 "std-name-hint.gperf"
{"formatted_size", "<format>", cxx20},
-#line 275 "../../src/gcc/cp/std-name-hint.gperf"
+#line 275 "std-name-hint.gperf"
{"back_inserter", "<iterator>", cxx98},
-#line 251 "../../src/gcc/cp/std-name-hint.gperf"
+#line 251 "std-name-hint.gperf"
{"nouppercase", "<ios>", cxx98},
-#line 250 "../../src/gcc/cp/std-name-hint.gperf"
+#line 250 "std-name-hint.gperf"
{"nounitbuf", "<ios>", cxx98},
-#line 433 "../../src/gcc/cp/std-name-hint.gperf"
+#line 433 "std-name-hint.gperf"
{"basic_stringbuf", "<sstream>", cxx98},
-#line 592 "../../src/gcc/cp/std-name-hint.gperf"
+#line 592 "std-name-hint.gperf"
{"vector", "<vector>", cxx98},
-#line 246 "../../src/gcc/cp/std-name-hint.gperf"
+#line 246 "std-name-hint.gperf"
{"noshowbase", "<ios>", cxx98},
-#line 219 "../../src/gcc/cp/std-name-hint.gperf"
+#line 219 "std-name-hint.gperf"
{"future", "<future>", cxx11},
-#line 340 "../../src/gcc/cp/std-name-hint.gperf"
+#line 340 "std-name-hint.gperf"
{"pmr::new_delete_resource", "<memory_resource>", cxx17},
-#line 337 "../../src/gcc/cp/std-name-hint.gperf"
+#line 337 "std-name-hint.gperf"
{"pmr::get_default_resource", "<memory_resource>", cxx17},
-#line 343 "../../src/gcc/cp/std-name-hint.gperf"
+#line 343 "std-name-hint.gperf"
{"pmr::set_default_resource", "<memory_resource>", cxx17},
-#line 455 "../../src/gcc/cp/std-name-hint.gperf"
+#line 455 "std-name-hint.gperf"
{"runtime_error", "<stdexcept>", cxx98},
-#line 516 "../../src/gcc/cp/std-name-hint.gperf"
+#line 516 "std-name-hint.gperf"
{"tuple", "<tuple>", cxx11},
-#line 132 "../../src/gcc/cp/std-name-hint.gperf"
+#line 132 "std-name-hint.gperf"
{"regular_invocable", "<concepts>", cxx20},
-#line 116 "../../src/gcc/cp/std-name-hint.gperf"
+#line 116 "std-name-hint.gperf"
{"swappable", "<concepts>", cxx20},
-#line 186 "../../src/gcc/cp/std-name-hint.gperf"
+#line 186 "std-name-hint.gperf"
{"runtime_format", "<format>", cxx26},
-#line 211 "../../src/gcc/cp/std-name-hint.gperf"
+#line 211 "std-name-hint.gperf"
{"not_fn", "<functional>", cxx17},
-#line 142 "../../src/gcc/cp/std-name-hint.gperf"
+#line 142 "std-name-hint.gperf"
{"byte", "<cstddef>", cxx17},
-#line 518 "../../src/gcc/cp/std-name-hint.gperf"
+#line 518 "std-name-hint.gperf"
{"tuple_element", "<tuple>", cxx11},
-#line 519 "../../src/gcc/cp/std-name-hint.gperf"
+#line 519 "std-name-hint.gperf"
{"tuple_element_t", "<tuple>", cxx14},
-#line 584 "../../src/gcc/cp/std-name-hint.gperf"
+#line 584 "std-name-hint.gperf"
{"variant", "<variant>", cxx17},
-#line 386 "../../src/gcc/cp/std-name-hint.gperf"
+#line 386 "std-name-hint.gperf"
{"ends", "<ostream>", cxx98},
-#line 520 "../../src/gcc/cp/std-name-hint.gperf"
+#line 520 "std-name-hint.gperf"
{"tuple_size", "<tuple>", cxx11},
-#line 123 "../../src/gcc/cp/std-name-hint.gperf"
+#line 123 "std-name-hint.gperf"
{"equality_comparable", "<concepts>", cxx20},
-#line 247 "../../src/gcc/cp/std-name-hint.gperf"
+#line 247 "std-name-hint.gperf"
{"noshowpoint", "<ios>", cxx98},
-#line 394 "../../src/gcc/cp/std-name-hint.gperf"
+#line 394 "std-name-hint.gperf"
{"println", "<print>", cxx23},
-#line 248 "../../src/gcc/cp/std-name-hint.gperf"
+#line 248 "std-name-hint.gperf"
{"noshowpos", "<ios>", cxx98},
-#line 388 "../../src/gcc/cp/std-name-hint.gperf"
+#line 388 "std-name-hint.gperf"
{"flush_emit", "<ostream>", cxx20},
-#line 585 "../../src/gcc/cp/std-name-hint.gperf"
+#line 585 "std-name-hint.gperf"
{"variant_alternative", "<variant>", cxx17},
-#line 537 "../../src/gcc/cp/std-name-hint.gperf"
+#line 537 "std-name-hint.gperf"
{"void_t", "<type_traits>", cxx17},
-#line 586 "../../src/gcc/cp/std-name-hint.gperf"
+#line 586 "std-name-hint.gperf"
{"variant_alternative_t", "<variant>", cxx17},
-#line 134 "../../src/gcc/cp/std-name-hint.gperf"
+#line 134 "std-name-hint.gperf"
{"relation", "<concepts>", cxx20},
-#line 461 "../../src/gcc/cp/std-name-hint.gperf"
+#line 461 "std-name-hint.gperf"
{"float32_t", "<stdfloat>", cxx23},
-#line 459 "../../src/gcc/cp/std-name-hint.gperf"
+#line 459 "std-name-hint.gperf"
{"float128_t", "<stdfloat>", cxx23},
-#line 381 "../../src/gcc/cp/std-name-hint.gperf"
+#line 381 "std-name-hint.gperf"
{"nullopt", "<optional>", cxx17},
-#line 291 "../../src/gcc/cp/std-name-hint.gperf"
+#line 291 "std-name-hint.gperf"
{"prev", "<iterator>", cxx11},
-#line 425 "../../src/gcc/cp/std-name-hint.gperf"
+#line 425 "std-name-hint.gperf"
{"spanbuf", "<spanstream>", cxx23},
-#line 513 "../../src/gcc/cp/std-name-hint.gperf"
+#line 513 "std-name-hint.gperf"
{"make_from_tuple", "<tuple>", cxx17},
-#line 253 "../../src/gcc/cp/std-name-hint.gperf"
+#line 253 "std-name-hint.gperf"
{"right", "<ios>", cxx98},
-#line 210 "../../src/gcc/cp/std-name-hint.gperf"
+#line 210 "std-name-hint.gperf"
{"mem_fn", "<functional>", cxx11},
-#line 515 "../../src/gcc/cp/std-name-hint.gperf"
+#line 515 "std-name-hint.gperf"
{"tie", "<tuple>", cxx11},
-#line 197 "../../src/gcc/cp/std-name-hint.gperf"
+#line 197 "std-name-hint.gperf"
{"basic_fstream", "<fstream>", cxx98},
-#line 573 "../../src/gcc/cp/std-name-hint.gperf"
+#line 573 "std-name-hint.gperf"
{"move", "<utility>", cxx11},
-#line 462 "../../src/gcc/cp/std-name-hint.gperf"
+#line 462 "std-name-hint.gperf"
{"float64_t", "<stdfloat>", cxx23},
-#line 127 "../../src/gcc/cp/std-name-hint.gperf"
+#line 127 "std-name-hint.gperf"
{"movable", "<concepts>", cxx20},
-#line 282 "../../src/gcc/cp/std-name-hint.gperf"
+#line 282 "std-name-hint.gperf"
{"front_inserter", "<iterator>", cxx98},
-#line 296 "../../src/gcc/cp/std-name-hint.gperf"
+#line 296 "std-name-hint.gperf"
{"map", "<map>", cxx98},
-#line 460 "../../src/gcc/cp/std-name-hint.gperf"
+#line 460 "std-name-hint.gperf"
{"float16_t", "<stdfloat>", cxx23},
-#line 56 "../../src/gcc/cp/std-name-hint.gperf"
+#line 56 "std-name-hint.gperf"
{"bitset", "<bitset>", cxx11},
-#line 205 "../../src/gcc/cp/std-name-hint.gperf"
+#line 205 "std-name-hint.gperf"
{"bind_front", "<functional>", cxx20},
-#line 574 "../../src/gcc/cp/std-name-hint.gperf"
+#line 574 "std-name-hint.gperf"
{"move_if_noexcept", "<utility>", cxx11},
-#line 274 "../../src/gcc/cp/std-name-hint.gperf"
+#line 274 "std-name-hint.gperf"
{"advance", "<iterator>", cxx98},
-#line 287 "../../src/gcc/cp/std-name-hint.gperf"
+#line 287 "std-name-hint.gperf"
{"move_iterator", "<iterator>", cxx11},
-#line 161 "../../src/gcc/cp/std-name-hint.gperf"
+#line 161 "std-name-hint.gperf"
{"terminate", "<exception>", cxx98},
-#line 531 "../../src/gcc/cp/std-name-hint.gperf"
+#line 531 "std-name-hint.gperf"
{"negation", "<type_traits>", cxx17},
-#line 318 "../../src/gcc/cp/std-name-hint.gperf"
+#line 318 "std-name-hint.gperf"
{"make_obj_using_allocator", "<memory>", cxx20},
-#line 321 "../../src/gcc/cp/std-name-hint.gperf"
+#line 321 "std-name-hint.gperf"
{"make_unique", "<memory>", cxx14},
-#line 255 "../../src/gcc/cp/std-name-hint.gperf"
+#line 255 "std-name-hint.gperf"
{"showbase", "<ios>", cxx98},
-#line 416 "../../src/gcc/cp/std-name-hint.gperf"
+#line 416 "std-name-hint.gperf"
{"span", "<span>", cxx20},
-#line 185 "../../src/gcc/cp/std-name-hint.gperf"
+#line 185 "std-name-hint.gperf"
{"range_formatter", "<format>", cxx23},
-#line 299 "../../src/gcc/cp/std-name-hint.gperf"
+#line 299 "std-name-hint.gperf"
{"addressof", "<memory>", cxx11},
-#line 571 "../../src/gcc/cp/std-name-hint.gperf"
+#line 571 "std-name-hint.gperf"
{"make_integer_sequence", "<utility>", cxx14},
-#line 184 "../../src/gcc/cp/std-name-hint.gperf"
+#line 184 "std-name-hint.gperf"
{"range_format", "<format>", cxx23},
-#line 322 "../../src/gcc/cp/std-name-hint.gperf"
+#line 322 "std-name-hint.gperf"
{"make_unique_for_overwrite", "<memory>", cxx20},
-#line 421 "../../src/gcc/cp/std-name-hint.gperf"
+#line 421 "std-name-hint.gperf"
{"basic_spanstream", "<spanstream>", cxx23},
-#line 257 "../../src/gcc/cp/std-name-hint.gperf"
+#line 257 "std-name-hint.gperf"
{"showpos", "<ios>", cxx98},
-#line 550 "../../src/gcc/cp/std-name-hint.gperf"
+#line 550 "std-name-hint.gperf"
{"as_const", "<utility>", cxx17},
-#line 308 "../../src/gcc/cp/std-name-hint.gperf"
+#line 308 "std-name-hint.gperf"
{"bad_weak_ptr", "<memory>", cxx11},
-#line 168 "../../src/gcc/cp/std-name-hint.gperf"
+#line 168 "std-name-hint.gperf"
{"basic_format_context", "<format>", cxx20},
-#line 434 "../../src/gcc/cp/std-name-hint.gperf"
+#line 434 "std-name-hint.gperf"
{"basic_stringstream", "<sstream>", cxx98},
-#line 539 "../../src/gcc/cp/std-name-hint.gperf"
+#line 539 "std-name-hint.gperf"
{"type_index", "<typeindex>", cxx11},
-#line 169 "../../src/gcc/cp/std-name-hint.gperf"
+#line 169 "std-name-hint.gperf"
{"basic_format_parse_context", "<format>", cxx20},
-#line 160 "../../src/gcc/cp/std-name-hint.gperf"
+#line 160 "std-name-hint.gperf"
{"make_exception_ptr", "<exception>", cxx11},
-#line 468 "../../src/gcc/cp/std-name-hint.gperf"
+#line 468 "std-name-hint.gperf"
{"basic_streambuf", "<streambuf>", cxx98},
-#line 167 "../../src/gcc/cp/std-name-hint.gperf"
+#line 167 "std-name-hint.gperf"
{"basic_format_args", "<format>", cxx20},
-#line 588 "../../src/gcc/cp/std-name-hint.gperf"
+#line 588 "std-name-hint.gperf"
{"variant_size", "<variant>", cxx17},
-#line 407 "../../src/gcc/cp/std-name-hint.gperf"
+#line 407 "std-name-hint.gperf"
{"multiset", "<set>", cxx98},
-#line 133 "../../src/gcc/cp/std-name-hint.gperf"
+#line 133 "std-name-hint.gperf"
{"predicate", "<concepts>", cxx20},
-#line 397 "../../src/gcc/cp/std-name-hint.gperf"
+#line 397 "std-name-hint.gperf"
{"queue", "<queue>", cxx98},
-#line 353 "../../src/gcc/cp/std-name-hint.gperf"
+#line 353 "std-name-hint.gperf"
{"recursive_timed_mutex", "<mutex>", cxx11},
-#line 399 "../../src/gcc/cp/std-name-hint.gperf"
+#line 399 "std-name-hint.gperf"
{"ranges::enable_borrowed_range", "<ranges>", cxx20},
-#line 533 "../../src/gcc/cp/std-name-hint.gperf"
+#line 533 "std-name-hint.gperf"
{"remove_cvref", "<type_traits>", cxx20},
-#line 206 "../../src/gcc/cp/std-name-hint.gperf"
+#line 206 "std-name-hint.gperf"
{"function", "<functional>", cxx11},
-#line 532 "../../src/gcc/cp/std-name-hint.gperf"
+#line 532 "std-name-hint.gperf"
{"negation_v", "<type_traits>", cxx17},
-#line 534 "../../src/gcc/cp/std-name-hint.gperf"
+#line 534 "std-name-hint.gperf"
{"remove_cvref_t", "<type_traits>", cxx20},
-#line 289 "../../src/gcc/cp/std-name-hint.gperf"
+#line 289 "std-name-hint.gperf"
{"ostream_iterator", "<iterator>", cxx98},
-#line 587 "../../src/gcc/cp/std-name-hint.gperf"
+#line 587 "std-name-hint.gperf"
{"variant_npos", "<variant>", cxx17},
-#line 244 "../../src/gcc/cp/std-name-hint.gperf"
+#line 244 "std-name-hint.gperf"
{"left", "<ios>", cxx98},
-#line 200 "../../src/gcc/cp/std-name-hint.gperf"
+#line 200 "std-name-hint.gperf"
{"fstream", "<fstream>", cxx98},
-#line 590 "../../src/gcc/cp/std-name-hint.gperf"
+#line 590 "std-name-hint.gperf"
{"visit", "<variant>", cxx17},
-#line 208 "../../src/gcc/cp/std-name-hint.gperf"
+#line 208 "std-name-hint.gperf"
{"invoke", "<functional>", cxx17},
-#line 137 "../../src/gcc/cp/std-name-hint.gperf"
+#line 137 "std-name-hint.gperf"
{"ranges::swap", "<concepts>", cxx20},
-#line 283 "../../src/gcc/cp/std-name-hint.gperf"
+#line 283 "std-name-hint.gperf"
{"inserter", "<iterator>", cxx98},
-#line 362 "../../src/gcc/cp/std-name-hint.gperf"
+#line 362 "std-name-hint.gperf"
{"launder", "<new>", cxx17},
-#line 228 "../../src/gcc/cp/std-name-hint.gperf"
+#line 228 "std-name-hint.gperf"
{"put_time", "<iomanip>", cxx11},
-#line 237 "../../src/gcc/cp/std-name-hint.gperf"
+#line 237 "std-name-hint.gperf"
{"boolalpha", "<ios>", cxx98},
-#line 361 "../../src/gcc/cp/std-name-hint.gperf"
+#line 361 "std-name-hint.gperf"
{"hardware_destructive_interference_size", "<new>", cxx17},
-#line 199 "../../src/gcc/cp/std-name-hint.gperf"
+#line 199 "std-name-hint.gperf"
{"basic_ofstream", "<fstream>", cxx98},
-#line 324 "../../src/gcc/cp/std-name-hint.gperf"
+#line 324 "std-name-hint.gperf"
{"pointer_traits", "<memory>", cxx11},
-#line 131 "../../src/gcc/cp/std-name-hint.gperf"
+#line 131 "std-name-hint.gperf"
{"invocable", "<concepts>", cxx20},
-#line 426 "../../src/gcc/cp/std-name-hint.gperf"
+#line 426 "std-name-hint.gperf"
{"spanstream", "<spanstream>", cxx23},
-#line 182 "../../src/gcc/cp/std-name-hint.gperf"
+#line 182 "std-name-hint.gperf"
{"make_format_args", "<format>", cxx20},
-#line 121 "../../src/gcc/cp/std-name-hint.gperf"
+#line 121 "std-name-hint.gperf"
{"move_constructible", "<concepts>", cxx20},
-#line 114 "../../src/gcc/cp/std-name-hint.gperf"
+#line 114 "std-name-hint.gperf"
{"floating_point", "<concepts>", cxx20},
-#line 258 "../../src/gcc/cp/std-name-hint.gperf"
+#line 258 "std-name-hint.gperf"
{"skipws", "<ios>", cxx98},
-#line 241 "../../src/gcc/cp/std-name-hint.gperf"
+#line 241 "std-name-hint.gperf"
{"hex", "<ios>", cxx98},
-#line 568 "../../src/gcc/cp/std-name-hint.gperf"
+#line 568 "std-name-hint.gperf"
{"index_sequence_for", "<utility>", cxx14},
-#line 567 "../../src/gcc/cp/std-name-hint.gperf"
+#line 567 "std-name-hint.gperf"
{"index_sequence", "<utility>", cxx14},
-#line 350 "../../src/gcc/cp/std-name-hint.gperf"
+#line 350 "std-name-hint.gperf"
{"mutex", "<mutex>", cxx11},
-#line 284 "../../src/gcc/cp/std-name-hint.gperf"
+#line 284 "std-name-hint.gperf"
{"istream_iterator", "<iterator>", cxx98},
-#line 334 "../../src/gcc/cp/std-name-hint.gperf"
+#line 334 "std-name-hint.gperf"
{"weak_ptr", "<memory>", cxx11},
-#line 173 "../../src/gcc/cp/std-name-hint.gperf"
+#line 173 "std-name-hint.gperf"
{"format_context", "<format>", cxx20},
-#line 451 "../../src/gcc/cp/std-name-hint.gperf"
+#line 451 "std-name-hint.gperf"
{"logic_error", "<stdexcept>", cxx98},
-#line 372 "../../src/gcc/cp/std-name-hint.gperf"
+#line 372 "std-name-hint.gperf"
{"numbers::ln2_v", "<numbers>", cxx20},
-#line 371 "../../src/gcc/cp/std-name-hint.gperf"
+#line 371 "std-name-hint.gperf"
{"numbers::ln10_v", "<numbers>", cxx20},
-#line 368 "../../src/gcc/cp/std-name-hint.gperf"
+#line 368 "std-name-hint.gperf"
{"numbers::inv_pi_v", "<numbers>", cxx20},
-#line 235 "../../src/gcc/cp/std-name-hint.gperf"
+#line 235 "std-name-hint.gperf"
{"setw", "<iomanip>", cxx98},
-#line 369 "../../src/gcc/cp/std-name-hint.gperf"
+#line 369 "std-name-hint.gperf"
{"numbers::inv_sqrt3_v", "<numbers>", cxx20},
-#line 370 "../../src/gcc/cp/std-name-hint.gperf"
+#line 370 "std-name-hint.gperf"
{"numbers::inv_sqrtpi_v", "<numbers>", cxx20},
-#line 230 "../../src/gcc/cp/std-name-hint.gperf"
+#line 230 "std-name-hint.gperf"
{"resetiosflags", "<iomanip>", cxx98},
-#line 303 "../../src/gcc/cp/std-name-hint.gperf"
+#line 303 "std-name-hint.gperf"
{"allocator", "<memory>", cxx98},
-#line 135 "../../src/gcc/cp/std-name-hint.gperf"
+#line 135 "std-name-hint.gperf"
{"equivalence_relation", "<concepts>", cxx20},
-#line 272 "../../src/gcc/cp/std-name-hint.gperf"
+#line 272 "std-name-hint.gperf"
{"ws", "<istream>", cxx98},
-#line 44 "../../src/gcc/cp/std-name-hint.gperf"
+#line 44 "std-name-hint.gperf"
{"any_cast", "<any>", cxx17},
-#line 198 "../../src/gcc/cp/std-name-hint.gperf"
+#line 198 "std-name-hint.gperf"
{"basic_ifstream", "<fstream>", cxx98},
-#line 175 "../../src/gcc/cp/std-name-hint.gperf"
+#line 175 "std-name-hint.gperf"
{"format_parse_context", "<format>", cxx20},
-#line 341 "../../src/gcc/cp/std-name-hint.gperf"
+#line 341 "std-name-hint.gperf"
{"pmr::polymorphic_allocator", "<memory_resource>", cxx17},
-#line 419 "../../src/gcc/cp/std-name-hint.gperf"
+#line 419 "std-name-hint.gperf"
{"basic_ospanstream", "<spanstream>", cxx23},
-#line 572 "../../src/gcc/cp/std-name-hint.gperf"
+#line 572 "std-name-hint.gperf"
{"make_pair", "<utility>", cxx98},
-#line 172 "../../src/gcc/cp/std-name-hint.gperf"
+#line 172 "std-name-hint.gperf"
{"format_args", "<format>", cxx20},
-#line 475 "../../src/gcc/cp/std-name-hint.gperf"
+#line 475 "std-name-hint.gperf"
{"stof", "<string>", cxx11},
-#line 339 "../../src/gcc/cp/std-name-hint.gperf"
+#line 339 "std-name-hint.gperf"
{"pmr::monotonic_buffer_resource", "<memory_resource>", cxx17},
-#line 342 "../../src/gcc/cp/std-name-hint.gperf"
+#line 342 "std-name-hint.gperf"
{"pmr::pool_options", "<memory_resource>", cxx17},
-#line 256 "../../src/gcc/cp/std-name-hint.gperf"
+#line 256 "std-name-hint.gperf"
{"showpoint", "<ios>", cxx98},
-#line 446 "../../src/gcc/cp/std-name-hint.gperf"
+#line 446 "std-name-hint.gperf"
{"stacktrace", "<stacktrace>", cxx23},
-#line 589 "../../src/gcc/cp/std-name-hint.gperf"
+#line 589 "std-name-hint.gperf"
{"variant_size_v", "<variant>", cxx17},
-#line 212 "../../src/gcc/cp/std-name-hint.gperf"
+#line 212 "std-name-hint.gperf"
{"reference_wrapper", "<functional>", cxx11},
-#line 262 "../../src/gcc/cp/std-name-hint.gperf"
+#line 262 "std-name-hint.gperf"
{"cerr", "<iostream>", cxx98},
-#line 300 "../../src/gcc/cp/std-name-hint.gperf"
+#line 300 "std-name-hint.gperf"
{"align", "<memory>", cxx11},
-#line 438 "../../src/gcc/cp/std-name-hint.gperf"
+#line 438 "std-name-hint.gperf"
{"stringbuf", "<sstream>", cxx98},
-#line 469 "../../src/gcc/cp/std-name-hint.gperf"
+#line 469 "std-name-hint.gperf"
{"streambuf", "<streambuf>", cxx98},
-#line 306 "../../src/gcc/cp/std-name-hint.gperf"
+#line 306 "std-name-hint.gperf"
{"allocator_traits", "<memory>", cxx11},
-#line 183 "../../src/gcc/cp/std-name-hint.gperf"
+#line 183 "std-name-hint.gperf"
{"make_wformat_args", "<format>", cxx20},
-#line 583 "../../src/gcc/cp/std-name-hint.gperf"
+#line 583 "std-name-hint.gperf"
{"monostate", "<variant>", cxx17},
-#line 387 "../../src/gcc/cp/std-name-hint.gperf"
+#line 387 "std-name-hint.gperf"
{"flush", "<ostream>", cxx98},
-#line 527 "../../src/gcc/cp/std-name-hint.gperf"
+#line 527 "std-name-hint.gperf"
{"enable_if", "<type_traits>", cxx11},
-#line 352 "../../src/gcc/cp/std-name-hint.gperf"
+#line 352 "std-name-hint.gperf"
{"recursive_mutex", "<mutex>", cxx11},
-#line 418 "../../src/gcc/cp/std-name-hint.gperf"
+#line 418 "std-name-hint.gperf"
{"basic_ispanstream", "<spanstream>", cxx23},
-#line 178 "../../src/gcc/cp/std-name-hint.gperf"
+#line 178 "std-name-hint.gperf"
{"format_to_n", "<format>", cxx20},
-#line 338 "../../src/gcc/cp/std-name-hint.gperf"
+#line 338 "std-name-hint.gperf"
{"pmr::memory_resource", "<memory_resource>", cxx17},
-#line 124 "../../src/gcc/cp/std-name-hint.gperf"
+#line 124 "std-name-hint.gperf"
{"equality_comparable_with", "<concepts>", cxx20},
-#line 493 "../../src/gcc/cp/std-name-hint.gperf"
+#line 493 "std-name-hint.gperf"
{"errc", "<system_error>", cxx11},
-#line 344 "../../src/gcc/cp/std-name-hint.gperf"
+#line 344 "std-name-hint.gperf"
{"pmr::synchronized_pool_resource", "<memory_resource>", cxx17},
-#line 385 "../../src/gcc/cp/std-name-hint.gperf"
+#line 385 "std-name-hint.gperf"
{"endl", "<ostream>", cxx98},
-#line 495 "../../src/gcc/cp/std-name-hint.gperf"
+#line 495 "std-name-hint.gperf"
{"error_code", "<system_error>", cxx11},
-#line 528 "../../src/gcc/cp/std-name-hint.gperf"
+#line 528 "std-name-hint.gperf"
{"enable_if_t", "<type_traits>", cxx14},
-#line 390 "../../src/gcc/cp/std-name-hint.gperf"
+#line 390 "std-name-hint.gperf"
{"ostream", "<ostream>", cxx98},
-#line 374 "../../src/gcc/cp/std-name-hint.gperf"
+#line 374 "std-name-hint.gperf"
{"numbers::log2e_v", "<numbers>", cxx20},
-#line 373 "../../src/gcc/cp/std-name-hint.gperf"
+#line 373 "std-name-hint.gperf"
{"numbers::log10e_v", "<numbers>", cxx20},
-#line 364 "../../src/gcc/cp/std-name-hint.gperf"
+#line 364 "std-name-hint.gperf"
{"nothrow_t", "<new>", cxx98},
-#line 512 "../../src/gcc/cp/std-name-hint.gperf"
+#line 512 "std-name-hint.gperf"
{"ignore", "<tuple>", cxx11},
-#line 360 "../../src/gcc/cp/std-name-hint.gperf"
+#line 360 "std-name-hint.gperf"
{"hardware_constructive_interference_size", "<new>", cxx17},
-#line 396 "../../src/gcc/cp/std-name-hint.gperf"
+#line 396 "std-name-hint.gperf"
{"priority_queue", "<queue>", cxx98},
-#line 424 "../../src/gcc/cp/std-name-hint.gperf"
+#line 424 "std-name-hint.gperf"
{"ospanstream", "<spanstream>", cxx23},
-#line 316 "../../src/gcc/cp/std-name-hint.gperf"
+#line 316 "std-name-hint.gperf"
{"enable_shared_from_this", "<memory>", cxx11},
-#line 265 "../../src/gcc/cp/std-name-hint.gperf"
+#line 265 "std-name-hint.gperf"
{"cout", "<iostream>", cxx98},
-#line 552 "../../src/gcc/cp/std-name-hint.gperf"
+#line 552 "std-name-hint.gperf"
{"cmp_greater", "<utility>", cxx20},
-#line 490 "../../src/gcc/cp/std-name-hint.gperf"
+#line 490 "std-name-hint.gperf"
{"basic_string_view", "<string_view>", cxx17},
-#line 249 "../../src/gcc/cp/std-name-hint.gperf"
+#line 249 "std-name-hint.gperf"
{"noskipws", "<ios>", cxx98},
-#line 177 "../../src/gcc/cp/std-name-hint.gperf"
+#line 177 "std-name-hint.gperf"
{"format_to", "<format>", cxx20},
-#line 502 "../../src/gcc/cp/std-name-hint.gperf"
+#line 502 "std-name-hint.gperf"
{"make_error_code", "<system_error>", cxx11},
-#line 174 "../../src/gcc/cp/std-name-hint.gperf"
+#line 174 "std-name-hint.gperf"
{"format_error", "<format>", cxx20},
-#line 347 "../../src/gcc/cp/std-name-hint.gperf"
+#line 347 "std-name-hint.gperf"
{"call_once", "<mutex>", cxx11},
-#line 377 "../../src/gcc/cp/std-name-hint.gperf"
+#line 377 "std-name-hint.gperf"
{"numbers::sqrt2_v", "<numbers>", cxx20},
-#line 378 "../../src/gcc/cp/std-name-hint.gperf"
+#line 378 "std-name-hint.gperf"
{"numbers::sqrt3_v", "<numbers>", cxx20},
-#line 242 "../../src/gcc/cp/std-name-hint.gperf"
+#line 242 "std-name-hint.gperf"
{"hexfloat", "<ios>", cxx11},
-#line 326 "../../src/gcc/cp/std-name-hint.gperf"
+#line 326 "std-name-hint.gperf"
{"shared_ptr", "<memory>", cxx11},
-#line 569 "../../src/gcc/cp/std-name-hint.gperf"
+#line 569 "std-name-hint.gperf"
{"integer_sequence", "<utility>", cxx14},
-#line 271 "../../src/gcc/cp/std-name-hint.gperf"
+#line 271 "std-name-hint.gperf"
{"istream", "<istream>", cxx98},
-#line 376 "../../src/gcc/cp/std-name-hint.gperf"
+#line 376 "std-name-hint.gperf"
{"numbers::pi_v", "<numbers>", cxx20},
-#line 259 "../../src/gcc/cp/std-name-hint.gperf"
+#line 259 "std-name-hint.gperf"
{"unitbuf", "<ios>", cxx98},
-#line 294 "../../src/gcc/cp/std-name-hint.gperf"
+#line 294 "std-name-hint.gperf"
{"list", "<list>", cxx98},
-#line 554 "../../src/gcc/cp/std-name-hint.gperf"
+#line 554 "std-name-hint.gperf"
{"cmp_less", "<utility>", cxx20},
-#line 422 "../../src/gcc/cp/std-name-hint.gperf"
+#line 422 "std-name-hint.gperf"
{"ispanstream", "<spanstream>", cxx23},
-#line 423 "../../src/gcc/cp/std-name-hint.gperf"
+#line 423 "std-name-hint.gperf"
{"ispanstream", "<spanstream>", cxx23},
-#line 470 "../../src/gcc/cp/std-name-hint.gperf"
+#line 470 "std-name-hint.gperf"
{"wstreambuf", "<streambuf>", cxx98},
-#line 432 "../../src/gcc/cp/std-name-hint.gperf"
+#line 432 "std-name-hint.gperf"
{"basic_ostringstream", "<sstream>", cxx98},
-#line 503 "../../src/gcc/cp/std-name-hint.gperf"
+#line 503 "std-name-hint.gperf"
{"make_error_condition", "<system_error>", cxx11},
-#line 570 "../../src/gcc/cp/std-name-hint.gperf"
+#line 570 "std-name-hint.gperf"
{"make_index_sequence", "<utility>", cxx14},
-#line 405 "../../src/gcc/cp/std-name-hint.gperf"
+#line 405 "std-name-hint.gperf"
{"counting_semaphore", "<semaphore>", cxx20},
-#line 355 "../../src/gcc/cp/std-name-hint.gperf"
+#line 355 "std-name-hint.gperf"
{"timed_mutex", "<mutex>", cxx11},
-#line 297 "../../src/gcc/cp/std-name-hint.gperf"
+#line 297 "std-name-hint.gperf"
{"multimap", "<map>", cxx98},
-#line 227 "../../src/gcc/cp/std-name-hint.gperf"
+#line 227 "std-name-hint.gperf"
{"put_money", "<iomanip>", cxx11},
-#line 309 "../../src/gcc/cp/std-name-hint.gperf"
+#line 309 "std-name-hint.gperf"
{"const_pointer_cast", "<memory>", cxx11},
-#line 45 "../../src/gcc/cp/std-name-hint.gperf"
+#line 45 "std-name-hint.gperf"
{"make_any", "<any>", cxx17},
-#line 465 "../../src/gcc/cp/std-name-hint.gperf"
+#line 465 "std-name-hint.gperf"
{"stop_source", "<stop_token>", cxx20},
-#line 548 "../../src/gcc/cp/std-name-hint.gperf"
+#line 548 "std-name-hint.gperf"
{"unordered_set", "<unordered_set>", cxx11},
-#line 582 "../../src/gcc/cp/std-name-hint.gperf"
+#line 582 "std-name-hint.gperf"
{"holds_alternative", "<variant>", cxx17},
-#line 514 "../../src/gcc/cp/std-name-hint.gperf"
+#line 514 "std-name-hint.gperf"
{"make_tuple", "<tuple>", cxx11},
-#line 47 "../../src/gcc/cp/std-name-hint.gperf"
+#line 47 "std-name-hint.gperf"
{"array", "<array>", cxx11},
-#line 517 "../../src/gcc/cp/std-name-hint.gperf"
+#line 517 "std-name-hint.gperf"
{"tuple_cat", "<tuple>", cxx11},
-#line 323 "../../src/gcc/cp/std-name-hint.gperf"
+#line 323 "std-name-hint.gperf"
{"owner_less", "<memory>", cxx11},
-#line 158 "../../src/gcc/cp/std-name-hint.gperf"
+#line 158 "std-name-hint.gperf"
{"exception", "<exception>", cxx98},
-#line 159 "../../src/gcc/cp/std-name-hint.gperf"
+#line 159 "std-name-hint.gperf"
{"exception_ptr", "<exception>", cxx11},
-#line 207 "../../src/gcc/cp/std-name-hint.gperf"
+#line 207 "std-name-hint.gperf"
{"hash", "<functional>", cxx11},
-#line 521 "../../src/gcc/cp/std-name-hint.gperf"
+#line 521 "std-name-hint.gperf"
{"tuple_size_v", "<tuple>", cxx17},
-#line 431 "../../src/gcc/cp/std-name-hint.gperf"
+#line 431 "std-name-hint.gperf"
{"basic_istringstream", "<sstream>", cxx98},
-#line 153 "../../src/gcc/cp/std-name-hint.gperf"
+#line 153 "std-name-hint.gperf"
{"uintptr_t", "<cstdint>", cxx11},
-#line 476 "../../src/gcc/cp/std-name-hint.gperf"
+#line 476 "std-name-hint.gperf"
{"stoi", "<string>", cxx11},
-#line 466 "../../src/gcc/cp/std-name-hint.gperf"
+#line 466 "std-name-hint.gperf"
{"stop_token", "<stop_token>", cxx20},
-#line 151 "../../src/gcc/cp/std-name-hint.gperf"
+#line 151 "std-name-hint.gperf"
{"uint_least8_t", "<cstdint>", cxx11},
-#line 380 "../../src/gcc/cp/std-name-hint.gperf"
+#line 380 "std-name-hint.gperf"
{"make_optional", "<optional>", cxx17},
-#line 345 "../../src/gcc/cp/std-name-hint.gperf"
+#line 345 "std-name-hint.gperf"
{"pmr::unsynchronized_pool_resource", "<memory_resource>", cxx17},
-#line 48 "../../src/gcc/cp/std-name-hint.gperf"
+#line 48 "std-name-hint.gperf"
{"to_array", "<array>", cxx20},
-#line 104 "../../src/gcc/cp/std-name-hint.gperf"
+#line 104 "std-name-hint.gperf"
{"complex_literals", "<complex>", cxx14},
-#line 411 "../../src/gcc/cp/std-name-hint.gperf"
+#line 411 "std-name-hint.gperf"
{"shared_mutex", "<shared_mutex>", cxx17},
-#line 375 "../../src/gcc/cp/std-name-hint.gperf"
+#line 375 "std-name-hint.gperf"
{"numbers::phi_v", "<numbers>", cxx20},
-#line 499 "../../src/gcc/cp/std-name-hint.gperf"
+#line 499 "std-name-hint.gperf"
{"is_error_code_enum_v", "<system_error>", cxx17},
-#line 155 "../../src/gcc/cp/std-name-hint.gperf"
+#line 155 "std-name-hint.gperf"
{"deque", "<deque>", cxx98},
-#line 412 "../../src/gcc/cp/std-name-hint.gperf"
+#line 412 "std-name-hint.gperf"
{"shared_timed_mutex", "<shared_mutex>", cxx14},
-#line 290 "../../src/gcc/cp/std-name-hint.gperf"
+#line 290 "std-name-hint.gperf"
{"ostreambuf_iterator", "<iterator>", cxx98},
-#line 501 "../../src/gcc/cp/std-name-hint.gperf"
+#line 501 "std-name-hint.gperf"
{"is_error_condition_enum_v", "<system_error>", cxx17},
-#line 148 "../../src/gcc/cp/std-name-hint.gperf"
+#line 148 "std-name-hint.gperf"
{"uint_least16_t", "<cstdint>", cxx11},
-#line 305 "../../src/gcc/cp/std-name-hint.gperf"
+#line 305 "std-name-hint.gperf"
{"allocator_arg_t", "<memory>", cxx11},
-#line 366 "../../src/gcc/cp/std-name-hint.gperf"
+#line 366 "std-name-hint.gperf"
{"numbers::e_v", "<numbers>", cxx20},
-#line 209 "../../src/gcc/cp/std-name-hint.gperf"
+#line 209 "std-name-hint.gperf"
{"invoke_r", "<functional>", cxx23},
-#line 441 "../../src/gcc/cp/std-name-hint.gperf"
+#line 441 "std-name-hint.gperf"
{"wostringstream", "<sstream>", cxx98},
-#line 122 "../../src/gcc/cp/std-name-hint.gperf"
+#line 122 "std-name-hint.gperf"
{"copy_constructible", "<concepts>", cxx20},
-#line 149 "../../src/gcc/cp/std-name-hint.gperf"
+#line 149 "std-name-hint.gperf"
{"uint_least32_t", "<cstdint>", cxx11},
-#line 108 "../../src/gcc/cp/std-name-hint.gperf"
+#line 108 "std-name-hint.gperf"
{"convertible_to", "<concepts>", cxx20},
-#line 234 "../../src/gcc/cp/std-name-hint.gperf"
+#line 234 "std-name-hint.gperf"
{"setprecision", "<iomanip>", cxx98},
-#line 498 "../../src/gcc/cp/std-name-hint.gperf"
+#line 498 "std-name-hint.gperf"
{"is_error_code_enum", "<system_error>", cxx11},
-#line 453 "../../src/gcc/cp/std-name-hint.gperf"
+#line 453 "std-name-hint.gperf"
{"overflow_error", "<stdexcept>", cxx98},
-#line 414 "../../src/gcc/cp/std-name-hint.gperf"
+#line 414 "std-name-hint.gperf"
{"source_location", "<source_location>", cxx20},
-#line 500 "../../src/gcc/cp/std-name-hint.gperf"
+#line 500 "std-name-hint.gperf"
{"is_error_condition_enum", "<system_error>", cxx11},
-#line 400 "../../src/gcc/cp/std-name-hint.gperf"
+#line 400 "std-name-hint.gperf"
{"ranges::enable_view", "<ranges>", cxx20},
-#line 218 "../../src/gcc/cp/std-name-hint.gperf"
+#line 218 "std-name-hint.gperf"
{"async", "<future>", cxx11},
-#line 103 "../../src/gcc/cp/std-name-hint.gperf"
+#line 103 "std-name-hint.gperf"
{"complex", "<complex>", cxx98},
-#line 150 "../../src/gcc/cp/std-name-hint.gperf"
+#line 150 "std-name-hint.gperf"
{"uint_least64_t", "<cstdint>", cxx11},
-#line 232 "../../src/gcc/cp/std-name-hint.gperf"
+#line 232 "std-name-hint.gperf"
{"setfill", "<iomanip>", cxx98},
-#line 79 "../../src/gcc/cp/std-name-hint.gperf"
+#line 79 "std-name-hint.gperf"
{"chrono::parse", "<chrono>", cxx20},
-#line 285 "../../src/gcc/cp/std-name-hint.gperf"
+#line 285 "std-name-hint.gperf"
{"istreambuf_iterator", "<iterator>", cxx98},
-#line 473 "../../src/gcc/cp/std-name-hint.gperf"
+#line 473 "std-name-hint.gperf"
{"char_traits", "<string>", cxx98},
-#line 263 "../../src/gcc/cp/std-name-hint.gperf"
+#line 263 "std-name-hint.gperf"
{"cin", "<iostream>", cxx98},
-#line 61 "../../src/gcc/cp/std-name-hint.gperf"
+#line 61 "std-name-hint.gperf"
{"chrono::duration_cast", "<chrono>", cxx11},
-#line 152 "../../src/gcc/cp/std-name-hint.gperf"
+#line 152 "std-name-hint.gperf"
{"uintmax_t", "<cstdint>", cxx11},
-#line 43 "../../src/gcc/cp/std-name-hint.gperf"
+#line 43 "std-name-hint.gperf"
{"any", "<any>", cxx17},
-#line 389 "../../src/gcc/cp/std-name-hint.gperf"
+#line 389 "std-name-hint.gperf"
{"noemit_on_flush", "<ostream>", cxx20},
-#line 66 "../../src/gcc/cp/std-name-hint.gperf"
+#line 66 "std-name-hint.gperf"
{"chrono::get_tzdb_list", "<chrono>", cxx20},
-#line 93 "../../src/gcc/cp/std-name-hint.gperf"
+#line 93 "std-name-hint.gperf"
{"chrono::weeks", "<chrono>", cxx20},
-#line 65 "../../src/gcc/cp/std-name-hint.gperf"
+#line 65 "std-name-hint.gperf"
{"chrono::get_tzdb", "<chrono>", cxx20},
-#line 302 "../../src/gcc/cp/std-name-hint.gperf"
+#line 302 "std-name-hint.gperf"
{"allocate_shared_for_overwrite", "<memory>", cxx20},
-#line 547 "../../src/gcc/cp/std-name-hint.gperf"
+#line 547 "std-name-hint.gperf"
{"unordered_multiset", "<unordered_set>", cxx11},
-#line 194 "../../src/gcc/cp/std-name-hint.gperf"
+#line 194 "std-name-hint.gperf"
{"forward_list", "<forward_list>", cxx11},
-#line 496 "../../src/gcc/cp/std-name-hint.gperf"
+#line 496 "std-name-hint.gperf"
{"error_condition", "<system_error>", cxx11},
-#line 542 "../../src/gcc/cp/std-name-hint.gperf"
+#line 542 "std-name-hint.gperf"
{"bad_typeid", "<typeinfo>", cxx98},
-#line 60 "../../src/gcc/cp/std-name-hint.gperf"
+#line 60 "std-name-hint.gperf"
{"chrono::duration", "<chrono>", cxx11},
-#line 510 "../../src/gcc/cp/std-name-hint.gperf"
+#line 510 "std-name-hint.gperf"
{"apply", "<tuple>", cxx17},
-#line 95 "../../src/gcc/cp/std-name-hint.gperf"
+#line 95 "std-name-hint.gperf"
{"chrono::zoned_time", "<chrono>", cxx20},
-#line 477 "../../src/gcc/cp/std-name-hint.gperf"
+#line 477 "std-name-hint.gperf"
{"stol", "<string>", cxx11},
-#line 479 "../../src/gcc/cp/std-name-hint.gperf"
+#line 479 "std-name-hint.gperf"
{"stoll", "<string>", cxx11},
-#line 480 "../../src/gcc/cp/std-name-hint.gperf"
+#line 480 "std-name-hint.gperf"
{"stoul", "<string>", cxx11},
-#line 481 "../../src/gcc/cp/std-name-hint.gperf"
+#line 481 "std-name-hint.gperf"
{"stoull", "<string>", cxx11},
-#line 220 "../../src/gcc/cp/std-name-hint.gperf"
+#line 220 "std-name-hint.gperf"
{"packaged_task", "<future>", cxx11},
-#line 544 "../../src/gcc/cp/std-name-hint.gperf"
+#line 544 "std-name-hint.gperf"
{"unordered_map", "<unordered_map>", cxx11},
-#line 77 "../../src/gcc/cp/std-name-hint.gperf"
+#line 77 "std-name-hint.gperf"
{"chrono::months", "<chrono>", cxx20},
-#line 76 "../../src/gcc/cp/std-name-hint.gperf"
+#line 76 "std-name-hint.gperf"
{"chrono::minutes", "<chrono>", cxx11},
-#line 545 "../../src/gcc/cp/std-name-hint.gperf"
+#line 545 "std-name-hint.gperf"
{"unordered_multimap", "<unordered_map>", cxx11},
-#line 78 "../../src/gcc/cp/std-name-hint.gperf"
+#line 78 "std-name-hint.gperf"
{"chrono::nanoseconds", "<chrono>", cxx11},
-#line 286 "../../src/gcc/cp/std-name-hint.gperf"
+#line 286 "std-name-hint.gperf"
{"iterator_traits", "<iterator>", cxx98},
-#line 404 "../../src/gcc/cp/std-name-hint.gperf"
+#line 404 "std-name-hint.gperf"
{"binary_semaphore", "<semaphore>", cxx20},
-#line 281 "../../src/gcc/cp/std-name-hint.gperf"
+#line 281 "std-name-hint.gperf"
{"end", "<iterator>", cxx11},
-#line 429 "../../src/gcc/cp/std-name-hint.gperf"
+#line 429 "std-name-hint.gperf"
{"wspanbuf", "<spanstream>", cxx23},
-#line 252 "../../src/gcc/cp/std-name-hint.gperf"
+#line 252 "std-name-hint.gperf"
{"oct", "<ios>", cxx98},
-#line 245 "../../src/gcc/cp/std-name-hint.gperf"
+#line 245 "std-name-hint.gperf"
{"noboolalpha", "<ios>", cxx98},
-#line 450 "../../src/gcc/cp/std-name-hint.gperf"
+#line 450 "std-name-hint.gperf"
{"length_error", "<stdexcept>", cxx98},
-#line 560 "../../src/gcc/cp/std-name-hint.gperf"
+#line 560 "std-name-hint.gperf"
{"in_place", "<utility>", cxx17},
-#line 563 "../../src/gcc/cp/std-name-hint.gperf"
+#line 563 "std-name-hint.gperf"
{"in_place_t", "<utility>", cxx17},
-#line 384 "../../src/gcc/cp/std-name-hint.gperf"
+#line 384 "std-name-hint.gperf"
{"emit_on_flush", "<ostream>", cxx20},
-#line 440 "../../src/gcc/cp/std-name-hint.gperf"
+#line 440 "std-name-hint.gperf"
{"wistringstream", "<sstream>", cxx98},
-#line 327 "../../src/gcc/cp/std-name-hint.gperf"
+#line 327 "std-name-hint.gperf"
{"static_pointer_cast", "<memory>", cxx11},
-#line 260 "../../src/gcc/cp/std-name-hint.gperf"
+#line 260 "std-name-hint.gperf"
{"uppercase", "<ios>", cxx98},
-#line 277 "../../src/gcc/cp/std-name-hint.gperf"
+#line 277 "std-name-hint.gperf"
{"common_iterator", "<iterator>", cxx20},
-#line 117 "../../src/gcc/cp/std-name-hint.gperf"
+#line 117 "std-name-hint.gperf"
{"swappable_with", "<concepts>", cxx20},
-#line 359 "../../src/gcc/cp/std-name-hint.gperf"
+#line 359 "std-name-hint.gperf"
{"bad_alloc", "<new>", cxx98},
-#line 391 "../../src/gcc/cp/std-name-hint.gperf"
+#line 391 "std-name-hint.gperf"
{"wostream", "<ostream>", cxx98},
-#line 348 "../../src/gcc/cp/std-name-hint.gperf"
+#line 348 "std-name-hint.gperf"
{"lock", "<mutex>", cxx11},
-#line 504 "../../src/gcc/cp/std-name-hint.gperf"
+#line 504 "std-name-hint.gperf"
{"system_category", "<system_error>", cxx11},
-#line 128 "../../src/gcc/cp/std-name-hint.gperf"
+#line 128 "std-name-hint.gperf"
{"copyable", "<concepts>", cxx20},
-#line 139 "../../src/gcc/cp/std-name-hint.gperf"
+#line 139 "std-name-hint.gperf"
{"condition_variable", "<condition_variable>", cxx11},
-#line 240 "../../src/gcc/cp/std-name-hint.gperf"
+#line 240 "std-name-hint.gperf"
{"fixed", "<ios>", cxx98},
-#line 553 "../../src/gcc/cp/std-name-hint.gperf"
+#line 553 "std-name-hint.gperf"
{"cmp_greater_equal", "<utility>", cxx20},
-#line 508 "../../src/gcc/cp/std-name-hint.gperf"
+#line 508 "std-name-hint.gperf"
{"thread", "<thread>", cxx11},
-#line 439 "../../src/gcc/cp/std-name-hint.gperf"
+#line 439 "std-name-hint.gperf"
{"stringstream", "<sstream>", cxx98},
-#line 58 "../../src/gcc/cp/std-name-hint.gperf"
+#line 58 "std-name-hint.gperf"
{"chrono::clock_cast", "<chrono>", cxx20},
-#line 579 "../../src/gcc/cp/std-name-hint.gperf"
+#line 579 "std-name-hint.gperf"
{"unreachable", "<utility>", cxx23},
-#line 428 "../../src/gcc/cp/std-name-hint.gperf"
+#line 428 "std-name-hint.gperf"
{"wospanstream", "<spanstream>", cxx23},
-#line 330 "../../src/gcc/cp/std-name-hint.gperf"
+#line 330 "std-name-hint.gperf"
{"unique_ptr", "<memory>", cxx11},
-#line 562 "../../src/gcc/cp/std-name-hint.gperf"
+#line 562 "std-name-hint.gperf"
{"in_place_index_t", "<utility>", cxx17},
-#line 363 "../../src/gcc/cp/std-name-hint.gperf"
+#line 363 "std-name-hint.gperf"
{"nothrow", "<new>", cxx98},
-#line 64 "../../src/gcc/cp/std-name-hint.gperf"
+#line 64 "std-name-hint.gperf"
{"chrono::get_leap_second_info", "<chrono>", cxx20},
-#line 204 "../../src/gcc/cp/std-name-hint.gperf"
+#line 204 "std-name-hint.gperf"
{"bind", "<functional>", cxx11},
-#line 89 "../../src/gcc/cp/std-name-hint.gperf"
+#line 89 "std-name-hint.gperf"
{"chrono::time_zone", "<chrono>", cxx20},
-#line 120 "../../src/gcc/cp/std-name-hint.gperf"
+#line 120 "std-name-hint.gperf"
{"default_initializable", "<concepts>", cxx20},
-#line 145 "../../src/gcc/cp/std-name-hint.gperf"
+#line 145 "std-name-hint.gperf"
{"uint_fast32_t", "<cstdint>", cxx11},
-#line 87 "../../src/gcc/cp/std-name-hint.gperf"
+#line 87 "std-name-hint.gperf"
{"chrono::time_point", "<chrono>", cxx11},
-#line 444 "../../src/gcc/cp/std-name-hint.gperf"
+#line 444 "std-name-hint.gperf"
{"stack", "<stack>", cxx98},
-#line 215 "../../src/gcc/cp/std-name-hint.gperf"
+#line 215 "std-name-hint.gperf"
{"unwrap_reference", "<functional>", cxx20},
-#line 88 "../../src/gcc/cp/std-name-hint.gperf"
+#line 88 "std-name-hint.gperf"
{"chrono::time_point_cast", "<chrono>", cxx11},
-#line 223 "../../src/gcc/cp/std-name-hint.gperf"
+#line 223 "std-name-hint.gperf"
{"generator", "<generator>", cxx23},
-#line 216 "../../src/gcc/cp/std-name-hint.gperf"
+#line 216 "std-name-hint.gperf"
{"unwrap_reference_t", "<functional>", cxx20},
-#line 382 "../../src/gcc/cp/std-name-hint.gperf"
+#line 382 "std-name-hint.gperf"
{"optional", "<optional>", cxx17},
-#line 112 "../../src/gcc/cp/std-name-hint.gperf"
+#line 112 "std-name-hint.gperf"
{"signed_integral", "<concepts>", cxx20},
-#line 456 "../../src/gcc/cp/std-name-hint.gperf"
+#line 456 "std-name-hint.gperf"
{"underflow_error", "<stdexcept>", cxx98},
-#line 239 "../../src/gcc/cp/std-name-hint.gperf"
+#line 239 "std-name-hint.gperf"
{"defaultfloat", "<ios>", cxx11},
-#line 146 "../../src/gcc/cp/std-name-hint.gperf"
+#line 146 "std-name-hint.gperf"
{"uint_fast64_t", "<cstdint>", cxx11},
-#line 129 "../../src/gcc/cp/std-name-hint.gperf"
+#line 129 "std-name-hint.gperf"
{"semiregular", "<concepts>", cxx20},
-#line 111 "../../src/gcc/cp/std-name-hint.gperf"
+#line 111 "std-name-hint.gperf"
{"integral", "<concepts>", cxx20},
-#line 243 "../../src/gcc/cp/std-name-hint.gperf"
+#line 243 "std-name-hint.gperf"
{"internal", "<ios>", cxx98},
-#line 144 "../../src/gcc/cp/std-name-hint.gperf"
+#line 144 "std-name-hint.gperf"
{"uint_fast16_t", "<cstdint>", cxx11},
-#line 329 "../../src/gcc/cp/std-name-hint.gperf"
+#line 329 "std-name-hint.gperf"
{"uninitialized_construct_using_allocator", "<memory>", cxx20},
-#line 81 "../../src/gcc/cp/std-name-hint.gperf"
+#line 81 "std-name-hint.gperf"
{"chrono::remote_version", "<chrono>", cxx20},
-#line 458 "../../src/gcc/cp/std-name-hint.gperf"
+#line 458 "std-name-hint.gperf"
{"bfloat16_t", "<stdfloat>", cxx23},
-#line 576 "../../src/gcc/cp/std-name-hint.gperf"
+#line 576 "std-name-hint.gperf"
{"piecewise_construct", "<utility>", cxx11},
-#line 577 "../../src/gcc/cp/std-name-hint.gperf"
+#line 577 "std-name-hint.gperf"
{"piecewise_construct_t", "<utility>", cxx11},
-#line 278 "../../src/gcc/cp/std-name-hint.gperf"
+#line 278 "std-name-hint.gperf"
{"const_iterator", "<iterator>", cxx23},
-#line 484 "../../src/gcc/cp/std-name-hint.gperf"
+#line 484 "std-name-hint.gperf"
{"to_wstring", "<string>", cxx17},
-#line 356 "../../src/gcc/cp/std-name-hint.gperf"
+#line 356 "std-name-hint.gperf"
{"try_lock", "<mutex>", cxx11},
-#line 561 "../../src/gcc/cp/std-name-hint.gperf"
+#line 561 "std-name-hint.gperf"
{"in_place_index", "<utility>", cxx17},
-#line 51 "../../src/gcc/cp/std-name-hint.gperf"
+#line 51 "std-name-hint.gperf"
{"atomic_ref", "<atomic>", cxx20},
-#line 113 "../../src/gcc/cp/std-name-hint.gperf"
+#line 113 "std-name-hint.gperf"
{"unsigned_integral", "<concepts>", cxx20},
-#line 94 "../../src/gcc/cp/std-name-hint.gperf"
+#line 94 "std-name-hint.gperf"
{"chrono::years", "<chrono>", cxx20},
-#line 229 "../../src/gcc/cp/std-name-hint.gperf"
+#line 229 "std-name-hint.gperf"
{"quoted", "<iomanip>", cxx14},
-#line 115 "../../src/gcc/cp/std-name-hint.gperf"
+#line 115 "std-name-hint.gperf"
{"assignable_from", "<concepts>", cxx20},
-#line 53 "../../src/gcc/cp/std-name-hint.gperf"
+#line 53 "std-name-hint.gperf"
{"atomic_uintmax_t", "<atomic>", cxx20},
-#line 162 "../../src/gcc/cp/std-name-hint.gperf"
+#line 162 "std-name-hint.gperf"
{"uncaught_exceptions", "<exception>", cxx17},
-#line 331 "../../src/gcc/cp/std-name-hint.gperf"
+#line 331 "std-name-hint.gperf"
{"uses_allocator", "<memory>", cxx11},
-#line 472 "../../src/gcc/cp/std-name-hint.gperf"
+#line 472 "std-name-hint.gperf"
{"basic_string", "<string>", cxx98},
-#line 311 "../../src/gcc/cp/std-name-hint.gperf"
+#line 311 "std-name-hint.gperf"
{"default_delete", "<memory>", cxx11},
-#line 164 "../../src/gcc/cp/std-name-hint.gperf"
+#line 164 "std-name-hint.gperf"
{"expected", "<expected>", cxx23},
-#line 313 "../../src/gcc/cp/std-name-hint.gperf"
+#line 313 "std-name-hint.gperf"
{"destroy_at", "<memory>", cxx20},
-#line 536 "../../src/gcc/cp/std-name-hint.gperf"
+#line 536 "std-name-hint.gperf"
{"type_identity_t", "<type_traits>", cxx20},
-#line 63 "../../src/gcc/cp/std-name-hint.gperf"
+#line 63 "std-name-hint.gperf"
{"chrono::from_stream", "<chrono>", cxx20},
-#line 427 "../../src/gcc/cp/std-name-hint.gperf"
+#line 427 "std-name-hint.gperf"
{"wispanstream", "<spanstream>", cxx23},
-#line 52 "../../src/gcc/cp/std-name-hint.gperf"
+#line 52 "std-name-hint.gperf"
{"atomic_signed_lock_free", "<atomic>", cxx11},
-#line 266 "../../src/gcc/cp/std-name-hint.gperf"
+#line 266 "std-name-hint.gperf"
{"wcerr", "<iostream>", cxx98},
-#line 511 "../../src/gcc/cp/std-name-hint.gperf"
+#line 511 "std-name-hint.gperf"
{"forward_as_tuple", "<tuple>", cxx11},
-#line 187 "../../src/gcc/cp/std-name-hint.gperf"
+#line 187 "std-name-hint.gperf"
{"vformat", "<format>", cxx20},
-#line 332 "../../src/gcc/cp/std-name-hint.gperf"
+#line 332 "std-name-hint.gperf"
{"uses_allocator_construction_args", "<memory>", cxx20},
-#line 269 "../../src/gcc/cp/std-name-hint.gperf"
+#line 269 "std-name-hint.gperf"
{"wcout", "<iostream>", cxx98},
-#line 314 "../../src/gcc/cp/std-name-hint.gperf"
+#line 314 "std-name-hint.gperf"
{"destroy_n", "<memory>", cxx20},
-#line 226 "../../src/gcc/cp/std-name-hint.gperf"
+#line 226 "std-name-hint.gperf"
{"get_time", "<iomanip>", cxx11},
-#line 555 "../../src/gcc/cp/std-name-hint.gperf"
+#line 555 "std-name-hint.gperf"
{"cmp_less_equal", "<utility>", cxx20},
-#line 80 "../../src/gcc/cp/std-name-hint.gperf"
+#line 80 "std-name-hint.gperf"
{"chrono::reload_tzdb", "<chrono>", cxx20},
-#line 523 "../../src/gcc/cp/std-name-hint.gperf"
+#line 523 "std-name-hint.gperf"
{"conjunction", "<type_traits>", cxx17},
-#line 75 "../../src/gcc/cp/std-name-hint.gperf"
+#line 75 "std-name-hint.gperf"
{"chrono::milliseconds", "<chrono>", cxx11},
-#line 59 "../../src/gcc/cp/std-name-hint.gperf"
+#line 59 "std-name-hint.gperf"
{"chrono::days", "<chrono>", cxx20},
-#line 474 "../../src/gcc/cp/std-name-hint.gperf"
+#line 474 "std-name-hint.gperf"
{"stod", "<string>", cxx11},
-#line 478 "../../src/gcc/cp/std-name-hint.gperf"
+#line 478 "std-name-hint.gperf"
{"stold", "<string>", cxx11},
-#line 267 "../../src/gcc/cp/std-name-hint.gperf"
+#line 267 "std-name-hint.gperf"
{"wcin", "<iostream>", cxx98},
-#line 529 "../../src/gcc/cp/std-name-hint.gperf"
+#line 529 "std-name-hint.gperf"
{"invoke_result", "<type_traits>", cxx17},
-#line 530 "../../src/gcc/cp/std-name-hint.gperf"
+#line 530 "std-name-hint.gperf"
{"invoke_result_t", "<type_traits>", cxx17},
-#line 50 "../../src/gcc/cp/std-name-hint.gperf"
+#line 50 "std-name-hint.gperf"
{"atomic", "<atomic>", cxx11},
-#line 71 "../../src/gcc/cp/std-name-hint.gperf"
+#line 71 "std-name-hint.gperf"
{"chrono::leap_second_info", "<chrono>", cxx20},
-#line 238 "../../src/gcc/cp/std-name-hint.gperf"
+#line 238 "std-name-hint.gperf"
{"dec", "<ios>", cxx98},
-#line 157 "../../src/gcc/cp/std-name-hint.gperf"
+#line 157 "std-name-hint.gperf"
{"current_exception", "<exception>", cxx11},
-#line 119 "../../src/gcc/cp/std-name-hint.gperf"
+#line 119 "std-name-hint.gperf"
{"constructible_from", "<concepts>", cxx20},
-#line 100 "../../src/gcc/cp/std-name-hint.gperf"
+#line 100 "std-name-hint.gperf"
{"weak_equality", "<compare>", cxx20},
-#line 333 "../../src/gcc/cp/std-name-hint.gperf"
+#line 333 "std-name-hint.gperf"
{"uses_allocator_v", "<memory>", cxx17},
-#line 69 "../../src/gcc/cp/std-name-hint.gperf"
+#line 69 "std-name-hint.gperf"
{"chrono::hours", "<chrono>", cxx11},
-#line 109 "../../src/gcc/cp/std-name-hint.gperf"
+#line 109 "std-name-hint.gperf"
{"common_reference_with", "<concepts>", cxx20},
-#line 483 "../../src/gcc/cp/std-name-hint.gperf"
+#line 483 "std-name-hint.gperf"
{"to_string", "<string>", cxx17},
-#line 524 "../../src/gcc/cp/std-name-hint.gperf"
+#line 524 "std-name-hint.gperf"
{"conjunction_v", "<type_traits>", cxx17},
-#line 578 "../../src/gcc/cp/std-name-hint.gperf"
+#line 578 "std-name-hint.gperf"
{"to_underlying", "<utility>", cxx23},
-#line 402 "../../src/gcc/cp/std-name-hint.gperf"
+#line 402 "std-name-hint.gperf"
{"scoped_allocator_adaptor", "<scoped_allocator>", cxx11},
-#line 310 "../../src/gcc/cp/std-name-hint.gperf"
+#line 310 "std-name-hint.gperf"
{"construct_at", "<memory>", cxx20},
-#line 564 "../../src/gcc/cp/std-name-hint.gperf"
+#line 564 "std-name-hint.gperf"
{"in_place_type", "<utility>", cxx17},
-#line 320 "../../src/gcc/cp/std-name-hint.gperf"
+#line 320 "std-name-hint.gperf"
{"make_shared_for_overwrite", "<memory>", cxx20},
-#line 166 "../../src/gcc/cp/std-name-hint.gperf"
+#line 166 "std-name-hint.gperf"
{"basic_format_arg", "<format>", cxx20},
-#line 73 "../../src/gcc/cp/std-name-hint.gperf"
+#line 73 "std-name-hint.gperf"
{"chrono::locate_zone", "<chrono>", cxx20},
-#line 72 "../../src/gcc/cp/std-name-hint.gperf"
+#line 72 "std-name-hint.gperf"
{"chrono::local_t", "<chrono>", cxx20},
-#line 170 "../../src/gcc/cp/std-name-hint.gperf"
+#line 170 "std-name-hint.gperf"
{"basic_format_string", "<format>", cxx20},
-#line 565 "../../src/gcc/cp/std-name-hint.gperf"
+#line 565 "std-name-hint.gperf"
{"in_place_type_t", "<utility>", cxx17},
-#line 279 "../../src/gcc/cp/std-name-hint.gperf"
+#line 279 "std-name-hint.gperf"
{"counted_iterator", "<iterator>", cxx20},
-#line 448 "../../src/gcc/cp/std-name-hint.gperf"
+#line 448 "std-name-hint.gperf"
{"domain_error", "<stdexcept>", cxx98},
-#line 84 "../../src/gcc/cp/std-name-hint.gperf"
+#line 84 "std-name-hint.gperf"
{"chrono::steady_clock", "<chrono>", cxx11},
-#line 188 "../../src/gcc/cp/std-name-hint.gperf"
+#line 188 "std-name-hint.gperf"
{"vformat_to", "<format>", cxx20},
-#line 54 "../../src/gcc/cp/std-name-hint.gperf"
+#line 54 "std-name-hint.gperf"
{"atomic_unsigned_lock_free", "<atomic>", cxx11},
-#line 147 "../../src/gcc/cp/std-name-hint.gperf"
+#line 147 "std-name-hint.gperf"
{"uint_fast8_t", "<cstdint>", cxx11},
-#line 83 "../../src/gcc/cp/std-name-hint.gperf"
+#line 83 "std-name-hint.gperf"
{"chrono::seconds", "<chrono>", cxx11},
-#line 74 "../../src/gcc/cp/std-name-hint.gperf"
+#line 74 "std-name-hint.gperf"
{"chrono::microseconds", "<chrono>", cxx11},
-#line 67 "../../src/gcc/cp/std-name-hint.gperf"
+#line 67 "std-name-hint.gperf"
{"chrono::gps_clock", "<chrono>", cxx20},
-#line 85 "../../src/gcc/cp/std-name-hint.gperf"
+#line 85 "std-name-hint.gperf"
{"chrono::system_clock", "<chrono>", cxx11},
-#line 140 "../../src/gcc/cp/std-name-hint.gperf"
+#line 140 "std-name-hint.gperf"
{"condition_variable_any", "<condition_variable>", cxx11},
-#line 214 "../../src/gcc/cp/std-name-hint.gperf"
+#line 214 "std-name-hint.gperf"
{"unwrap_ref_decay_t", "<functional>", cxx20},
-#line 136 "../../src/gcc/cp/std-name-hint.gperf"
+#line 136 "std-name-hint.gperf"
{"strict_weak_order", "<concepts>", cxx20},
-#line 437 "../../src/gcc/cp/std-name-hint.gperf"
+#line 437 "std-name-hint.gperf"
{"ostringstream", "<sstream>", cxx98},
-#line 317 "../../src/gcc/cp/std-name-hint.gperf"
+#line 317 "std-name-hint.gperf"
{"get_deleter", "<memory>", cxx11},
-#line 367 "../../src/gcc/cp/std-name-hint.gperf"
+#line 367 "std-name-hint.gperf"
{"numbers::egamma_v", "<numbers>", cxx20},
-#line 566 "../../src/gcc/cp/std-name-hint.gperf"
+#line 566 "std-name-hint.gperf"
{"in_range", "<utility>", cxx20},
-#line 558 "../../src/gcc/cp/std-name-hint.gperf"
+#line 558 "std-name-hint.gperf"
{"exchange", "<utility>", cxx14},
-#line 551 "../../src/gcc/cp/std-name-hint.gperf"
+#line 551 "std-name-hint.gperf"
{"cmp_equal", "<utility>", cxx20},
-#line 556 "../../src/gcc/cp/std-name-hint.gperf"
+#line 556 "std-name-hint.gperf"
{"cmp_not_equal", "<utility>", cxx20},
-#line 435 "../../src/gcc/cp/std-name-hint.gperf"
+#line 435 "std-name-hint.gperf"
{"istringstream", "<sstream>", cxx98},
-#line 436 "../../src/gcc/cp/std-name-hint.gperf"
+#line 436 "std-name-hint.gperf"
{"istringstream", "<sstream>", cxx98},
-#line 442 "../../src/gcc/cp/std-name-hint.gperf"
+#line 442 "std-name-hint.gperf"
{"wstringbuf", "<sstream>", cxx98},
-#line 225 "../../src/gcc/cp/std-name-hint.gperf"
+#line 225 "std-name-hint.gperf"
{"get_money", "<iomanip>", cxx11},
-#line 191 "../../src/gcc/cp/std-name-hint.gperf"
+#line 191 "std-name-hint.gperf"
{"wformat_parse_context", "<format>", cxx20},
-#line 482 "../../src/gcc/cp/std-name-hint.gperf"
+#line 482 "std-name-hint.gperf"
{"string", "<string>", cxx98},
-#line 280 "../../src/gcc/cp/std-name-hint.gperf"
+#line 280 "std-name-hint.gperf"
{"distance", "<iterator>", cxx98},
-#line 557 "../../src/gcc/cp/std-name-hint.gperf"
+#line 557 "std-name-hint.gperf"
{"declval", "<utility>", cxx11},
-#line 254 "../../src/gcc/cp/std-name-hint.gperf"
+#line 254 "std-name-hint.gperf"
{"scientific", "<ios>", cxx98},
-#line 98 "../../src/gcc/cp/std-name-hint.gperf"
+#line 98 "std-name-hint.gperf"
{"strong_equality", "<compare>", cxx20},
-#line 487 "../../src/gcc/cp/std-name-hint.gperf"
+#line 487 "std-name-hint.gperf"
{"u8string", "<string>", cxx20},
-#line 190 "../../src/gcc/cp/std-name-hint.gperf"
+#line 190 "std-name-hint.gperf"
{"wformat_context", "<format>", cxx20},
-#line 312 "../../src/gcc/cp/std-name-hint.gperf"
+#line 312 "std-name-hint.gperf"
{"destroy", "<memory>", cxx20},
-#line 559 "../../src/gcc/cp/std-name-hint.gperf"
+#line 559 "std-name-hint.gperf"
{"forward", "<utility>", cxx11},
-#line 535 "../../src/gcc/cp/std-name-hint.gperf"
+#line 535 "std-name-hint.gperf"
{"type_identity", "<type_traits>", cxx20},
-#line 464 "../../src/gcc/cp/std-name-hint.gperf"
+#line 464 "std-name-hint.gperf"
{"stop_callback", "<stop_token>", cxx20},
-#line 86 "../../src/gcc/cp/std-name-hint.gperf"
+#line 86 "std-name-hint.gperf"
{"chrono::tai_clock", "<chrono>", cxx20},
-#line 91 "../../src/gcc/cp/std-name-hint.gperf"
+#line 91 "std-name-hint.gperf"
{"chrono::tzdb_list", "<chrono>", cxx20},
-#line 301 "../../src/gcc/cp/std-name-hint.gperf"
+#line 301 "std-name-hint.gperf"
{"allocate_shared", "<memory>", cxx11},
-#line 90 "../../src/gcc/cp/std-name-hint.gperf"
+#line 90 "std-name-hint.gperf"
{"chrono::tzdb", "<chrono>", cxx20},
-#line 126 "../../src/gcc/cp/std-name-hint.gperf"
+#line 126 "std-name-hint.gperf"
{"totally_ordered_with", "<concepts>", cxx20},
-#line 525 "../../src/gcc/cp/std-name-hint.gperf"
+#line 525 "std-name-hint.gperf"
{"disjunction", "<type_traits>", cxx17},
-#line 110 "../../src/gcc/cp/std-name-hint.gperf"
+#line 110 "std-name-hint.gperf"
{"common_with", "<concepts>", cxx20},
-#line 202 "../../src/gcc/cp/std-name-hint.gperf"
+#line 202 "std-name-hint.gperf"
{"ofstream", "<fstream>", cxx98},
-#line 349 "../../src/gcc/cp/std-name-hint.gperf"
+#line 349 "std-name-hint.gperf"
{"lock_guard", "<mutex>", cxx11},
-#line 118 "../../src/gcc/cp/std-name-hint.gperf"
+#line 118 "std-name-hint.gperf"
{"destructible", "<concepts>", cxx20},
-#line 176 "../../src/gcc/cp/std-name-hint.gperf"
+#line 176 "std-name-hint.gperf"
{"format_string", "<format>", cxx20},
-#line 410 "../../src/gcc/cp/std-name-hint.gperf"
+#line 410 "std-name-hint.gperf"
{"shared_lock", "<shared_mutex>", cxx14},
-#line 315 "../../src/gcc/cp/std-name-hint.gperf"
+#line 315 "std-name-hint.gperf"
{"dynamic_pointer_cast", "<memory>", cxx11},
-#line 101 "../../src/gcc/cp/std-name-hint.gperf"
+#line 101 "std-name-hint.gperf"
{"weak_ordering", "<compare>", cxx20},
-#line 201 "../../src/gcc/cp/std-name-hint.gperf"
+#line 201 "std-name-hint.gperf"
{"ifstream", "<fstream>", cxx98},
-#line 452 "../../src/gcc/cp/std-name-hint.gperf"
+#line 452 "std-name-hint.gperf"
{"out_of_range", "<stdexcept>", cxx98},
-#line 264 "../../src/gcc/cp/std-name-hint.gperf"
+#line 264 "std-name-hint.gperf"
{"clog", "<iostream>", cxx98},
-#line 62 "../../src/gcc/cp/std-name-hint.gperf"
+#line 62 "std-name-hint.gperf"
{"chrono::file_clock", "<chrono>", cxx20},
-#line 526 "../../src/gcc/cp/std-name-hint.gperf"
+#line 526 "std-name-hint.gperf"
{"disjunction_v", "<type_traits>", cxx17},
-#line 485 "../../src/gcc/cp/std-name-hint.gperf"
+#line 485 "std-name-hint.gperf"
{"u16string", "<string>", cxx11},
-#line 351 "../../src/gcc/cp/std-name-hint.gperf"
+#line 351 "std-name-hint.gperf"
{"once_flag", "<mutex>", cxx11},
-#line 491 "../../src/gcc/cp/std-name-hint.gperf"
+#line 491 "std-name-hint.gperf"
{"string_view", "<string_view>", cxx17},
-#line 304 "../../src/gcc/cp/std-name-hint.gperf"
+#line 304 "std-name-hint.gperf"
{"allocator_arg", "<memory>", cxx11},
-#line 486 "../../src/gcc/cp/std-name-hint.gperf"
+#line 486 "std-name-hint.gperf"
{"u32string", "<string>", cxx11},
-#line 213 "../../src/gcc/cp/std-name-hint.gperf"
+#line 213 "std-name-hint.gperf"
{"unwrap_ref_decay", "<functional>", cxx20},
-#line 70 "../../src/gcc/cp/std-name-hint.gperf"
+#line 70 "std-name-hint.gperf"
{"chrono::leap_second", "<chrono>", cxx20},
-#line 92 "../../src/gcc/cp/std-name-hint.gperf"
+#line 92 "std-name-hint.gperf"
{"chrono::utc_clock", "<chrono>", cxx20},
-#line 107 "../../src/gcc/cp/std-name-hint.gperf"
+#line 107 "std-name-hint.gperf"
{"derived_from", "<concepts>", cxx20},
-#line 99 "../../src/gcc/cp/std-name-hint.gperf"
+#line 99 "std-name-hint.gperf"
{"strong_ordering", "<compare>", cxx20},
-#line 497 "../../src/gcc/cp/std-name-hint.gperf"
+#line 497 "std-name-hint.gperf"
{"generic_category", "<system_error>", cxx11},
-#line 125 "../../src/gcc/cp/std-name-hint.gperf"
+#line 125 "std-name-hint.gperf"
{"totally_ordered", "<concepts>", cxx20},
-#line 494 "../../src/gcc/cp/std-name-hint.gperf"
+#line 494 "std-name-hint.gperf"
{"error_category", "<system_error>", cxx11},
-#line 82 "../../src/gcc/cp/std-name-hint.gperf"
+#line 82 "std-name-hint.gperf"
{"chrono::round", "<chrono>", cxx17},
-#line 357 "../../src/gcc/cp/std-name-hint.gperf"
+#line 357 "std-name-hint.gperf"
{"unique_lock", "<mutex>", cxx11},
-#line 319 "../../src/gcc/cp/std-name-hint.gperf"
+#line 319 "std-name-hint.gperf"
{"make_shared", "<memory>", cxx11},
-#line 507 "../../src/gcc/cp/std-name-hint.gperf"
+#line 507 "std-name-hint.gperf"
{"this_thread", "<thread>", cxx11},
-#line 449 "../../src/gcc/cp/std-name-hint.gperf"
+#line 449 "std-name-hint.gperf"
{"invalid_argument", "<stdexcept>", cxx98},
-#line 354 "../../src/gcc/cp/std-name-hint.gperf"
+#line 354 "std-name-hint.gperf"
{"scoped_lock", "<mutex>", cxx17},
-#line 268 "../../src/gcc/cp/std-name-hint.gperf"
+#line 268 "std-name-hint.gperf"
{"wclog", "<iostream>", cxx98},
-#line 506 "../../src/gcc/cp/std-name-hint.gperf"
+#line 506 "std-name-hint.gperf"
{"jthread", "<thread>", cxx20},
-#line 97 "../../src/gcc/cp/std-name-hint.gperf"
+#line 97 "std-name-hint.gperf"
{"partial_ordering", "<compare>", cxx20},
-#line 68 "../../src/gcc/cp/std-name-hint.gperf"
+#line 68 "std-name-hint.gperf"
{"chrono::high_resolution_clock", "<chrono>", cxx11},
-#line 307 "../../src/gcc/cp/std-name-hint.gperf"
+#line 307 "std-name-hint.gperf"
{"assume_aligned", "<memory>", cxx20},
-#line 488 "../../src/gcc/cp/std-name-hint.gperf"
+#line 488 "std-name-hint.gperf"
{"wstring", "<string>", cxx98},
-#line 192 "../../src/gcc/cp/std-name-hint.gperf"
+#line 192 "std-name-hint.gperf"
{"wformat_string", "<format>", cxx20},
-#line 189 "../../src/gcc/cp/std-name-hint.gperf"
+#line 189 "std-name-hint.gperf"
{"wformat_args", "<format>", cxx20}
};
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 5863b68..accce0e 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;
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 88f8f34..0bf5ae4 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -156,7 +156,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
{
if (complain & tf_error)
cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
- note_failed_type_completion_for_satisfaction (type);
+ note_failed_type_completion (type, complain);
return NULL_TREE;
}
else
@@ -1372,17 +1372,12 @@ cxx_safe_arg_type_equiv_p (tree t1, tree t2)
&& TYPE_PTR_P (t2))
return true;
- /* The signedness of the parameter matters only when an integral
- type smaller than int is promoted to int, otherwise only the
- precision of the parameter matters.
- This check should make sure that the callee does not see
- undefined values in argument registers. */
+ /* Only the precision of the parameter matters. This check should
+ make sure that the callee does not see undefined values in argument
+ registers. */
if (INTEGRAL_TYPE_P (t1)
&& INTEGRAL_TYPE_P (t2)
- && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
- && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2)
- || !targetm.calls.promote_prototypes (NULL_TREE)
- || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node)))
+ && TYPE_PRECISION (t1) == TYPE_PRECISION (t2))
return true;
return same_type_p (t1, t2);
@@ -2089,7 +2084,14 @@ cxx_sizeof_or_alignof_type (location_t loc, tree type, enum tree_code op,
bool dependent_p = dependent_type_p (type);
if (!dependent_p)
- complete_type (type);
+ {
+ complete_type (type);
+ if (!COMPLETE_TYPE_P (type))
+ /* Call this here because the incompleteness diagnostic comes from
+ c_sizeof_or_alignof_type instead of
+ complete_type_or_maybe_complain. */
+ note_failed_type_completion (type, complain);
+ }
if (dependent_p
/* VLA types will have a non-constant size. In the body of an
uninstantiated template, we don't need to try to compute the
@@ -2111,7 +2113,7 @@ cxx_sizeof_or_alignof_type (location_t loc, tree type, enum tree_code op,
return c_sizeof_or_alignof_type (loc, complete_type (type),
op == SIZEOF_EXPR, std_alignof,
- complain);
+ complain & (tf_warning_or_error));
}
/* Return the size of the type, without producing any warnings for
@@ -3999,13 +4001,61 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
}
case COND_EXPR:
- ret = build_conditional_expr
- (loc, TREE_OPERAND (array, 0),
- cp_build_array_ref (loc, TREE_OPERAND (array, 1), idx,
- complain),
- cp_build_array_ref (loc, TREE_OPERAND (array, 2), idx,
- complain),
- complain);
+ tree op0, op1, op2;
+ op0 = TREE_OPERAND (array, 0);
+ op1 = TREE_OPERAND (array, 1);
+ op2 = TREE_OPERAND (array, 2);
+ if (TREE_SIDE_EFFECTS (idx) || !tree_invariant_p (idx))
+ {
+ /* If idx could possibly have some SAVE_EXPRs, turning
+ (op0 ? op1 : op2)[idx] into
+ op0 ? op1[idx] : op2[idx] can lead into temporaries
+ initialized in one conditional path and uninitialized
+ uses of them in the other path.
+ And if idx is a really large expression, evaluating it
+ twice is also not optimal.
+ On the other side, op0 must be sequenced before evaluation
+ of op1 and op2 and for C++17 op0, op1 and op2 must be
+ sequenced before idx.
+ If idx is INTEGER_CST, we can just do the optimization
+ without any SAVE_EXPRs, if op1 and op2 are both ARRAY_TYPE
+ VAR_DECLs or COMPONENT_REFs thereof (so their address
+ is constant or relative to frame), optimize into
+ (SAVE_EXPR <op0>, SAVE_EXPR <idx>, SAVE_EXPR <op0>)
+ ? op1[SAVE_EXPR <idx>] : op2[SAVE_EXPR <idx>]
+ Otherwise avoid this optimization. */
+ if (flag_strong_eval_order == 2)
+ {
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+ {
+ if (!address_invariant_p (op1) || !address_invariant_p (op2))
+ {
+ /* Force default conversion on array if
+ we can't optimize this and array is ARRAY_TYPE
+ COND_EXPR, we can't leave COND_EXPRs with
+ ARRAY_TYPE in the IL. */
+ array = cp_default_conversion (array, complain);
+ if (error_operand_p (array))
+ return error_mark_node;
+ break;
+ }
+ }
+ else if (!POINTER_TYPE_P (TREE_TYPE (array))
+ || !tree_invariant_p (op1)
+ || !tree_invariant_p (op2))
+ break;
+ }
+ if (TREE_SIDE_EFFECTS (idx))
+ {
+ idx = save_expr (idx);
+ op0 = save_expr (op0);
+ tree tem = build_compound_expr (loc, op0, idx);
+ op0 = build_compound_expr (loc, tem, op0);
+ }
+ }
+ op1 = cp_build_array_ref (loc, op1, idx, complain);
+ op2 = cp_build_array_ref (loc, op2, idx, complain);
+ ret = build_conditional_expr (loc, op0, op1, op2, complain);
protected_set_expr_location (ret, loc);
return ret;
@@ -11468,6 +11518,12 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
&& call_from_lambda_thunk_p (retval))
converted = true;
+ /* Don't check copy-initialization for NRV in a coroutine ramp; we
+ implement this case as NRV, but it's specified as directly
+ initializing the return value from get_return_object(). */
+ if (DECL_RAMP_P (current_function_decl) && named_return_value_okay_p)
+ converted = true;
+
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
case that functype is smaller than the valtype. */