diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-10-12 09:46:38 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-10-12 09:46:38 -0700 |
commit | 9cd320ea6572c577cdf17ce1f9ea5230b166af6d (patch) | |
tree | d1c8e7c2e09a91ed75f0e5476c648c2e745aa2de /gcc/cp | |
parent | 4854d721be78358e59367982bdd94461b4be3c5a (diff) | |
parent | 3175d40fc52fb8eb3c3b18cc343d773da24434fb (diff) | |
download | gcc-9cd320ea6572c577cdf17ce1f9ea5230b166af6d.zip gcc-9cd320ea6572c577cdf17ce1f9ea5230b166af6d.tar.gz gcc-9cd320ea6572c577cdf17ce1f9ea5230b166af6d.tar.bz2 |
Merge from trunk revision 3175d40fc52fb8eb3c3b18cc343d773da24434fb.
Diffstat (limited to 'gcc/cp')
35 files changed, 5760 insertions, 3789 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bf71994..c28ae8c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,1367 @@ +2020-10-08 Jason Merrill <jason@redhat.com> + + PR c++/96805 + PR c++/96199 + * pt.c (tsubst_aggr_type): Don't build a TYPENAME_TYPE when + entering_scope. + (tsubst_template_decl): Use tsubst_aggr_type. + +2020-10-08 Patrick Palka <ppalka@redhat.com> + + PR c++/97052 + * constraint.cc (build_type_constraint): Temporarily increment + processing_template_decl before calling build_concept_check. + * pt.c (make_constrained_placeholder_type): Likewise. + +2020-10-08 Patrick Palka <ppalka@redhat.com> + + PR c++/96229 + * parser.c (cp_parser_class_specifier_1): Move call to + associate_classtype_constraints from here to ... + (cp_parser_class_head): ... here. + * pt.c (is_compatible_template_arg): Correct documentation to + say "argument is _no_ more constrained than the parameter". + +2020-10-07 Marek Polacek <polacek@redhat.com> + + PR c++/97010 + * pt.c (tsubst_copy_and_build) <case TEMPLATE_ID_EXPR>: Call + tsubst_copy_and_build explicitly instead of using the RECUR macro. + Handle a TEMPLATE_ID_EXPR with an IDENTIFIER_NODE as its operand. + <case CALL_EXPR>: Perform ADL for a TEMPLATE_ID_EXPR with an + IDENTIFIER_NODE as its operand. + +2020-10-07 Patrick Palka <ppalka@redhat.com> + + PR c++/88115 + PR libstdc++/97273 + * tree.c (cp_tree_equal) <case ALIGNOF_EXPR>: Return false if + ALIGNOF_EXPR_STD_P differ. + +2020-10-07 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct language_function): Delete extern_decl_map. + (DECL_LOCAL_DECL_ALIAS): New. + * name-lookup.h (is_local_extern): Delete. + * name-lookup.c (set_local_extern_decl_linkage): Replace with ... + (push_local_extern_decl): ... this new function. + (do_pushdecl): Call new function after pushing new decl. Unhide + hidden non-functions. + (is_local_extern): Delete. + * decl.c (layout_var_decl): Do not allow VLA local externs. + * decl2.c (mark_used): Also mark DECL_LOCAL_DECL_ALIAS. Drop old + local-extern treatment. + * parser.c (cp_parser_oacc_declare): Deal with local extern aliases. + * pt.c (tsubst_expr): Adjust local extern instantiation. + * cp-gimplify.c (cp_genericize_r): Remap DECL_LOCAL_DECLs. + +2020-10-07 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_BUILTIN_P): Rename to ... + (DECL_UNDECLARED_BUILTIN_P): ... here. + * decl.c (duplicate_decls): Adjust. + * name-lookup.c (anticipated_builtin_p): Adjust. + (do_nonmember_using_decl): Likewise. + +2020-10-07 Nathan Sidwell <nathan@acm.org> + + * tree.c (build_cp_fntype_variant): Clear + TYPE_DEPENDENT_P_VALID if necessary. + +2020-10-06 Marek Polacek <polacek@redhat.com> + + PR c++/97297 + * parser.c (cp_parser_direct_declarator): When checking if a + name is a function template declaration for the P0634R3 case, + look in uninstantiated templates too. + +2020-10-05 Marek Polacek <polacek@redhat.com> + + * cp-tree.h (NON_UNION_CLASS_TYPE_P): Fix typo in a comment. + +2020-10-05 Richard Biener <rguenther@suse.de> + Jakub Jelinek <jakub@redhat.com> + + PR c++/97197 + * error.c (dump_expr): Handle TARGET_MEM_REF. + +2020-10-05 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (maybe_add_fuzzy_decl): New. + (maybe_add_fuzzy_binding): New. + (consider_binding_level): Use intermediate sortable vector for + namespace bindings. + +2020-10-02 Marek Polacek <polacek@redhat.com> + + PR c++/97014 + * cxx-pretty-print.c (pp_cxx_template_argument_list): If the + argument is template_parm_object_p, print its DECL_INITIAL. + +2020-10-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (lang_decl_base): anticipated_p is not used for + anticipatedness. + (DECL_ANTICIPATED): Delete. + * decl.c (duplicate_decls): Delete DECL_ANTICIPATED_management, + use was_hidden. + (cxx_builtin_function): Drop DECL_ANTICIPATED setting. + (xref_tag_1): Drop DECL_ANTICIPATED assert. + * name-lookup.c (name_lookup::adl_class_only): Drop + DECL_ANTICIPATED check. + (name_lookup::search_adl): Always dedup. + (anticipated_builtin_p): Reimplement. + (do_pushdecl): Drop DECL_ANTICIPATED asserts & update. + (lookup_elaborated_type_1): Drop DECL_ANTICIPATED update. + (do_pushtag): Drop DECL_ANTICIPATED setting. + * pt.c (push_template_decl): Likewise. + (tsubst_friend_class): Likewise. + +2020-10-02 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (consider_decl): New, broken out of ... + (consider_binding_level): ... here. Iterate the hash table for + namespace bindings. + +2020-10-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (base_ctor_omit_inherited_parms): Declare. + * class.c (add_method): Refactor main loop, only pass fns to + ctor_omit_inherited_parms. + (build_cdtor_clones): Rename bool parms. + (clone_cdtor): Call base_ctor_omit_inherited_parms. + * method.c (base_ctor_omit_inherited_parms): New, broken out of + ... + (ctor_omit_inherited_parms): ... here, call it with + DECL_CLONED_FUNCTION. + +2020-10-02 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (cp_fname_init): Delete declaration. + * decl.c (cp_fname_init): Merge into only caller ... + (cp_make_fname): ... here & refactor. + +2020-10-02 Jason Merril <jason@redhat.com> + + * call.c (build_operator_new_call): Set CALL_FROM_NEW_OR_DELETE_P. + (build_op_delete_call): Likewise. + * init.c (build_new_1, build_vec_delete_1, build_delete): Not here. + (build_delete): + +2020-10-02 Jason Merril <jason@redhat.com> + + * lambda.c (call_from_lambda_thunk_p): New. + * cp-gimplify.c (cp_genericize_r): Use it. + * pt.c (tsubst_copy_and_build): Use it. + * typeck.c (check_return_expr): Use it. + * cp-tree.h: Declare it. + (CALL_FROM_NEW_OR_DELETE_P): Move to gcc/tree.h. + +2020-10-01 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_ANTICIPATED): Adjust comment. + (DECL_HIDDEN_P, TYPE_HIDDEN_P): Delete. + * tree.c (ovl_insert): Delete DECL_HIDDEN_P assert. + (ovl_skip_hidden): Likewise. + +2020-10-01 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (pushdecl_top_level): Assert incoming context is + null, add global_namespace context. + (pushdecl_top_level_and_finish): Likewise. + * pt.c (get_template_parm_object): Clear decl context before + pushing. + * semantics.c (finish_compound_literal): Likewise. + +2020-10-01 Nathan Sidwell <nathan@acm.org> + + * decl.c (lookup_and_check_tag): Refactor. + +2020-10-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/96994 + * call.c (build_over_call): If obj_arg is non-NULL, return INIT_EXPR + setting obj_arg to call. + +2020-10-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/97195 + * constexpr.c (cxx_eval_call_expression): Don't VERIFY_CONSTANT the + second argument. + +2020-10-01 Marek Polacek <polacek@redhat.com> + + PR c++/90210 + * pt.c (do_class_deduction): Don't prune explicit deduction guides + in copy-list-initialization. In copy-list-initialization, if an + explicit deduction guide was selected, give an error. + +2020-09-30 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct lang_decl_fn): Remove hidden_friend_p. + (DECL_HIDDEN_FRIEND_P): Delete. + * call.c (add_function_candidate): Drop assert about anticipated + decl. + (build_new_op_1): Drop koenig lookup flagging for hidden friend. + * decl.c (duplicate_decls): Drop HIDDEN_FRIEND_P updating. + * name-lookup.c (do_pushdecl): Likewise. + (set_decl_namespace): Discover hiddenness from OVL_HIDDEN_P. + * pt.c (check_explicit_specialization): Record found_hidden + explicitly. + +2020-09-29 Marek Polacek <polacek@redhat.com> + + PR c++/94695 + * call.c (ref_conv_binds_directly_p): New function. + * cp-tree.h (ref_conv_binds_directly_p): Declare. + * parser.c (warn_for_range_copy): New function. + (cp_convert_range_for): Call it. + +2020-09-29 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (ovl_insert): Change final parm to hidden-or-using + indicator. + * name-lookup.h (HIDDEN_TYPE_BINDING_P): New. + (struct cxx_binding): Add type_is_hidden flag. + * tree.c (ovl_insert): Change using_p parm to using_or_hidden, + adjust. + (ovl_skip_hidden): Assert we never see a naked hidden decl. + * decl.c (xref_tag_1): Delete unhiding friend from here (moved to + lookup_elaborated_type_1). + * name-lookup.c (STAT_TYPE_HIDDEN_P, STAT_DECL_HIDDEN_P): New. + (name_lookup::search_namespace_only): Check new hidden markers. + (cxx_binding_make): Clear HIDDEN_TYPE_BINDING_P. + (update_binding): Update new hidden markers. + (lookup_name_1): Check HIDDEN_TYPE_BINDING_P and simplify friend + ignoring. + (lookup_elaborated_type_1): Use new hidden markers. Reveal the + decl here. + +2020-09-29 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (create_local_binding): Do not clear + INHERITED_VALUE_BINDING_P here. + (name_lookup::process_binding): Move done hidden-decl triage to ... + (name_lookup::search_namespace_only): ... here, its only caller. + (cxx_binding_make): Clear flags here. + (push_binding): Not here. + (pop_local_binding): RAII. + (update_binding): Refactor. + (do_pushdecl): Assert we're never revealing a local binding. + (do_pushdecl_with_scope): Directly call do_pushdecl. + (get_class_binding): Do not clear LOCAL_BINDING_P here. + * pt.c (push_template_decl): Set friend & anticipated before + pushing. + +2020-09-29 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (update_binding): We never meet two implicit + typedefs. + (do_pushdecl): Adjust set_identifier_type_value_with_scope calls. + (set_identifier_type_value_with_scope): Do not update binding in + the namespace-case. Assert it is already there. + +2020-09-25 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (duplicate_decls): Replace 'is_friend' with 'hiding' + and add 'was_hidden'. + * name-lookup.h (pushdecl_namespace_level): Replace 'is_friend' + with 'hiding'. + (pushdecl): Likewise. + (pushdecl_top_level): Drop is_friend parm. + * decl.c (check_no_redeclaration_friend_default_args): Rename parm + olddelc_hidden_p. + (duplicate_decls): Replace 'is_friend' with 'hiding' + and 'was_hidden'. Do minimal adjustments in body. + (cxx_builtin_function): Pass 'hiding' to pushdecl. + * friend.c (do_friend): Pass 'hiding' to pushdecl. + * name-lookup.c (supplement_binding_1): Drop defaulted arg to + duplicate_decls. + (update_binding): Replace 'is_friend' with 'hiding'. Drop + defaulted arg to duplicate_decls. + (do_pushdecl): Replace 'is_friend' with 'hiding'. Assert no + surprise hidhing. Adjust duplicate_decls calls to inform of old + decl's hiddennes. + (pushdecl): Replace 'is_friend' with 'hiding'. + (set_identifier_type_value_with_scope): Adjust update_binding + call. + (do_pushdecl_with_scope): Replace 'is_friend' with 'hiding'. + (pushdecl_outermost_localscope): Drop default arg to + do_pushdecl_with_scope. + (pushdecl_namespace_level): Replace 'is_friend' with 'hiding'. + (pushdecl_top_level): Drop is_friend parm. + * pt.c (register_specialization): Comment duplicate_decls call + args. + (push_template_decl): Commont pushdecl_namespace_level. + (tsubst_friend_function, tsubst_friend_class): Likewise. + +2020-09-25 Nathan Sidwell <nathan@acm.org> + + * name-lookup.h (enum tag_scope): Replace with ... + (enum class TAG_how): ... this. Add HIDDEN_FRIEND value. + (lookup_type_scope): Replace with ... + (lookup_elaborated_type): ... this. + (pushtag): Use TAG_how, not tag_scope. + * cp-tree.h (xref_tag): Parameter is TAG_how, not tag_scope. + * decl.c (lookup_and_check_tag): Likewise. Adjust. + (xref_tag_1, xref_tag): Likewise. adjust. + (start_enum): Adjust lookup_and_check_tag call. + * name-lookup.c (lookup_type_scope_1): Rename to ... + (lookup_elaborated_type_1) ... here. Use TAG_how, not tag_scope. + (lookup_type_scope): Rename to ... + (lookup_elaborated_type): ... here. Use TAG_how, not tag_scope. + (do_pushtag): Use TAG_how, not tag_scope. Adjust. + (pushtag): Likewise. + * parser.c (cp_parser_elaborated_type_specifier): Adjust. + (cp_parser_class_head): Likewise. + +2020-09-25 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_BUILTIN_P): New. + * decl.c (duplicate_decls): Use it. Do not treat omp-udr as a + builtin. + * name-lookup.c (anticipated_builtin): Use it. + (set_decl_context_in_fn): Function-scope OMP UDRs have function context. + (do_nonmember_using_decl): Use DECL_BUILTIN_P. + * parser.c (cp_parser_omp_declare_reduction): Function-scope OMP + UDRs have function context. Assert we never find a valid duplicate. + * pt.c (tsubst_expr): Function-scope OMP UDRs have function context. + +2020-09-24 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (duplicate_decls): Default is_friend to false. + (xref_tag): Default tag_scope & tpl_header_p to ts_current & false. + (push_template_decl_real): Default is_friend to false. Rename to + ... + (push_template_decl): ... here. Delete original decl. + * name-lookup.h (pushdecl_namespace_level): Default is_friend to + false. + (pushtag): Default tag_scope to ts_current. + * coroutines.cc (morph_fn_to_coro): Drop default args to xref_tag. + * decl.c (start_decl): Drop default args to duplicate_decls. + (start_enum): Drop default arg to pushtag & xref_tag. + (start_preparsed_function): Pass DECL_FRIEND_P to + push_template_decl. + (grokmethod): Likewise. + * friend.c (do_friend): Rename push_template_decl_real calls. + * lambda.c (begin_lamnbda_type): Drop default args to xref_tag. + (vla_capture_type): Likewise. + * name-lookup.c (maybe_process_template_type_declaration): Rename + push_template_decl_real call. + (pushdecl_top_level_and_finish): Drop default arg to + pushdecl_namespace_level. + * pt.c (push_template_decl_real): Assert no surprising friend + functions. Rename to ... + (push_template_decl): ... here. Delete original function. + (lookup_template_class_1): Drop default args from pushtag. + (instantiate_class_template_1): Likewise. + * ptree.c (debug_overload): Print hidden and using markers. + * rtti.c (init_rtti_processing): Drop refault args from xref_tag. + (build_dynamic_cast_1, tinfo_base_init): Likewise. + * semantics.c (begin_class_definition): Drop default args to + pushtag. + +2020-09-24 Nathan Sidwell <nathan@acm.org> + + PR c++/97186 + * pt.c (maybe_instantiate_noexcept): Local externs are never + member fns. + +2020-09-23 Nathan Sidwell <nathan@acm.org> + + * name-lookup.h (typedef cxx_binding): Delete tdef. + (typedef cp_binding_level): Likewise. + (struct cxx_binding): Flags are bools. + +2020-09-23 Nathan Sidwell <nathan@acm.org> + + PR c++/97171 + * pt.c (tsubst_copy) [FUNCTION_DECL,VAR_DECL]: Retrieve local + specialization for DECL_LOCAL_P decls. + +2020-09-22 Patrick Palka <ppalka@redhat.com> + + PR c++/95310 + * pt.c (corresponding_template_parameter): Define. + (keep_template_parm): Use it to adjust the given template + parameter to the corresponding in-scope one from ctx_parms. + +2020-09-22 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (xref_tag_from_type): Don't declare. + * decl.c (xref_tag_from_type): Delete. + * pt.c (lookup_template_class_1): Erroneously located class + definitions just give error_mark, don't try and inject it into the + namespace. + +2020-09-22 Jakub Jelinek <jakub@redhat.com> + + PR c++/97145 + * constexpr.c (cxx_eval_builtin_function_call): Return void_node for + calls to __sanitize_ptr_{sub,cmp} builtins. + +2020-09-22 Nathan Sidwell <nathan@acm.org> + + * pt.c (instantiate_class_template_1): Do not repush and unhide + injected friend. + +2020-09-21 Marek Polacek <polacek@redhat.com> + + PR c++/90583 + DR 1722 + * lambda.c (maybe_add_lambda_conv_op): Mark the conversion function + as noexcept. + +2020-09-21 Marek Polacek <polacek@redhat.com> + + * pt.c (deduction_guides_for): Add a bool parameter. Set it. + (do_class_deduction): Warn when CTAD succeeds but the type doesn't + have any explicit deduction guides. + +2020-09-21 Nathan Sidwell <nathan@acm.org> + + * decl.c (xref_tag_1): Use IDENTIFIER_LAMBDA_P to detect lambdas. + * lambda.c (begin_lambda_type): Use ts_current to push the tag. + * name-lookup.h (enum tag_scope): Drop ts_lambda. + +2020-09-21 Marek Polacek <polacek@redhat.com> + + PR c++/97099 + * decl.c (redeclaration_error_message): Detect a redeclaration of + deduction guides. + +2020-09-19 Sandra Loosemore <sandra@codesourcery.com> + + * cp-gimplify.c (enum bc_t, bc_label): Move to c-family. + (begin_bc_block, finish_bc_block, get_bc_label): Likewise. + (genericize_cp_loop): Likewise. + (genericize_for_stmt, genericize_while_stmt): Likewise. + (genericize_do_stmt, genericize_switch_stmt): Likewise. + (genericize_continue_stmt, genericize_break_stmt): Likewise. + (genericize_omp_for_stmt): Likewise. + (cp_genericize_r): Call c_genericize_control_stmt instead of + above functions directly. + (cp_genericize): Call save_bc_state and restore_bc_state instead + of manipulating bc_label directly. + * cp-objcp-common.c (cxx_block_may_fallthru): Defer to + c_block_may_fallthru instead of handling SWITCH_STMT here. + (cp_common_init_ts): Move handling of loop and switch-related + statements to c-family. + * cp-tree.def (FOR_STMT, WHILE_STMT, DO_STMT): Move to c-family. + (BREAK_STMT, CONTINUE_STMT, SWITCH_STMT): Likewise. + * cp-tree.h (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): Likewise. + (WHILE_COND, WHILE_BODY): Likewise. + (DO_COND, DO_BODY): Likewise. + (FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, FOR_SCOPE): Likewise. + (SWITCH_STMT_COND, SWITCH_STMT_BODY): Likewise. + (SWITCH_STMT_TYPE, SWITCH_STMT_SCOPE): Likewise. + (SWITCH_STMT_ALL_CASES_P, SWITCH_STMT_NO_BREAK_P): Likewise. + * cxx-pretty-print.c (cxx_pretty_printer::statement): Move code + to handle structured loop and switch tree nodes to c-family. + * dump.c (cp_dump_tree): Likewise. + +2020-09-19 Patrick Palka <ppalka@redhat.com> + + PR c++/96531 + PR c++/97103 + * constraint.cc (map_arguments): Call template_parm_to_arg + in the self-mapping case. + (finish_shorthand_constraint): No need to build a TREE_LIST + before calling template_parm_to_arg. + * pt.c (template_parm_to_arg): Rewrite to handle TEMPLATE_PARM_P + nodes as well as DECL_TEMPLATE_PARM_P nodes, and to make the + overlying TREE_LIST node optional. + (keep_template_parm): Don't record a BOUND_TEMPLATE_TEMPLATE_PARM, + instead record its corresponding TEMPLATE_TEMPLATE_PARM. + (convert_generic_types_to_packs): Don't call + template_parm_to_arg. + +2020-09-19 Patrick Palka <ppalka@redhat.com> + + PR c++/97051 + * constraint.cc (satisfy_atom): Pass true as the + manifestly_const_eval argument to maybe_constant_value. + +2020-09-18 Jason Merrill <jason@redhat.com> + + PR bootstrap/97118 + * decl.c (complete_vars): Only call layout_var_decl if completing + the type succeeded. + +2020-09-18 Jason Merrill <jason@redhat.com> + + * decl.c (complete_vars): Call layout_var_decl. + +2020-09-17 Patrick Palka <ppalka@redhat.com> + + PR c++/96409 + PR c++/96410 + * constraint.cc (tsubst_requires_expr): Use REQUIRES_EXPR_PARMS + and REQUIRES_EXPR_REQS. Use REQUIRES_EXPR_EXTRA_ARGS, + add_extra_args and build_extra_args to defer substitution until + we have all the template arguments. + (finish_requires_expr): Adjust the call to build_min so that + REQUIRES_EXPR_EXTRA_ARGS gets set to NULL_TREE. + * cp-tree.def (REQUIRES_EXPR): Give it a third operand. + * cp-tree.h (REQUIRES_EXPR_PARMS, REQUIRES_EXPR_REQS, + REQUIRES_EXPR_EXTRA_ARGS): Define. + (add_extra_args, build_extra_args): Declare. + +2020-09-16 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (cp_check_omp_declare_reduction): Return bool. + * semantics.c (cp_check_omp_declare_reduction): Return true on for + success. + * pt.c (push_template_decl_real): OMP reductions do not get a + template header. + (tsubst_function_decl): Remove special casing for local decl omp + reductions. + (tsubst_expr): Call instantiate_body for a local omp reduction. + (instantiate_body): Add nested_p parm, and deal with such + instantiations. + (instantiate_decl): Reject FUNCTION_SCOPE entities, adjust + instantiate_body call. + +2020-09-16 Nathan Sidwell <nathan@acm.org> + + * pt.c (instantiate_body): Remove 'nested' var, simplify + push_to_top logic. + +2020-09-16 Nathan Sidwell <nathan@acm.org> + + * pt.c (instantiate_body): New, broken out of .. + (instantiate_decl): ... here. Call it. + +2020-09-15 Nathan Sidwell <nathan@acm.org> + + * pt.c (push_template_decl_real): OMP reductions retain a template + header. + (tsubst_function_decl): Likewise. + +2020-09-15 Tobias Burnus <tobias@codesourcery.com> + + PR fortran/96668 + * cp-gimplify.c (cxx_omp_finish_clause): Add bool openacc arg. + * cp-tree.h (cxx_omp_finish_clause): Likewise + * semantics.c (handle_omp_for_class_iterator): Update call. + +2020-09-14 Marek Polacek <polacek@redhat.com> + + * pt.c (push_template_decl_real): Use VAR_OR_FUNCTION_DECL_P. + +2020-09-14 Nathan Sidwell <nathan@acm.org> + + * pt.c (push_template_decl_real): Don't attach a template head to + local externs. + (tsubst_function_decl): Add support for headless local extern + decls. + (tsubst_decl): Add support for headless local extern decls. + +2020-09-11 Nathan Sidwell <nathan@acm.org> + + * decl.c (grokfndecl): Don't attach to local extern. + +2020-09-11 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_objc_method_definition_list): Reimplement + loop, make sure we pop scope. + +2020-09-11 Marek Polacek <polacek@redhat.com> + + * cp-tree.h (LOOKUP_CONSTINIT): Remove. + (LOOKUP_REWRITTEN): Adjust. + * decl.c (duplicate_decls): Set DECL_DECLARED_CONSTINIT_P. + (check_initializer): Use DECL_DECLARED_CONSTINIT_P instead of + LOOKUP_CONSTINIT. + (cp_finish_decl): Don't set DECL_DECLARED_CONSTINIT_P. Use + DECL_DECLARED_CONSTINIT_P instead of LOOKUP_CONSTINIT. + (grokdeclarator): Set DECL_DECLARED_CONSTINIT_P. + * decl2.c (grokfield): Don't handle LOOKUP_CONSTINIT. + * parser.c (cp_parser_decomposition_declaration): Remove + LOOKUP_CONSTINIT handling. + (cp_parser_init_declarator): Likewise. + * pt.c (tsubst_expr): Likewise. + (instantiate_decl): Likewise. + * typeck2.c (store_init_value): Use DECL_DECLARED_CONSTINIT_P instead + of LOOKUP_CONSTINIT. + +2020-09-10 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (TINFO_VAR_DECLARED_CONSTINIT): Replace with ... + (DECL_DECLARED_CONSTINIT_P): ... this. + * decl.c (start_decl): No need to retrofit_lang_decl for constinit + flag. + (cp_finish_decl): Use DECL_DECLARED_CONSTINIT_P. + * pt.c (tsubst_decl): No need to handle constinit flag + propagation. + (tsubst_expr): Or here. + +2020-09-10 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (DECL_LOCAL_FUNCTION_P): Rename to ... + (DECL_LOCAL_DECL_P): ... here. Accept both fns and vars. + * decl.c (start_decl): Set DECL_LOCAL_DECL_P for local externs. + (omp_declare_variant_finalize_one): Use DECL_LOCAL_DECL_P. + (local_variable_p): Simplify. + * name-lookup.c (set_decl_context_in_fn): Assert DECL_LOCAL_DECL_P + is as expected. Simplify. + (do_pushdecl): Don't set decl_context_in_fn for friends. + (is_local_extern): Simplify. + * call.c (equal_functions): Use DECL_LOCAL_DECL_P. + * parser.c (cp_parser_postfix_expression): Likewise. + (cp_parser_omp_declare_reduction): Likewise. + * pt.c (check_default_tmpl_args): Likewise. + (tsubst_expr): Assert nested reduction function is local. + (type_dependent_expression_p): Use DECL_LOCAL_DECL_P. + * semantics.c (finish_call_expr): Likewise. + +2020-09-09 Marek Polacek <polacek@redhat.com> + + PR c++/77841 + * decl.c (reshape_init): If we're initializing a char array from + a string-literal that is enclosed in braces, unwrap it. + * init.c (build_new_1): Don't handle string-initializers here. + (build_new): Handle new-expression with paren-init when the + array bound is known. Always pass string constants to build_new_1 + enclosed in braces. Don't handle string-initializers in any + special way. + +2020-09-09 Marek Polacek <polacek@redhat.com> + + PR c++/95164 + * decl.c (reshape_init_r): When initializing an aggregate member + with an initializer from an initializer-list, also consider + COMPOUND_LITERAL_P. + +2020-09-09 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_omp_declare_reduction): Refactor to avoid + code duplication. Update DECL_TI_TEMPLATE's context. + * pt.c (tsubst_expr): For OMP reduction function, set context to + global_namespace before pushing. + (tsubst_omp_udr): Assert current_function_decl, add comment about + decl context. + +2020-09-09 Patrick Palka <ppalka@redhat.com> + + PR c++/96647 + * class.c (resolve_address_of_overloaded_function): Check + constraints_satisfied_p and perform return-type deduction via + maybe_instantiate_decl when considering non-template functions + in the overload set. + * cp-tree.h (maybe_instantiate_decl): Declare. + * decl2.c (maybe_instantiate_decl): Remove static. + +2020-09-04 Jason Merrill <jason@redhat.com> + + * expr.c (mark_use): Use iloc_sentinel. + +2020-09-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/96901 + * constexpr.c (fundef_copies_table): Change type from + hash_map<tree, tree> * to decl_tree_map *. + +2020-09-03 Marek Polacek <polacek@redhat.com> + + PR c++/92812 + * cp-tree.h (do_aggregate_paren_init): Declare. + * decl.c (do_aggregate_paren_init): New. + (grok_reference_init): Use it. + (check_initializer): Likewise. + * init.c (perform_member_init): Handle initializing an array from + a ()-list. Use do_aggregate_paren_init. + +2020-09-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/96862 + * constexpr.c (cxx_eval_outermost_constant_expr): Temporarily disable + flag_rounding_math during manifestly constant evaluation. + +2020-09-01 Marek Polacek <polacek@redhat.com> + + PR c++/77841 + * init.c (build_new_1): Call reshape_init. + +2020-09-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/96867 + * semantics.c (handle_omp_array_sections_1): Test + DECL_ARRAY_PARAMETER_P only on PARM_DECLs. + +2020-08-31 Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/93529 + * call.c (build_new_method_call_1): Use build_constructor_from_vec + instead of build_tree_list_vec + build_constructor_from_list. + * init.c (build_new_1): Handle new char[]{"foo"}. Use + build_constructor_from_vec instead of build_tree_list_vec + + build_constructor_from_list. + (build_new): Deduce the array size in new-expression if not + present. Handle ()-init. Handle initializing an array from + a string literal. + * parser.c (cp_parser_new_type_id): Leave [] alone. + (cp_parser_direct_new_declarator): Allow []. + * pt.c (type_dependent_expression_p): In a NEW_EXPR, consider + array types whose dimension has to be deduced type-dependent. + +2020-08-27 Martin Liska <mliska@suse.cz> + + * class.c (build_vtbl_initializer): Set exact argument of a vector + growth function to true. + * constraint.cc (get_mapped_args): Likewise. + * decl.c (cp_maybe_mangle_decomp): Likewise. + (cp_finish_decomp): Likewise. + * parser.c (cp_parser_omp_for_loop): Likewise. + * pt.c (canonical_type_parameter): Likewise. + * rtti.c (get_pseudo_ti_init): Likewise. + +2020-08-26 Nathan Sidwell <nathan@acm.org> + + * decl.c (poplevel): A local-binding tree list holds the name in + TREE_PURPOSE. + * name-lookup.c (update_local_overload): Add id to TREE_PURPOSE. + (lookup_name_1): Deal with local-binding error_mark_node marker. + (op_unqualified_lookup): Return error_mark_node for 'nothing + found'. Retain global binding, check class binding here. + (maybe_save_operator_binding): Reimplement to always cache a + result. + (push_operator_bindings): Deal with 'ignore' marker. + +2020-08-25 Tobias Burnus <tobias@codesourcery.com> + + PR c/96678 + * semantics.c (handle_omp_array_sections_1): Talk about + array function parameter in the error message. + +2020-08-25 Jakub Jelinek <jakub@redhat.com> + + PR c++/96721 + * cp-tree.h (build_trivial_dtor_call): Add bool argument defaulted + to false. + * call.c (build_trivial_dtor_call): Add NO_PTR_DEREF argument. If + instance is a pointer and NO_PTR_DEREF is true, clobber the pointer + rather than what it points to. + * semantics.c (finish_call_expr): Call build_trivial_dtor_call with + true as NO_PTR_DEREF. + +2020-08-25 Jason Merrill <jason@redhat.com> + + PR c++/95428 + * optimize.c (populate_clone_array): Revert PR70462 change. + (maybe_clone_body): Likewise. + +2020-08-24 Nathan Sidwell <nathan@acm.org> + + * ptree.c (debug_overload): New. + +2020-08-19 Jason Merrill <jason@redhat.com> + + DR 2369 + * cp-tree.h (push_tinst_level, push_tinst_level_loc): Declare. + * constraint.cc (satisfy_declaration_constraints): + Use add_outermost_template_args and push_tinst_level. + * pt.c (add_outermost_template_args): Handle getting + a TEMPLATE_DECL as the first argument. + (push_tinst_level, push_tinst_level_loc): No longer static. + (fn_type_unification): Check satisfaction before non-dependent + conversions. + +2020-08-18 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (SET_TYPE_TEMPLTE_INFO): Do not deal with ALIAS templates. + * pt.c (lookup_template_class_1): Special-case alias template + template_info setting. + +2020-08-18 Jason Merrill <jason@redhat.com> + + PR c++/96199 + * pt.c (tsubst_aggr_type): Rewrite in C++17, too. + (maybe_dependent_member_ref): Likewise. + (build_deduction_guide): Re-substitute template parms. + * cp-tree.h (struct push_nested_class_guard): New. + * constraint.cc (get_normalized_constraints_from_decl): Use it. + +2020-08-18 Jason Merrill <jason@redhat.com> + + PR c++/96199 + * pt.c (maybe_dependent_member_ref): New. + (tsubst_copy) [CONST_DECL]: Use it. + [VAR_DECL]: Likewise. + (tsubst_aggr_type): Handle nested type. + +2020-08-18 Nathan Sidwell <nathan@acm.org> + + * name-lookup.c (qualify_lookup): Drop lambda checking here. + Reorder namespace & type checking. + (lookup_name_1): Do hidden lambda checking here. + +2020-08-14 Nathan Sidwell <nathan@acm.org> + + * name-lookup.h (lookup_name_real, lookup_name_nonclass): Rename + to ... + (lookup_name): ... these new overloads. + * name-lookup.c (identifier_type_value_1): Rename lookup_name_real + call. + (lookup_name_real_1): Rename to ... + (lookup_name_1): ... here. + (lookup_name_real): Rename to ... + (lookup_name): ... here. Rename lookup_name_real_1 call. + (lookup_name_nonclass): Delete. + * call.c (build_operator_new_call): Rename lookup_name_real call. + (add_operator_candidates): Likewise. + (build_op_delete_call): Rename lookup_name_nonclass call. + * parser.c (cp_parser_lookup_name): Likewise. + * pt.c (tsubst_friend_class, lookup_init_capture_pack): Likewise. + (tsubst_expr): Likewise. + * semantics.c (capture_decltype): Likewise. + +2020-08-14 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (LOOKUP_HIDDEN): Delete. + (LOOKUP_PREFER_RVALUE): Adjust initializer. + * name-lookup.h (enum class LOOK_want): Add HIDDEN_FRIEND and + HIDDEN_LAMBDA flags. + (lookup_name_real): Drop flags parm. + (lookup_qualified_name): Drop find_hidden parm. + * name-lookup.c (class name_lookup): Drop hidden field, adjust + ctors. + (name_lookup::add_overload): Check want for hiddenness. + (name_lookup::process_binding): Likewise. + (name_lookup::search_unqualified): Likewise. + (identifier_type_value_1): Adjust lookup_name_real call. + (set_decl_namespace): Adjust name_lookup ctor. + (qualify_lookup): Drop flags parm, use want for hiddenness. + (lookup_qualified_name): Drop find_hidden parm. + (lookup_name_real_1): Drop flags parm, adjust qualify_lookup + calls. + (lookup_name_real): Drop flags parm. + (lookup_name_nonclass, lookup_name): Adjust lookup_name_real + calls. + (lookup_type_scope_1): Adjust qualify_lookup calls. + * call.c (build_operator_new_call): Adjust lookup_name_real call. + (add_operator_candidates): Likewise. + * coroutines.cc (morph_fn_to_coro): Adjust lookup_qualified_name + call. + * parser.c (cp_parser_lookup_name): Adjust lookup_name_real calls. + * pt.c (check_explicit_specialization): Adjust + lookup_qualified_name call. + (deduction_guides_for): Likewise. + (tsubst_friend_class): Adjust lookup_name_real call. + (lookup_init_capture_pack): Likewise. + (tsubst_expr): Likewise, don't look in namespaces. + * semantics.c (capture_decltype): Adjust lookup_name_real. Don't + look in namespaces. + +2020-08-14 Jason Merrill <jason@redhat.com> + + PR c++/90254 + PR c++/93711 + * cp-tree.h (unsafe_return_slot_p): Declare. + * call.c (is_base_field_ref): Rename to unsafe_return_slot_p. + (build_over_call): Check unsafe_return_slot_p. + (build_special_member_call): Likewise. + * init.c (expand_default_init): Likewise. + * typeck2.c (split_nonconstant_init_1): Likewise. + +2020-08-14 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (LOOKUP_PREFER_TYPES, LOOKUP_PREFER_NAMESPACES) + (LOOKUP_NAMESPACES_ONLY, LOOKUP_TYPES_ONLY) + (LOOKUP_QUALIFIERS_ONL): Delete. + (LOOKUP_HIDDEN): Adjust. + * name-lookup.h (enum class LOOK_want): New. + (operator|, operator&): Overloads for it. + (lookup_name_real): Replace prefer_type & namespaces_only with + LOOK_want parm. + (lookup_qualified_name): Replace prefer_type with LOOK_want. + (lookup_name_prefer_type): Replace with ... + (lookup_name): ... this. New overload with LOOK_want parm. + * name-lookup.c (struct name_lookup): Replace flags with want and + hidden fields. Adjust constructors. + (name_lookyp::add_overload): Correct hidden stripping test. Update + for new LOOK_want type. + (name_lookup::process_binding): Likewise. + (name_lookup::search_unqualified): Use hidden flag. + (identifier_type_value_1): Adjust lookup_name_real call. + (set_decl_namespace): Adjust name_lookup ctor. + (lookup_flags): Delete. + (qualify_lookup): Add LOOK_want parm, adjust. + (lookup_qualified_name): Replace prefer_type parm with LOOK_want. + (lookup_name_real_1): Replace prefer_type and namespaces_only with + LOOK_want parm. + (lookup_name_real): Likewise. + (lookup_name_nonclass, lookup_name): Adjust lookup_name_real call. + (lookup_name_prefer_type): Rename to ... + (lookup_name): ... here. New overload with LOOK_want parm. + (lookup_type_scope_1): Adjust qualify_lookup calls. + * call.c (build_operator_new_call) + (add_operator_candidates): Adjust lookup_name_real calls. + * coroutines.cc (find_coro_traits_template_decl) + (find_coro_handle_template_decl, morph_fn_to_coro): Adjust + lookup_qualified_name calls. + * cp-objcp-common.c (identifier_global_tag): Likewise. + * decl.c (get_tuple_size, get_tuple_decomp_init): Likewise. + (lookup_and_check_tag): Use lookup_name overload. + * parser.c (cp_parser_userdef_numeric_literal): Adjust + lookup_qualified_name call. + (prefer_arg_type): Drop template_mem_access parm, return LOOK_want + value. + (cp_parser_lookup_name): Adjust lookup_member, lookup_name_real + calls. + * pt.c (check_explicit_specialization): Adjust lookup_qualified_name + call. + (tsubst_copy_and_build, tsubst_qualified_name): Likewise + (deduction_guides_for): Likewise. + (tsubst_friend_class): Adjust lookup_name_real call. + (lookup_init_capture, tsubst_expr): Likewise. + * rtti.c (emit_support_tinfos): Adjust lookup_qualified_name call. + * semantics.c (omp_reduction_lookup): Likewise. + (capture_decltype): Adjust lookup_name_real call. + +2020-08-13 Nathan Sidwell <nathan@acm.org> + + * name-lookup.h (enum class LOOK_where): New. + (operator|, operator&): Overloads for it. + (lookup_name_real): Replace NONCLASS & BLOCK_P parms with WHERE. + * name-lookup.c (identifier_type_value_w): Adjust + lookup_name_real call. + (lookup_name_real_1): Replace NONCLASS and BLOCK_P parameters + with WHERE bitmask. Don't search namespaces if not asked to. + (lookup_name_real): Adjust lookup_name_real_1 call. + (lookup_name_nonclass, lookup_name) + (lookup_name_prefer_type): Likewise. + * call.c (build_operator_new_call) + (add_operator_candidates): Adjust lookup_name_real calls. + * parser.c (cp_parser_lookup_name): Likewise. + * pt.c (tsubst_friend_class, lookup_init_capture_pack) + (tsubst_expr): Likewise. + * semantics.c (capture_decltype): Likewise. + +2020-08-13 Marek Polacek <polacek@redhat.com> + + PR c++/92812 + * typeck.c (build_static_cast_1): Implement P1975R0 by allowing + static_cast to aggregate type. + +2020-08-10 Jakub Jelinek <jakub@redhat.com> + + PR c++/96497 + * constexpr.c (cxx_eval_binary_expression): For SPACESHIP_EXPR, tail + call cxx_eval_constant_expression after genericize_spaceship to avoid + undesirable further VERIFY_CONSTANT. + +2020-08-10 Patrick Palka <ppalka@redhat.com> + + * pt.c (resolve_overloaded_unification): Drop functions with + unsatisfied constraints. + (resolve_nondeduced_context): Likewise. + +2020-08-05 Patrick Palka <ppalka@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/96282 + * constexpr.c (cxx_eval_vec_init_1): Truncate ctx->ctor and + then clear CONSTRUCTOR_NO_CLEARING on each appended element + initializer if we're initializing a previously zero-initialized + array object. + +2020-08-04 Marek Polacek <polacek@redhat.com> + + PR c++/96082 + * parser.c (cp_parser_elaborated_type_specifier): Allow + 'template' following ::. + +2020-08-04 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_explicit_specialization): Refactor + to avoid leak of num_template_parameter_lists value. + +2020-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/94024 + * init.c (sort_mem_initializers): Preserve TREE_TYPE of the + member initializer list node. + (emit_mem_initializers): Set input_location when performing each + member initialization. + * parser.c (cp_parser_mem_initializer): Attach the source + location of this initializer to a dummy EMPTY_CLASS_EXPR + within the TREE_TYPE of the list node. + * pt.c (tsubst_initializer_list): Preserve TREE_TYPE of the + member initializer list node. + +2020-08-03 Marek Polacek <polacek@redhat.com> + + * cp-tree.h (after_nsdmi_defaulted_late_checks): Remove. + +2020-08-03 Marek Polacek <polacek@redhat.com> + + DR 2032 + PR c++/96218 + * pt.c (check_default_tmpl_args): Also consider variable + templates. + +2020-07-31 Jakub Jelinek <jakub@redhat.com> + + PR c++/96182 + * decl.c (finish_function): In constexpr functions use for C++14 and + later error instead of warning if no return statement is present and + diagnose it regardless of warn_return_type. Move the warn_return_type + diagnostics earlier in the function. + +2020-07-31 Martin Sebor <msebor@redhat.com> + + PR c++/96003 + * class.c (build_base_path): Set no-warning bit on the synthesized + conditional expression in static_cast. + +2020-07-31 Richard Biener <rguenther@suse.de> + + PR debug/96383 + * cp-objcp-common.h (LANG_HOOKS_FINALIZE_EARLY_DEBUG): + Define to c_common_finalize_early_debug. + +2020-07-31 Patrick Palka <ppalka@redhat.com> + + PR c++/96197 + * constexpr.c (cxx_eval_constant_expression) <case CONST_DECL>: + Pass false to decl_constant_value and decl_really_constant_value + so that they don't unshare their result. + * cp-tree.h (decl_constant_value): New declaration with an added + bool parameter. + (decl_really_constant_value): Add bool parameter defaulting to + true to existing declaration. + * init.c (constant_value_1): Add bool parameter which controls + whether to unshare the initializer before returning. Call + unshare_expr at most once. + (scalar_constant_value): Pass true to constant_value_1's new + bool parameter. + (decl_really_constant_value): Add bool parameter and forward it + to constant_value_1. + (decl_constant_value): Likewise, but instead define a new + overload with an added bool parameter. + +2020-07-30 Patrick Palka <ppalka@redhat.com> + + PR c++/64194 + * pt.c (resolve_overloaded_unification): If the function + template specialization has a placeholder return type, + then instantiate it before attempting unification. + +2020-07-30 Patrick Palka <ppalka@redhat.com> + + PR c++/95486 + * pt.c (alias_ctad_tweaks): Call remove_constraints before + calling set_constraints. + +2020-07-30 Patrick Palka <ppalka@redhat.com> + + PR c++/96106 + * pt.c (reduce_template_parm_level): Propagate DECL_VIRTUAL_P + from the original TEMPLATE_PARM_DECL to the new lowered one. + +2020-07-30 Patrick Palka <ppalka@redhat.com> + + PR c++/96164 + * constraint.cc (constraints_satisfied_p): Return true if + !flags_concepts. + * pt.c (do_type_instantiation): Update a paragraph taken from + [temp.explicit] to reflect the latest specification. Don't + instantiate a member with unsatisfied constraints. + +2020-07-29 Jason Merrill <jason@redhat.com> + + PR c++/91427 + * cp-tree.h (IMPLICIT_RVALUE_P): New. + (enum cp_lvalue_kind_flags): Add clk_implicit_rval. + (implicit_rvalue_p, set_implicit_rvalue_p): New. + * call.c (reference_binding): Check clk_implicit_rval. + (build_over_call): Adjust C++20 implicit move. + * coroutines.cc (finish_co_return_stmt): Simplify implicit move. + * except.c (build_throw): Adjust C++20 implicit move. + * pt.c (tsubst_copy_and_build) [STATIC_CAST_EXPR]: Propagate + IMPLICIT_RVALUE_P. + * tree.c (lvalue_kind): Set clk_implicit_rval. + * typeck.c (treat_lvalue_as_rvalue_p): Overhaul. + (maybe_warn_pessimizing_move): Adjust. + (check_return_expr): Adjust C++20 implicit move. + +2020-07-29 Jason Merrill <jason@redhat.com> + + PR c++/91212 + * call.c (build_over_call): Don't call a const ref + overload for implicit move. + +2020-07-28 Nathan Sidwell <nathan@acm.org> + + * cp-gimplify.c (cp_genericize_r): Set IMPORTED_DECL's context. + * cp-objcp-common.c (cp_pushdecl): Set decl's context. + * decl.c (grokfndecl): Make DECL_CONTEXT setting clearer. + +2020-07-28 Nathan Sidwell <nathan@acm.org> + + * class.c (fixup_type_variants): Copy TYPE_SIZE and + TYPE_SIZE_UINIT. + (finish_struct): Call it. + +2020-07-28 Nathan Sidwell <nathan@acm.org> + + * ptree.c (cxx_print_decl): Better indentation. + +2020-07-28 Jakub Jelinek <jakub@redhat.com> + Mark Wielaard <mark@klomp.org> + + PR c++/96328 + * parser.c (cp_lexer_safe_previous_token): Don't call + cp_lexer_previous_token, instead inline it by hand and return NULL + instead of failing assertion if all previous tokens until the first + one are purged. + (cp_parser_error_1): Optimize - only call cp_lexer_safe_previous_token + if token->type is CPP_NAME. Use cp_lexer_safe_previous_token instead + of cp_lexer_previous_token for the missing_token_desc != RT_NONE + case too. + +2020-07-27 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (enum cp_tree_index): Add CPTI_AS_BASE_IDENTIFIER. + (as_base_identifier): Define. + * decl.c (initialize_predifined_identifiers): Initialize as_base + identifier. + * class.c (layout_class_type): Name the as-base type. Zap + NSDMI its fields may have. + +2020-07-22 Nathan Sidwell <nathan@acm.org> + + * class.c (maybe_add_class_template_decl_list): Don't add CONST_DECLs. + +2020-07-22 Nathan Sidwell <nathan@acm.org> + + * typeck.c (structural_comptypes): [DECLTYPE_TYPE] break + apart complex if. + [UNDERLYING_TYPE]: Use an if. + [TYPEOF_TYPE]: New. + +2020-07-22 Nathan Sidwell <nathan@acm.org> + + * decl.c (decls_match): Move variables into scopes + they're needed in. + (duplicate_decls): Use STRIP_TEMPLATE. + (build_typename_type): Move var decls to their assignments. + (begin_function_body): Likewise. + * decl2.c (get_guard): Likewise. + (mark_used): Use true for truthiness. + * error.c (dump_aggr_type): Hold the decl in a var called + 'decl', not 'name'. + +2020-07-22 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h (struct tree_lambda_expr): Shrink + default_capture_mode & discriminator. + +2020-07-22 Nathan Sidwell <nathan@acm.org> + + * mangle.c (decl_is_template_id): Rename to ... + (maybe_template_info): ... here. Return the template info, + rather than use a pointer. Adjust all callers. + (find_substitution): Use template_args_equal, rather than + local check. + +2020-07-22 Tobias Burnus <tobias@codesourcery.com> + + * parser.c (cp_parser_omp_clause_hint): Require nonnegative hint. + (cp_parser_omp_critical): Permit hint(0) clause without named critical. + * pt.c (tsubst_expr): Re-check the latter for templates. + +2020-07-21 Sunil K Pandey <skpgkp2@gmail.com> + + PR target/95237 + * decl.c (cp_finish_decl): Call target hook + lower_local_decl_alignment to lower local decl alignment. + +2020-07-21 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_lexer_consume_token): Drop PRAGMA_EOL assert. + (cp_parser_skip_to_closing_parenthesis_1): Only pass start token + to pragma skipper if recovering. + (cp_parser_skip_to_pragma_eol): Only purge and change pragma + state when recovering. + +2020-07-20 Jason Merrill <jason@redhat.com> + + * pt.c (type_dependent_expression_p): A pseudo-dtor can be + dependent. + * semantics.c (finish_call_expr): Use build_trivial_dtor_call for + pseudo-destructor. + (finish_pseudo_destructor_expr): Leave type NULL for dependent arg. + +2020-07-20 Jason Merrill <jason@redhat.com> + + * mangle.c (write_base_ref): New. + (write_expression): Use it for base field COMPONENT_REFs. + * pt.c (invalid_tparm_referent_p): Canonicalize the type + of array offsets. Allow subobjects. + +2020-07-20 Jason Merrill <jason@redhat.com> + + * pt.c (collect_ctor_idx_types): Add 'const' when deducing from + a string constant. + +2020-07-17 Marek Polacek <polacek@redhat.com> + + PR c++/79815 + * decl.c (grokdeclarator): Detect cv-qual decltype(auto). + * pt.c (do_auto_deduction): Likewise. + +2020-07-16 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/95591 + PR c++/95599 + PR c++/95823 + PR c++/95824 + PR c++/95895 + * coroutines.cc (struct coro_ret_data): Delete. + (coro_maybe_expand_co_return): Delete. + (co_return_expander): Delete. + (expand_co_returns): Delete. + (co_await_find_in_subtree): Remove unused name. + (build_actor_fn): Remove unused parm, remove handling + for co_return expansion. + (register_await_info): Demote duplicate info message to a + warning. + (coro_make_frame_entry): Move closer to use site. + (struct susp_frame_data): Add fields for final suspend label + and a flag to indicate await expressions with initializers. + (captures_temporary): Delete. + (register_awaits): Remove unused code, update comments. + (find_any_await): New. + (tmp_target_expr_p): New. + (struct interesting): New. + (find_interesting_subtree): New. + (struct var_nest_node): New. + (flatten_await_stmt): New. + (handle_nested_conditionals): New. + (process_conditional): New. + (replace_statement_captures): Rename to... + (maybe_promote_temps): ... this. + (maybe_promote_captured_temps): Delete. + (analyze_expression_awaits): Check for await expressions with + initializers. Simplify handling for truth-and/or-if. + (expand_one_truth_if): Simplify (map cases that need expansion + to COND_EXPR). + (await_statement_walker): Handle CO_RETURN_EXPR. Simplify the + handling for truth-and/or-if expressions. + (register_local_var_uses): Ensure that we create names in the + implementation namespace. + (morph_fn_to_coro): Add final suspend label to suspend frame + callback data and remove it from the build_actor_fn call. + +2020-07-16 Marek Polacek <polacek@redhat.com> + + * call.c (convert_like): Remove macro and introduce a new + wrapper instead. + (convert_like_with_context): Likewise. + (convert_like_real): Rename to convert_like. + (convert_like_real_1): Rename to convert_like_internal. Call + convert_like instead of convert_like_real therein. + (perform_direct_initialization_if_possible): Call convert_like + instead of convert_like_real. + +2020-07-16 Iain Sandoe <iain@sandoe.co.uk> + + * coroutines.cc: Correct some spelling errors + in comments. + +2020-07-15 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_declaration): Avoid copying tokens. + (cp_parser_block_declaration): RAII token pointer. + +2020-07-15 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_parser_skip_to_closing_parenthesis_1): Deal with + meeting a deferred pragma. + (cp_parser_skip_to_end_of_statement): Likewise. + (cp_parser_skip_to_end_of_block_or_statement): Likewise. + (cp_parser_skip_to_pragma_eol): We should never meet EOF. + (cp_parser_omp_declare_simd): Likewise. + (cp_parser_omp_declare_reduction, cp_parser_oacc_routine) + (pragma_lex): Likewise. + +2020-07-14 Marek Polacek <polacek@redhat.com> + + PR c++/95789 + PR c++/96104 + PR c++/96179 + * call.c (convert_like_real_1): Renamed from convert_like_real. + (convert_like_real): New wrapper for convert_like_real_1. + +2020-07-14 Nathan Sidwell <nathan@acm.org> + + * parser.c (cp_lexer_alloc): Do not deal with PCH here. + (cp_lexer_new_main): Deal with PCH here. Store the tokens directly + into the buffer. + (cp_lexer_new_from_tokens): Assert last token isn't purged either. + (cp_lexer_get_preprocessor_token): Change first arg to flags, adjust. + (cp_parser_new): Pass the lexer in, don't create it here. + (cp_parser_translation_unit): Initialize access checks here. + (cp_parser_initial_pragma): First token is provided by caller, + don't deal with PCH stopping here. Adjust error message. + (c_parse_file): Adjust, change error message to avoid C++20 module + confusion. + +2020-07-14 Nathan Sidwell <nathan@acm.org> + + * ptree.c (cxx_print_type): Add TYPEOF_TYPE and BASES. + +2020-07-14 Nathan Sidwell <nathan@acm.org> + + * class.c (build_base_field_1): Cache CLASSTYPE_AS_BASE. + (build_self_reference): Rename value -> decl. + (dump_class_hierarchy_1): Cache CLASSTYPE_AS_BASE. + +2020-07-14 Marek Polacek <polacek@redhat.com> + + PR c++/95820 + * decl.c (grokdeclarator) <case cdk_function>: Check also + pointers/references/... to functions. + +2020-07-14 Nathan Sidwell <nathan@acm.org> + + * cp-tree.h: Correct some tree lang flag comments, + reformat some structure definitions. Note some structure + sizes. Clarify some comments. + (yyungetc): Delete. Not been a thing for some time. + * class.c (copy_fndecl_with_name): Comment. + (check_bases_and_members): Unnecessary {}. + (layout_class_type): Comment. + * cp-tree.def (UNBOUND_CLASS_TEMPLATE): Adjust comment. + * decl.c: Fix some formatting & whitespace issues. + (function_requirements_equivalent_p): Note why + substitutions are needed. + * decl2.c (no_linkage_error): Note that heroics about + 'typedef struct { ... };' are no longer needed. + * method.c: Whitespace. + * name-lookup.c: Whitespace. + (add_decl_to_level): Reformat a line. + (print_binding_stack): Mark as DEBUG_FUNCTION. + (has_using_namespace_std_directive_p): Delete comment. + * pt.c: Whitespace + * ptree.c: Whitespace. + * rtti.c: Whitespace & comment. + * tree.c: Comment. + * typeck.c (structural_comptypes): Add comment. + +2020-07-13 Nathan Sidwell <nathan@acm.org> + + * Make-lang.in (c++.disclean): Likewise. + +2020-07-13 Marek Polacek <polacek@redhat.com> + + PR c++/96077 + * parser.c (cp_parser_enum_specifier): Commit to tentative parse + after we've seen an opening brace. + 2020-07-10 Jason Merrill <jason@redhat.com> * tree.c (structural_type_p): Allow unions. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 7896591..6ee4e41 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -287,7 +287,6 @@ c++.mostlyclean: c++.clean: c++.distclean: -rm -f cp/config.status cp/Makefile - -rm -f cxxmain.c c++.maintainer-clean: # # Stage hooks: diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5341a57..bd66251 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -161,16 +161,9 @@ static int compare_ics (conversion *, conversion *); static void maybe_warn_class_memaccess (location_t, tree, const vec<tree, va_gc> *); static tree build_over_call (struct z_candidate *, int, tsubst_flags_t); -#define convert_like(CONV, EXPR, COMPLAIN) \ - convert_like_real ((CONV), (EXPR), NULL_TREE, 0, \ - /*issue_conversion_warnings=*/true, \ - /*c_cast_p=*/false, (COMPLAIN)) -#define convert_like_with_context(CONV, EXPR, FN, ARGNO, COMPLAIN ) \ - convert_like_real ((CONV), (EXPR), (FN), (ARGNO), \ - /*issue_conversion_warnings=*/true, \ - /*c_cast_p=*/false, (COMPLAIN)) -static tree convert_like_real (conversion *, tree, tree, int, bool, - bool, tsubst_flags_t); +static tree convert_like (conversion *, tree, tsubst_flags_t); +static tree convert_like_with_context (conversion *, tree, tree, int, + tsubst_flags_t); static void op_error (const op_location_t &, enum tree_code, enum tree_code, tree, tree, tree, bool); static struct z_candidate *build_user_type_conversion_1 (tree, tree, int, @@ -1233,7 +1226,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, { from = type_decays_to (from); fcode = TREE_CODE (from); - /* Tell convert_like_real that we're using the address. */ + /* Tell convert_like that we're using the address. */ conv->rvaluedness_matches_p = true; conv = build_conv (ck_lvalue, from, conv); } @@ -1254,7 +1247,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, } conv = build_conv (ck_rvalue, from, conv); if (flags & LOOKUP_PREFER_RVALUE) - /* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */ + /* Tell convert_like to set LOOKUP_PREFER_RVALUE. */ conv->rvaluedness_matches_p = true; /* If we're performing copy-initialization, remember to skip explicit constructors. */ @@ -1534,7 +1527,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, the conversion unless we're binding directly to a reference. */ conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND); if (flags & LOOKUP_PREFER_RVALUE) - /* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */ + /* Tell convert_like to set LOOKUP_PREFER_RVALUE. */ conv->rvaluedness_matches_p = true; /* If we're performing copy-initialization, remember to skip explicit constructors. */ @@ -1829,6 +1822,9 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, /* Nor the reverse. */ if (!is_lvalue && !TYPE_REF_IS_RVALUE (rto) + /* Unless it's really an lvalue. */ + && !(cxx_dialect >= cxx20 + && (gl_kind & clk_implicit_rval)) && (!CP_TYPE_CONST_NON_VOLATILE_P (to) || (flags & LOOKUP_NO_RVAL_BIND)) && TREE_CODE (to) != FUNCTION_TYPE) @@ -2224,11 +2220,6 @@ add_function_candidate (struct z_candidate **candidates, int viable = 1; struct rejection_reason *reason = NULL; - /* At this point we should not see any functions which haven't been - explicitly declared, except for friend functions which will have - been found using argument dependent lookup. */ - gcc_assert (!DECL_ANTICIPATED (fn) || DECL_HIDDEN_FRIEND_P (fn)); - /* The `this', `in_chrg' and VTT arguments to constructors are not considered in overload resolution. */ if (DECL_CONSTRUCTOR_P (fn)) @@ -2497,7 +2488,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj, t = build_identity_conv (argtype, NULL_TREE); t = build_conv (ck_user, totype, t); /* Leave the 'cand' field null; we'll figure out the conversion in - convert_like_real if this candidate is chosen. */ + convert_like if this candidate is chosen. */ convert_type = totype; } else if (parmnode == void_list_node) @@ -3635,7 +3626,7 @@ equal_functions (tree fn1, tree fn2) return 0; if (TREE_CODE (fn1) == TEMPLATE_DECL) return fn1 == fn2; - if (DECL_LOCAL_FUNCTION_P (fn1) || DECL_LOCAL_FUNCTION_P (fn2) + if (DECL_LOCAL_DECL_P (fn1) || DECL_LOCAL_DECL_P (fn2) || DECL_EXTERN_C_FUNCTION_P (fn1)) return decls_match (fn1, fn2); return fn1 == fn2; @@ -4708,7 +4699,7 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args, up in the global scope. we disregard block-scope declarations of "operator new". */ - fns = lookup_name_real (fnname, 0, 1, /*block_p=*/false, 0, 0); + fns = lookup_name (fnname, LOOK_where::NAMESPACE); fns = lookup_arg_dependent (fnname, fns, *args); if (align_arg) @@ -4778,7 +4769,16 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args, *fn = cand->fn; /* Build the CALL_EXPR. */ - return build_over_call (cand, LOOKUP_NORMAL, complain); + tree ret = build_over_call (cand, LOOKUP_NORMAL, complain); + + /* Set this flag for all callers of this function. In addition to + new-expressions, this is called for allocating coroutine state; treat + that as an implicit new-expression. */ + tree call = extract_call_expr (ret); + if (TREE_CODE (call) == CALL_EXPR) + CALL_FROM_NEW_OR_DELETE_P (call) = 1; + + return ret; } /* Build a new call to operator(). This may change ARGS. */ @@ -5986,7 +5986,7 @@ add_operator_candidates (z_candidate **candidates, consider. */ if (!memonly) { - tree fns = lookup_name_real (fnname, 0, 1, /*block_p=*/true, 0, 0); + tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); fns = lookup_arg_dependent (fnname, fns, arglist); add_candidates (fns, NULL_TREE, arglist, NULL_TREE, NULL_TREE, false, NULL_TREE, NULL_TREE, @@ -6155,7 +6155,7 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, case VEC_NEW_EXPR: case VEC_DELETE_EXPR: case DELETE_EXPR: - /* Use build_op_new_call and build_op_delete_call instead. */ + /* Use build_operator_new_call and build_op_delete_call instead. */ gcc_unreachable (); case CALL_EXPR: @@ -6348,11 +6348,6 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, tree call = extract_call_expr (result); CALL_EXPR_OPERATOR_SYNTAX (call) = true; - if (processing_template_decl && DECL_HIDDEN_FRIEND_P (cand->fn)) - /* This prevents build_new_function_call from discarding this - function during instantiation of the enclosing template. */ - KOENIG_LOOKUP_P (call) = 1; - /* Specify evaluation order as per P0145R2. */ CALL_EXPR_ORDERED_ARGS (call) = false; switch (op_is_ordered (code)) @@ -6815,7 +6810,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, fns = NULL_TREE; if (fns == NULL_TREE) - fns = lookup_name_nonclass (fnname); + fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); /* Strip const and volatile from addr. */ tree oaddr = addr; @@ -6997,6 +6992,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, if (DECL_DELETED_FN (fn) && alloc_fn) return NULL_TREE; + tree ret; if (placement) { /* The placement args might not be suitable for overload @@ -7009,7 +7005,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, argarray[i] = CALL_EXPR_ARG (placement, i); if (!mark_used (fn, complain) && !(complain & tf_error)) return error_mark_node; - return build_cxx_call (fn, nargs, argarray, complain); + ret = build_cxx_call (fn, nargs, argarray, complain); } else { @@ -7027,7 +7023,6 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, complain); } - tree ret; releasing_vec args; args->quick_push (addr); if (destroying) @@ -7040,8 +7035,18 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, args->quick_push (al); } ret = cp_build_function_call_vec (fn, &args, complain); - return ret; } + + /* Set this flag for all callers of this function. In addition to + delete-expressions, this is called for deallocating coroutine state; + treat that as an implicit delete-expression. This is also called for + the delete if the constructor throws in a new-expression, and for a + deleting destructor (which implements a delete-expression). */ + tree call = extract_call_expr (ret); + if (TREE_CODE (call) == CALL_EXPR) + CALL_FROM_NEW_OR_DELETE_P (call) = 1; + + return ret; } /* [expr.new] @@ -7281,6 +7286,10 @@ maybe_warn_array_conv (location_t loc, conversion *c, tree expr) "are only available with %<-std=c++20%> or %<-std=gnu++20%>"); } +/* We call this recursively in convert_like_internal. */ +static tree convert_like (conversion *, tree, tree, int, bool, bool, + tsubst_flags_t); + /* Perform the conversions in CONVS on the expression EXPR. FN and ARGNUM are used for diagnostics. ARGNUM is zero based, -1 indicates the `this' argument of a method. INNER is nonzero when @@ -7292,9 +7301,9 @@ maybe_warn_array_conv (location_t loc, conversion *c, tree expr) conversions to inaccessible bases are permitted. */ static tree -convert_like_real (conversion *convs, tree expr, tree fn, int argnum, - bool issue_conversion_warnings, - bool c_cast_p, tsubst_flags_t complain) +convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, + bool issue_conversion_warnings, bool c_cast_p, + tsubst_flags_t complain) { tree totype = convs->type; diagnostic_t diag_kind; @@ -7348,10 +7357,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, totype); if (complained) print_z_candidate (loc, N_("candidate is:"), t->cand); - expr = convert_like_real (t, expr, fn, argnum, - /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, - complain); + expr = convert_like (t, expr, fn, argnum, + /*issue_conversion_warnings=*/false, + /*c_cast_p=*/false, complain); if (convs->kind == ck_ref_bind) expr = convert_to_reference (totype, expr, CONV_IMPLICIT, LOOKUP_NORMAL, NULL_TREE, @@ -7364,17 +7372,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, } else if (t->kind == ck_user || !t->bad_p) { - expr = convert_like_real (t, expr, fn, argnum, - /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, - complain); + expr = convert_like (t, expr, fn, argnum, + /*issue_conversion_warnings=*/false, + /*c_cast_p=*/false, complain); break; } else if (t->kind == ck_ambig) - return convert_like_real (t, expr, fn, argnum, - /*issue_conversion_warnings=*/false, - /*c_cast_p=*/false, - complain); + return convert_like (t, expr, fn, argnum, + /*issue_conversion_warnings=*/false, + /*c_cast_p=*/false, complain); else if (t->kind == ck_identity) break; } @@ -7395,19 +7401,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, if (issue_conversion_warnings && (complain & tf_warning)) conversion_null_warnings (totype, expr, fn, argnum); - /* Creating &TARGET_EXPR<> in a template breaks when substituting, - and creating a CALL_EXPR in a template breaks in finish_call_expr - so use an IMPLICIT_CONV_EXPR for this conversion. We would have - created such codes e.g. when calling a user-defined conversion - function. */ - if (processing_template_decl - && convs->kind != ck_identity - && (CLASS_TYPE_P (totype) || CLASS_TYPE_P (TREE_TYPE (expr)))) - { - expr = build1 (IMPLICIT_CONV_EXPR, totype, expr); - return convs->kind == ck_ref_bind ? expr : convert_from_reference (expr); - } - switch (convs->kind) { case ck_user: @@ -7545,8 +7538,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* Convert all the elements. */ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) { - tree sub = convert_like_real (convs->u.list[ix], val, fn, - argnum, false, false, complain); + tree sub = convert_like (convs->u.list[ix], val, fn, + argnum, false, false, complain); if (sub == error_mark_node) return sub; if (!BRACE_ENCLOSED_INITIALIZER_P (val) @@ -7611,10 +7604,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, break; }; - expr = convert_like_real (next_conversion (convs), expr, fn, argnum, - convs->kind == ck_ref_bind - ? issue_conversion_warnings : false, - c_cast_p, complain); + expr = convert_like (next_conversion (convs), expr, fn, argnum, + convs->kind == ck_ref_bind + ? issue_conversion_warnings : false, + c_cast_p, complain); if (expr == error_mark_node) return error_mark_node; @@ -7869,6 +7862,61 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, return expr; } +/* Wrapper for convert_like_internal that handles creating + IMPLICIT_CONV_EXPR. */ + +static tree +convert_like (conversion *convs, tree expr, tree fn, int argnum, + bool issue_conversion_warnings, bool c_cast_p, + tsubst_flags_t complain) +{ + /* Creating &TARGET_EXPR<> in a template breaks when substituting, + and creating a CALL_EXPR in a template breaks in finish_call_expr + so use an IMPLICIT_CONV_EXPR for this conversion. We would have + created such codes e.g. when calling a user-defined conversion + function. */ + tree conv_expr = NULL_TREE; + if (processing_template_decl + && convs->kind != ck_identity + && (CLASS_TYPE_P (convs->type) || CLASS_TYPE_P (TREE_TYPE (expr)))) + { + conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr); + if (convs->kind != ck_ref_bind) + conv_expr = convert_from_reference (conv_expr); + if (!convs->bad_p) + return conv_expr; + /* Do the normal processing to give the bad_p errors. But we still + need to return the IMPLICIT_CONV_EXPR, unless we're returning + error_mark_node. */ + } + expr = convert_like_internal (convs, expr, fn, argnum, + issue_conversion_warnings, c_cast_p, complain); + if (expr == error_mark_node) + return error_mark_node; + return conv_expr ? conv_expr : expr; +} + +/* Convenience wrapper for convert_like. */ + +static inline tree +convert_like (conversion *convs, tree expr, tsubst_flags_t complain) +{ + return convert_like (convs, expr, NULL_TREE, 0, + /*issue_conversion_warnings=*/true, + /*c_cast_p=*/false, complain); +} + +/* Convenience wrapper for convert_like. */ + +static inline tree +convert_like_with_context (conversion *convs, tree expr, tree fn, int argnum, + tsubst_flags_t complain) +{ + return convert_like (convs, expr, fn, argnum, + /*issue_conversion_warnings=*/true, + /*c_cast_p=*/false, complain); +} + /* ARG is being passed to a varargs function. Perform any conversions required. Return the converted value. */ @@ -8307,24 +8355,34 @@ call_copy_ctor (tree a, tsubst_flags_t complain) return r; } -/* Return true iff T refers to a base field. */ +/* Return true iff T refers to a base or potentially-overlapping field, which + cannot be used for return by invisible reference. We avoid doing C++17 + mandatory copy elision when this is true. -static bool -is_base_field_ref (tree t) + This returns true even if the type of T has no tail padding that other data + could be allocated into, because that depends on the particular ABI. + unsafe_copy_elision_p, below, does consider whether there is padding. */ + +bool +unsafe_return_slot_p (tree t) { STRIP_NOPS (t); if (TREE_CODE (t) == ADDR_EXPR) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == COMPONENT_REF) t = TREE_OPERAND (t, 1); - if (TREE_CODE (t) == FIELD_DECL) - return DECL_FIELD_IS_BASE (t); - return false; + if (TREE_CODE (t) != FIELD_DECL) + return false; + if (!CLASS_TYPE_P (TREE_TYPE (t))) + /* The middle-end will do the right thing for scalar types. */ + return false; + return (DECL_FIELD_IS_BASE (t) + || lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t))); } -/* We can't elide a copy from a function returning by value to a base - subobject, as the callee might clobber tail padding. Return true iff this - could be that case. */ +/* We can't elide a copy from a function returning by value to a + potentially-overlapping subobject, as the callee might clobber tail padding. + Return true iff this could be that case. */ static bool unsafe_copy_elision_p (tree target, tree exp) @@ -8334,10 +8392,11 @@ unsafe_copy_elision_p (tree target, tree exp) return false; tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp)); /* It's safe to elide the copy for a class with no tail padding. */ - if (tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type))) + if (!is_empty_class (type) + && tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type))) return false; /* It's safe to elide the copy if we aren't initializing a base object. */ - if (!is_base_field_ref (target)) + if (!unsafe_return_slot_p (target)) return false; tree init = TARGET_EXPR_INITIAL (exp); /* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR. */ @@ -8379,11 +8438,35 @@ conv_binds_ref_to_prvalue (conversion *c) return false; } +/* True iff converting EXPR to a reference type TYPE does not involve + creating a temporary. */ + +bool +ref_conv_binds_directly_p (tree type, tree expr) +{ + gcc_assert (TYPE_REF_P (type)); + + /* Get the high-water mark for the CONVERSION_OBSTACK. */ + void *p = conversion_obstack_alloc (0); + + conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr, + /*c_cast_p=*/false, + LOOKUP_IMPLICIT, tf_none); + bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv); + + /* Free all the conversions we allocated. */ + obstack_free (&conversion_obstack, p); + + return ret; +} + /* Call the trivial destructor for INSTANCE, which can be either an lvalue of - class type or a pointer to class type. */ + class type or a pointer to class type. If NO_PTR_DEREF is true and + INSTANCE has pointer type, clobber the pointer rather than what it points + to. */ tree -build_trivial_dtor_call (tree instance) +build_trivial_dtor_call (tree instance, bool no_ptr_deref) { gcc_assert (!is_dummy_object (instance)); @@ -8393,7 +8476,8 @@ build_trivial_dtor_call (tree instance) return fold_convert (void_type_node, instance); } - if (INDIRECT_TYPE_P (TREE_TYPE (instance))) + if (INDIRECT_TYPE_P (TREE_TYPE (instance)) + && (!no_ptr_deref || TYPE_REF_P (TREE_TYPE (instance)))) { if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (instance)))) goto no_clobber; @@ -8529,6 +8613,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) && DECL_COMPLETE_CONSTRUCTOR_P (fn) && (DECL_COPY_CONSTRUCTOR_P (fn) || DECL_MOVE_CONSTRUCTOR_P (fn)) + && !unsafe_return_slot_p (first_arg) && conv_binds_ref_to_prvalue (convs[0])) { force_elide = true; @@ -8642,15 +8727,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) parm = TREE_CHAIN (parm); } - if (flags & LOOKUP_PREFER_RVALUE) + if (cxx_dialect < cxx20 + && (cand->flags & LOOKUP_PREFER_RVALUE)) { /* The implicit move specified in 15.8.3/3 fails "...if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified)...." */ gcc_assert (!(complain & tf_error)); tree ptype = convs[0]->type; - if (!TYPE_REF_P (ptype) - || !TYPE_REF_IS_RVALUE (ptype) + /* Allow calling a by-value converting constructor even though it + isn't permitted by the above, because we've allowed it since GCC 5 + (PR58051) and it's allowed in C++20. But don't call a copy + constructor. */ + if ((TYPE_REF_P (ptype) && !TYPE_REF_IS_RVALUE (ptype)) || CONVERSION_RANK (convs[0]) > cr_exact) return error_mark_node; } @@ -8909,7 +8998,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { tree targ; tree arg = argarray[num_artificial_parms_for (fn)]; - tree fa; + tree fa = argarray[0]; bool trivial = trivial_fn_p (fn); /* Pull out the real argument, disregarding const-correctness. */ @@ -8939,8 +9028,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) else arg = cp_build_fold_indirect_ref (arg); - /* In C++17 we shouldn't be copying a TARGET_EXPR except into a base - subobject. */ + /* In C++17 we shouldn't be copying a TARGET_EXPR except into a + potentially-overlapping subobject. */ if (CHECKING_P && cxx_dialect >= cxx17) gcc_assert (TREE_CODE (arg) != TARGET_EXPR || force_elide @@ -8948,9 +9037,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) || convs[0]->need_temporary_p || seen_error () /* See unsafe_copy_elision_p. */ - || DECL_BASE_CONSTRUCTOR_P (fn)); + || unsafe_return_slot_p (fa)); - fa = argarray[0]; bool unsafe = unsafe_copy_elision_p (fa, arg); bool eliding_temp = (TREE_CODE (arg) == TARGET_EXPR && !unsafe); @@ -9143,6 +9231,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } } call = cxx_constant_value (call, obj_arg); + if (obj_arg && !error_operand_p (call)) + call = build2 (INIT_EXPR, void_type_node, obj_arg, call); } } return call; @@ -9762,7 +9852,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args, resolution. */ if (cxx_dialect >= cxx17 && args && vec_safe_length (*args) == 1 - && name == complete_ctor_identifier) + && !unsafe_return_slot_p (instance)) { tree arg = (**args)[0]; @@ -10240,8 +10330,8 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args, && !vec_safe_is_empty (user_args)) { /* Create a CONSTRUCTOR from ARGS, e.g. {1, 2} from <1, 2>. */ - tree list = build_tree_list_vec (user_args); - tree ctor = build_constructor_from_list (init_list_type_node, list); + tree ctor = build_constructor_from_vec (init_list_type_node, + user_args); CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true; CONSTRUCTOR_IS_PAREN_INIT (ctor) = true; if (is_dummy_object (instance)) @@ -11944,10 +12034,9 @@ perform_direct_initialization_if_possible (tree type, IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true; } else - expr = convert_like_real (conv, expr, NULL_TREE, 0, - /*issue_conversion_warnings=*/false, - c_cast_p, - complain); + expr = convert_like (conv, expr, NULL_TREE, 0, + /*issue_conversion_warnings=*/false, + c_cast_p, complain); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 14380c7..01780fe 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -516,8 +516,14 @@ build_base_path (enum tree_code code, out: if (null_test) - expr = fold_build3_loc (input_location, COND_EXPR, target_type, null_test, expr, - build_zero_cst (target_type)); + { + expr = fold_build3_loc (input_location, COND_EXPR, target_type, null_test, + expr, build_zero_cst (target_type)); + /* Avoid warning for the whole conditional expression (in addition + to NULL_TEST itself -- see above) in case the result is used in + a nonnull context that the front end -Wnonnull checks. */ + TREE_NO_WARNING (expr) = 1; + } return expr; } @@ -1000,10 +1006,6 @@ add_method (tree type, tree method, bool via_using) for (ovl_iterator iter (current_fns); iter; ++iter) { tree fn = *iter; - tree fn_type; - tree method_type; - tree parms1; - tree parms2; if (TREE_CODE (fn) != TREE_CODE (method)) continue; @@ -1031,10 +1033,8 @@ add_method (tree type, tree method, bool via_using) functions in the derived class override and/or hide member functions with the same name and parameter types in a base class (rather than conflicting). */ - fn_type = TREE_TYPE (fn); - method_type = TREE_TYPE (method); - parms1 = TYPE_ARG_TYPES (fn_type); - parms2 = TYPE_ARG_TYPES (method_type); + tree fn_type = TREE_TYPE (fn); + tree method_type = TREE_TYPE (method); /* Compare the quals on the 'this' parm. Don't compare the whole types, as used functions are treated as @@ -1049,137 +1049,149 @@ add_method (tree type, tree method, bool via_using) || type_memfn_rqual (fn_type) != type_memfn_rqual (method_type))) continue; - /* For templates, the return type and template parameters - must be identical. */ - if (TREE_CODE (fn) == TEMPLATE_DECL - && (!same_type_p (TREE_TYPE (fn_type), - TREE_TYPE (method_type)) - || !comp_template_parms (DECL_TEMPLATE_PARMS (fn), - DECL_TEMPLATE_PARMS (method)))) + tree real_fn = fn; + tree real_method = method; + + /* Templates and conversion ops must match return types. */ + if ((DECL_CONV_FN_P (fn) || TREE_CODE (fn) == TEMPLATE_DECL) + && !same_type_p (TREE_TYPE (fn_type), TREE_TYPE (method_type))) continue; + + /* For templates, the template parameters must be identical. */ + if (TREE_CODE (fn) == TEMPLATE_DECL) + { + if (!comp_template_parms (DECL_TEMPLATE_PARMS (fn), + DECL_TEMPLATE_PARMS (method))) + continue; + + real_fn = DECL_TEMPLATE_RESULT (fn); + real_method = DECL_TEMPLATE_RESULT (method); + } - if (! DECL_STATIC_FUNCTION_P (fn)) + tree parms1 = TYPE_ARG_TYPES (fn_type); + tree parms2 = TYPE_ARG_TYPES (method_type); + if (! DECL_STATIC_FUNCTION_P (real_fn)) parms1 = TREE_CHAIN (parms1); - if (! DECL_STATIC_FUNCTION_P (method)) + if (! DECL_STATIC_FUNCTION_P (real_method)) parms2 = TREE_CHAIN (parms2); - /* Bring back parameters omitted from an inherited ctor. */ - if (ctor_omit_inherited_parms (fn)) - parms1 = FUNCTION_FIRST_USER_PARMTYPE (DECL_ORIGIN (fn)); - if (ctor_omit_inherited_parms (method)) - parms2 = FUNCTION_FIRST_USER_PARMTYPE (DECL_ORIGIN (method)); + /* Bring back parameters omitted from an inherited ctor. The + method and the function can have different omittedness. */ + if (ctor_omit_inherited_parms (real_fn)) + parms1 = FUNCTION_FIRST_USER_PARMTYPE (DECL_CLONED_FUNCTION (real_fn)); + if (ctor_omit_inherited_parms (real_method)) + parms2 = (FUNCTION_FIRST_USER_PARMTYPE + (DECL_CLONED_FUNCTION (real_method))); - if (compparms (parms1, parms2) - && (!DECL_CONV_FN_P (fn) - || same_type_p (TREE_TYPE (fn_type), - TREE_TYPE (method_type)))) - { - if (!equivalently_constrained (fn, method)) - { - if (processing_template_decl) - /* We can't check satisfaction in dependent context, wait until - the class is instantiated. */ - continue; + if (!compparms (parms1, parms2)) + continue; - special_function_kind sfk = special_memfn_p (method); + if (!equivalently_constrained (fn, method)) + { + if (processing_template_decl) + /* We can't check satisfaction in dependent context, wait until + the class is instantiated. */ + continue; - if (sfk == sfk_none - || DECL_INHERITED_CTOR (fn) - || TREE_CODE (fn) == TEMPLATE_DECL) - /* Member function templates and non-special member functions - coexist if they are not equivalently constrained. A member - function is not hidden by an inherited constructor. */ - continue; + special_function_kind sfk = special_memfn_p (method); - /* P0848: For special member functions, deleted, unsatisfied, or - less constrained overloads are ineligible. We implement this - by removing them from CLASSTYPE_MEMBER_VEC. Destructors don't - use the notion of eligibility, and the selected destructor can - be deleted, but removing unsatisfied or less constrained - overloads has the same effect as overload resolution. */ - bool dtor = (sfk == sfk_destructor); - if (losem == -1) - losem = ((!dtor && DECL_DELETED_FN (method)) - || !constraints_satisfied_p (method)); - bool losef = ((!dtor && DECL_DELETED_FN (fn)) - || !constraints_satisfied_p (fn)); - int win; - if (losem || losef) - win = losem - losef; - else - win = more_constrained (fn, method); - if (win > 0) - /* Leave FN in the method vec, discard METHOD. */ - return false; - else if (win < 0) - { - /* Remove FN, add METHOD. */ - current_fns = iter.remove_node (current_fns); - continue; - } - else - /* Let them coexist for now. */ - continue; - } - - /* If these are versions of the same function, process and - move on. */ - if (TREE_CODE (fn) == FUNCTION_DECL - && maybe_version_functions (method, fn, true)) + if (sfk == sfk_none + || DECL_INHERITED_CTOR (fn) + || TREE_CODE (fn) == TEMPLATE_DECL) + /* Member function templates and non-special member functions + coexist if they are not equivalently constrained. A member + function is not hidden by an inherited constructor. */ continue; - if (DECL_INHERITED_CTOR (method)) - { - if (DECL_INHERITED_CTOR (fn)) - { - tree basem = DECL_INHERITED_CTOR_BASE (method); - tree basef = DECL_INHERITED_CTOR_BASE (fn); - if (flag_new_inheriting_ctors) - { - if (basem == basef) - { - /* Inheriting the same constructor along different - paths, combine them. */ - SET_DECL_INHERITED_CTOR - (fn, ovl_make (DECL_INHERITED_CTOR (method), - DECL_INHERITED_CTOR (fn))); - /* And discard the new one. */ - return false; - } - else - /* Inherited ctors can coexist until overload - resolution. */ - continue; - } - error_at (DECL_SOURCE_LOCATION (method), - "%q#D conflicts with version inherited from %qT", - method, basef); - inform (DECL_SOURCE_LOCATION (fn), - "version inherited from %qT declared here", - basef); - } - /* Otherwise defer to the other function. */ - return false; - } - - if (via_using) - /* Defer to the local function. */ + /* P0848: For special member functions, deleted, unsatisfied, or + less constrained overloads are ineligible. We implement this + by removing them from CLASSTYPE_MEMBER_VEC. Destructors don't + use the notion of eligibility, and the selected destructor can + be deleted, but removing unsatisfied or less constrained + overloads has the same effect as overload resolution. */ + bool dtor = (sfk == sfk_destructor); + if (losem == -1) + losem = ((!dtor && DECL_DELETED_FN (method)) + || !constraints_satisfied_p (method)); + bool losef = ((!dtor && DECL_DELETED_FN (fn)) + || !constraints_satisfied_p (fn)); + int win; + if (losem || losef) + win = losem - losef; + else + win = more_constrained (fn, method); + if (win > 0) + /* Leave FN in the method vec, discard METHOD. */ return false; - else if (flag_new_inheriting_ctors - && DECL_INHERITED_CTOR (fn)) + else if (win < 0) { - /* Remove the inherited constructor. */ + /* Remove FN, add METHOD. */ current_fns = iter.remove_node (current_fns); continue; } else + /* Let them coexist for now. */ + continue; + } + + /* If these are versions of the same function, process and + move on. */ + if (TREE_CODE (fn) == FUNCTION_DECL + && maybe_version_functions (method, fn, true)) + continue; + + if (DECL_INHERITED_CTOR (method)) + { + if (!DECL_INHERITED_CTOR (fn)) + /* Defer to the other function. */ + return false; + + tree basem = DECL_INHERITED_CTOR_BASE (method); + tree basef = DECL_INHERITED_CTOR_BASE (fn); + if (flag_new_inheriting_ctors) { - error_at (DECL_SOURCE_LOCATION (method), - "%q#D cannot be overloaded with %q#D", method, fn); - inform (DECL_SOURCE_LOCATION (fn), - "previous declaration %q#D", fn); - return false; + if (basem == basef) + { + /* Inheriting the same constructor along different + paths, combine them. */ + SET_DECL_INHERITED_CTOR + (fn, ovl_make (DECL_INHERITED_CTOR (method), + DECL_INHERITED_CTOR (fn))); + /* And discard the new one. */ + return false; + } + else + /* Inherited ctors can coexist until overload + resolution. */ + continue; } + + error_at (DECL_SOURCE_LOCATION (method), + "%q#D conflicts with version inherited from %qT", + method, basef); + inform (DECL_SOURCE_LOCATION (fn), + "version inherited from %qT declared here", + basef); + return false; + } + + if (via_using) + /* Defer to the local function. */ + return false; + else if (flag_new_inheriting_ctors + && DECL_INHERITED_CTOR (fn)) + { + /* Remove the inherited constructor. */ + current_fns = iter.remove_node (current_fns); + continue; + } + else + { + error_at (DECL_SOURCE_LOCATION (method), + "%q#D cannot be overloaded with %q#D", method, fn); + inform (DECL_SOURCE_LOCATION (fn), + "previous declaration %q#D", fn); + return false; } } @@ -1967,6 +1979,9 @@ fixup_type_variants (tree t) /* Copy whatever these are holding today. */ TYPE_VFIELD (variants) = TYPE_VFIELD (t); TYPE_FIELDS (variants) = TYPE_FIELDS (t); + + TYPE_SIZE (variants) = TYPE_SIZE (t); + TYPE_SIZE_UNIT (variants) = TYPE_SIZE_UNIT (t); } } @@ -3049,11 +3064,14 @@ finish_struct_anon (tree t) void maybe_add_class_template_decl_list (tree type, tree t, int friend_p) { - /* Save some memory by not creating TREE_LIST if TYPE is not template. */ - if (CLASSTYPE_TEMPLATE_INFO (type)) - CLASSTYPE_DECL_LIST (type) - = tree_cons (friend_p ? NULL_TREE : type, - t, CLASSTYPE_DECL_LIST (type)); + if (CLASSTYPE_TEMPLATE_INFO (type) + && TREE_CODE (t) != CONST_DECL) + { + tree purpose = friend_p ? NULL_TREE : type; + + CLASSTYPE_DECL_LIST (type) + = tree_cons (purpose, t, CLASSTYPE_DECL_LIST (type)); + } } /* This function is called from declare_virt_assop_and_dtor via @@ -4456,9 +4474,10 @@ build_base_field_1 (tree t, tree binfo, tree access, tree *&next_field) { /* Create the FIELD_DECL. */ tree basetype = BINFO_TYPE (binfo); - gcc_assert (CLASSTYPE_AS_BASE (basetype)); - tree decl = build_decl (input_location, - FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype)); + tree as_base = CLASSTYPE_AS_BASE (basetype); + gcc_assert (as_base); + tree decl = build_decl (input_location, FIELD_DECL, NULL_TREE, as_base); + DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_FIELD_CONTEXT (decl) = t; @@ -4708,6 +4727,10 @@ check_methods (tree t) } } +/* FN is constructor, destructor or operator function. Clone the + declaration to create a NAME'd variant. NEED_VTT_PARM_P and + OMIT_INHERITED_PARMS_P are relevant if it's a cdtor. */ + static tree copy_fndecl_with_name (tree fn, tree name, tree_code code, bool need_vtt_parm_p, bool omit_inherited_parms_p) @@ -4875,7 +4898,7 @@ build_clone (tree fn, tree name, bool need_vtt_parm_p, will be inserted onto DECL_CHAIN of FN. */ static unsigned -build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p) +build_cdtor_clones (tree fn, bool needs_vtt_p, bool base_omits_inherited_p) { unsigned count = 0; @@ -4884,8 +4907,8 @@ build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p) /* For each constructor, we need two variants: an in-charge version and a not-in-charge version. */ build_clone (fn, complete_ctor_identifier, false, false); - build_clone (fn, base_ctor_identifier, needs_vtt_parm_p, - omit_inherited_parms_p); + build_clone (fn, base_ctor_identifier, needs_vtt_p, + base_omits_inherited_p); count += 2; } else @@ -4907,7 +4930,7 @@ build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p) count++; } build_clone (fn, complete_dtor_identifier, false, false); - build_clone (fn, base_dtor_identifier, needs_vtt_parm_p, false); + build_clone (fn, base_dtor_identifier, needs_vtt_p, false); count += 2; } @@ -4931,9 +4954,10 @@ clone_cdtor (tree fn, bool update_methods) /* Base ctor omits inherited parms it needs a vttparm and inherited from a virtual nase ctor. */ - bool omit_inherited = ctor_omit_inherited_parms (fn); + bool base_omits_inherited = (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) + && base_ctor_omit_inherited_parms (fn)); - unsigned count = build_cdtor_clones (fn, vtt, omit_inherited); + unsigned count = build_cdtor_clones (fn, vtt, base_omits_inherited); /* Note that this is an abstract function that is never emitted. */ DECL_ABSTRACT_P (fn) = true; @@ -6091,10 +6115,8 @@ check_bases_and_members (tree t) } if (LAMBDA_TYPE_P (t)) - { - /* "This class type is not an aggregate." */ - CLASSTYPE_NON_AGGREGATE (t) = 1; - } + /* "This class type is not an aggregate." */ + CLASSTYPE_NON_AGGREGATE (t) = 1; /* Compute the 'literal type' property before we do anything with non-static member functions. */ @@ -6709,6 +6731,10 @@ layout_class_type (tree t, tree *virtuals_p) /* T needs a different layout as a base (eliding virtual bases or whatever). Create that version. */ tree base_t = make_node (TREE_CODE (t)); + tree base_d = create_implicit_typedef (as_base_identifier, base_t); + + TYPE_CONTEXT (base_t) = t; + DECL_CONTEXT (base_d) = t; /* If the ABI version is not at least two, and the last field was a bit-field, RLI may not be on a byte @@ -6717,6 +6743,8 @@ layout_class_type (tree t, tree *virtuals_p) indicates the total number of bits used. Therefore, rli_size_so_far, rather than rli_size_unit_so_far, is used to compute TYPE_SIZE_UNIT. */ + + /* Set the size and alignment for the new type. */ tree eoc = end_of_class (t, /*include_virtuals_p=*/0); TYPE_SIZE_UNIT (base_t) = size_binop (MAX_EXPR, @@ -6743,6 +6771,9 @@ layout_class_type (tree t, tree *virtuals_p) if (TREE_CODE (field) == FIELD_DECL) { *next_field = copy_node (field); + /* Zap any NSDMI, it's not needed and might be a deferred + parse. */ + DECL_INITIAL (*next_field) = NULL_TREE; DECL_CONTEXT (*next_field) = base_t; next_field = &DECL_CHAIN (*next_field); } @@ -6752,8 +6783,6 @@ layout_class_type (tree t, tree *virtuals_p) needs a mode. */ compute_record_mode (base_t); - TYPE_CONTEXT (base_t) = t; - /* Record the base version of the type. */ CLASSTYPE_AS_BASE (t) = base_t; } @@ -7597,12 +7626,7 @@ finish_struct (tree t, tree attributes) CLASSTYPE_NON_AGGREGATE (t) = 1; /* Fix up any variants we've already built. */ - for (x = TYPE_NEXT_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) - { - TYPE_SIZE (x) = TYPE_SIZE (t); - TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t); - TYPE_FIELDS (x) = TYPE_FIELDS (t); - } + fixup_type_variants (t); } else finish_struct_1 (t); @@ -8269,6 +8293,19 @@ resolve_address_of_overloaded_function (tree target_type, one, or vice versa. */ continue; + /* Constraints must be satisfied. This is done before + return type deduction since that instantiates the + function. */ + if (!constraints_satisfied_p (fn)) + continue; + + if (undeduced_auto_decl (fn)) + { + /* Force instantiation to do return type deduction. */ + maybe_instantiate_decl (fn); + require_deduced_type (fn); + } + /* In C++17 we need the noexcept-qualifier to compare types. */ if (flag_noexcept_type && !maybe_instantiate_noexcept (fn, complain)) @@ -8674,20 +8711,20 @@ void build_self_reference (void) { tree name = DECL_NAME (TYPE_NAME (current_class_type)); - tree value = build_lang_decl (TYPE_DECL, name, current_class_type); + tree decl = build_lang_decl (TYPE_DECL, name, current_class_type); - DECL_NONLOCAL (value) = 1; - DECL_CONTEXT (value) = current_class_type; - DECL_ARTIFICIAL (value) = 1; - SET_DECL_SELF_REFERENCE_P (value); - set_underlying_type (value); + DECL_NONLOCAL (decl) = 1; + DECL_CONTEXT (decl) = current_class_type; + DECL_ARTIFICIAL (decl) = 1; + SET_DECL_SELF_REFERENCE_P (decl); + set_underlying_type (decl); if (processing_template_decl) - value = push_template_decl (value); + decl = push_template_decl (decl); tree saved_cas = current_access_specifier; current_access_specifier = access_public_node; - finish_member_declaration (value); + finish_member_declaration (decl); current_access_specifier = saved_cas; } @@ -9002,11 +9039,11 @@ dump_class_hierarchy_1 (FILE *stream, dump_flags_t flags, tree t) fprintf (stream, " size=%lu align=%lu\n", (unsigned long)(tree_to_shwi (TYPE_SIZE (t)) / BITS_PER_UNIT), (unsigned long)(TYPE_ALIGN (t) / BITS_PER_UNIT)); - fprintf (stream, " base size=%lu base align=%lu\n", - (unsigned long)(tree_to_shwi (TYPE_SIZE (CLASSTYPE_AS_BASE (t))) - / BITS_PER_UNIT), - (unsigned long)(TYPE_ALIGN (CLASSTYPE_AS_BASE (t)) - / BITS_PER_UNIT)); + if (tree as_base = CLASSTYPE_AS_BASE (t)) + fprintf (stream, " base size=%lu base align=%lu\n", + (unsigned long)(tree_to_shwi (TYPE_SIZE (as_base)) + / BITS_PER_UNIT), + (unsigned long)(TYPE_ALIGN (as_base) / BITS_PER_UNIT)); dump_class_hierarchy_r (stream, flags, TYPE_BINFO (t), TYPE_BINFO (t), 0); fprintf (stream, "\n"); } @@ -9725,7 +9762,8 @@ build_vtbl_initializer (tree binfo, { int n_entries = vec_safe_length (vid.inits); - vec_safe_grow (vid.inits, TARGET_VTABLE_DATA_ENTRY_DISTANCE * n_entries); + vec_safe_grow (vid.inits, TARGET_VTABLE_DATA_ENTRY_DISTANCE * n_entries, + true); /* Move data entries into their new positions and add padding after the new positions. Iterate backwards so we don't @@ -9757,7 +9795,7 @@ build_vtbl_initializer (tree binfo, order. Straighten them out and add them to the running list in one step. */ jx = vec_safe_length (*inits); - vec_safe_grow (*inits, jx + vid.inits->length ()); + vec_safe_grow (*inits, jx + vid.inits->length (), true); for (ix = vid.inits->length () - 1; vid.inits->iterate (ix, &e); diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 97dcc1b..a118f8a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1203,7 +1203,7 @@ maybe_initialize_constexpr_call_table (void) This is not GC-deletable to avoid GC affecting UID generation. */ -static GTY(()) hash_map<tree, tree> *fundef_copies_table; +static GTY(()) decl_tree_map *fundef_copies_table; /* Reuse a copy or create a new unshared copy of the function FUN. Return this copy. We use a TREE_LIST whose PURPOSE is body, VALUE @@ -1355,6 +1355,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, case BUILT_IN_STRSTR: strops = 2; strret = 1; + break; + case BUILT_IN_ASAN_POINTER_COMPARE: + case BUILT_IN_ASAN_POINTER_SUBTRACT: + /* These builtins shall be ignored during constant expression + evaluation. */ + return void_node; default: break; } @@ -2336,9 +2342,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, false, non_constant_p, overflow_p); - VERIFY_CONSTANT (arg); if (i == 1) arg1 = arg; + else + VERIFY_CONSTANT (arg); } gcc_assert (arg1); return arg1; @@ -3085,8 +3092,8 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, else if (code == SPACESHIP_EXPR) { r = genericize_spaceship (type, lhs, rhs); - r = cxx_eval_constant_expression (ctx, r, lval, non_constant_p, - overflow_p); + return cxx_eval_constant_expression (ctx, r, lval, non_constant_p, + overflow_p); } if (r == NULL_TREE) @@ -4171,6 +4178,18 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, pre_init = true; } + bool zeroed_out = false; + if (!CONSTRUCTOR_NO_CLEARING (ctx->ctor)) + { + /* We're initializing an array object that had been zero-initialized + earlier. Truncate ctx->ctor, and propagate its zeroed state by + clearing CONSTRUCTOR_NO_CLEARING on each of the aggregate element + initializers we append to it. */ + gcc_checking_assert (initializer_zerop (ctx->ctor)); + zeroed_out = true; + vec_safe_truncate (*p, 0); + } + tree nelts = get_array_or_vector_nelts (ctx, atype, non_constant_p, overflow_p); unsigned HOST_WIDE_INT max = tree_to_uhwi (nelts); @@ -4182,7 +4201,11 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, constexpr_ctx new_ctx; init_subob_ctx (ctx, new_ctx, idx, pre_init ? init : elttype); if (new_ctx.ctor != ctx->ctor) - CONSTRUCTOR_APPEND_ELT (*p, idx, new_ctx.ctor); + { + if (zeroed_out) + CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = false; + CONSTRUCTOR_APPEND_ELT (*p, idx, new_ctx.ctor); + } if (TREE_CODE (elttype) == ARRAY_TYPE) { /* A multidimensional array; recurse. */ @@ -5695,9 +5718,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, TREE_CONSTANT (r) = true; } else if (ctx->strict) - r = decl_really_constant_value (t); + r = decl_really_constant_value (t, /*unshare_p=*/false); else - r = decl_constant_value (t); + r = decl_constant_value (t, /*unshare_p=*/false); if (TREE_CODE (r) == TARGET_EXPR && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR) r = TARGET_EXPR_INITIAL (r); @@ -6664,6 +6687,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, allow_non_constant, strict, manifestly_const_eval || !allow_non_constant }; + /* Turn off -frounding-math for manifestly constant evaluation. */ + warning_sentinel rm (flag_rounding_math, ctx.manifestly_const_eval); tree type = initialized_type (t); tree r = t; bool is_consteval = false; diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index d0da230..050b55c 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -554,7 +554,7 @@ map_arguments (tree parms, tree args) TREE_PURPOSE (p) = TMPL_ARG (args, level, index); } else - TREE_PURPOSE (p) = TREE_VALUE (p); + TREE_PURPOSE (p) = template_parm_to_arg (p); return parms; } @@ -840,6 +840,8 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) if (tree *p = hash_map_safe_get (normalized_map, tmpl)) return *p; + push_nested_class_guard pncs (DECL_CONTEXT (d)); + tree args = generic_targs_for (tmpl); tree ci = get_constraints (decl); tree norm = get_normalized_constraints_from_info (ci, args, tmpl, diag); @@ -1425,7 +1427,9 @@ tree build_type_constraint (tree decl, tree args, tsubst_flags_t complain) { tree wildcard = build_nt (WILDCARD_DECL); + ++processing_template_decl; tree check = build_concept_check (decl, wildcard, args, complain); + --processing_template_decl; if (check == error_mark_node) return error_mark_node; return unpack_concept_check (check); @@ -1490,7 +1494,7 @@ finish_shorthand_constraint (tree decl, tree constr) /* Get the argument and overload used for the requirement and adjust it if we're going to expand later. */ - tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl)); + tree arg = template_parm_to_arg (decl); if (apply_to_each_p && declared_pack_p) arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0)); @@ -2173,7 +2177,19 @@ tsubst_requires_expr (tree t, tree args, /* A requires-expression is an unevaluated context. */ cp_unevaluated u; - tree parms = TREE_OPERAND (t, 0); + args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args); + if (processing_template_decl) + { + /* We're partially instantiating a generic lambda. Substituting into + this requires-expression now may cause its requirements to get + checked out of order, so instead just remember the template + arguments and wait until we can substitute them all at once. */ + t = copy_node (t); + REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain); + return t; + } + + tree parms = REQUIRES_EXPR_PARMS (t); if (parms) { parms = tsubst_constraint_variables (parms, args, info); @@ -2181,14 +2197,11 @@ tsubst_requires_expr (tree t, tree args, return boolean_false_node; } - tree reqs = TREE_OPERAND (t, 1); + tree reqs = REQUIRES_EXPR_REQS (t); reqs = tsubst_requirement_body (reqs, args, info); if (reqs == error_mark_node) return boolean_false_node; - if (processing_template_decl) - return finish_requires_expr (cp_expr_location (t), parms, reqs); - return boolean_true_node; } @@ -2550,7 +2563,7 @@ get_mapped_args (tree map) /* Insert the argument into its corresponding position. */ vec<tree> &list = lists[level - 1]; if (index >= (int)list.length ()) - list.safe_grow_cleared (index + 1); + list.safe_grow_cleared (index + 1, true); list[index] = TREE_PURPOSE (p); } @@ -2632,7 +2645,8 @@ satisfy_atom (tree t, tree args, subst_info info) result = cxx_constant_value (result); else { - result = maybe_constant_value (result); + result = maybe_constant_value (result, NULL_TREE, + /*manifestly_const_eval=*/true); if (!TREE_CONSTANT (result)) result = error_mark_node; } @@ -2812,16 +2826,22 @@ satisfy_declaration_constraints (tree t, tree args, subst_info info) info.in_decl = t; gcc_assert (TREE_CODE (t) == TEMPLATE_DECL); + + args = add_outermost_template_args (t, args); + + tree result = boolean_true_node; if (tree norm = normalize_template_requirements (t, info.noisy ())) { + if (!push_tinst_level (t, args)) + return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_access_scope (pattern); - tree result = satisfy_associated_constraints (norm, args, info); + result = satisfy_associated_constraints (norm, args, info); pop_access_scope (pattern); - return result; + pop_tinst_level (); } - return boolean_true_node; + return result; } static tree @@ -2864,6 +2884,9 @@ constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain) bool constraints_satisfied_p (tree t) { + if (!flag_concepts) + return true; + return constraint_satisfaction_value (t, tf_none) == boolean_true_node; } @@ -2873,6 +2896,9 @@ constraints_satisfied_p (tree t) bool constraints_satisfied_p (tree t, tree args) { + if (!flag_concepts) + return true; + return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node; } @@ -2919,7 +2945,7 @@ finish_requires_expr (location_t loc, tree parms, tree reqs) } /* Build the node. */ - tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs); + tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE); TREE_SIDE_EFFECTS (r) = false; TREE_CONSTANT (r) = true; SET_EXPR_LOCATION (r, loc); diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index bec7f2f..ba81345 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -110,7 +110,7 @@ struct coroutine_info_hasher : ggc_ptr_hash<coroutine_info> static GTY (()) hash_table<coroutine_info_hasher> *coroutine_info_table; -/* We will initialise state lazily. */ +/* We will initialize state lazily. */ static bool coro_initialized = false; /* Return a hash value for the entry pointed to by INFO. @@ -261,13 +261,13 @@ static GTY(()) tree void_coro_handle_type; static tree find_coro_traits_template_decl (location_t kw) { - /* If we are missing fundmental information, such as the traits, (or the + /* If we are missing fundamental information, such as the traits, (or the declaration found is not a type template), then don't emit an error for every keyword in a TU, just do it once. */ static bool traits_error_emitted = false; tree traits_decl = lookup_qualified_name (std_node, coro_traits_identifier, - 0, + LOOK_want::NORMAL, /*complain=*/!traits_error_emitted); if (traits_decl == error_mark_node || !DECL_TYPE_TEMPLATE_P (traits_decl)) @@ -348,7 +348,8 @@ find_coro_handle_template_decl (location_t kw) it once. */ static bool coro_handle_error_emitted = false; tree handle_decl = lookup_qualified_name (std_node, coro_handle_identifier, - 0, !coro_handle_error_emitted); + LOOK_want::NORMAL, + !coro_handle_error_emitted); if (handle_decl == error_mark_node || !DECL_CLASS_TEMPLATE_P (handle_decl)) { @@ -1102,7 +1103,7 @@ finish_co_yield_expr (location_t kw, tree expr) return op; } -/* Check and build a co_return statememt. +/* Check and build a co_return statement. First that it's valid to have a co_return keyword here. If it is, then check and build the p.return_{void(),value(expr)}. These are built against a proxy for the promise, which will be filled @@ -1189,29 +1190,15 @@ finish_co_return_stmt (location_t kw, tree expr) treating the object as an rvalue, if that fails, then we fall back to regular overload resolution. */ - if (treat_lvalue_as_rvalue_p (expr, /*parm_ok*/true) - && CLASS_TYPE_P (TREE_TYPE (expr)) - && !TYPE_VOLATILE (TREE_TYPE (expr))) - { - /* It's OK if this fails... */ - vec<tree, va_gc> *args = make_tree_vector_single (move (expr)); - co_ret_call - = coro_build_promise_expression (current_function_decl, NULL, - coro_return_value_identifier, kw, - &args, /*musthave=*/false); - release_tree_vector (args); - } + tree arg = expr; + if (tree moved = treat_lvalue_as_rvalue_p (expr, /*return*/true)) + arg = moved; - if (!co_ret_call || co_ret_call == error_mark_node) - { - /* ... but this must succeed if we didn't get the move variant. */ - vec<tree, va_gc> *args = make_tree_vector_single (expr); - co_ret_call - = coro_build_promise_expression (current_function_decl, NULL, - coro_return_value_identifier, kw, - &args, /*musthave=*/true); - release_tree_vector (args); - } + releasing_vec args = make_tree_vector_single (arg); + co_ret_call + = coro_build_promise_expression (current_function_decl, NULL, + coro_return_value_identifier, kw, + &args, /*musthave=*/true); } /* Makes no sense for a co-routine really. */ @@ -1390,119 +1377,6 @@ replace_proxy (tree *here, int *do_subtree, void *d) return NULL_TREE; } -/* Support for expansion of co_return statements. */ - -struct coro_ret_data -{ - tree promise_proxy; - tree real_promise; - tree fs_label; -}; - -/* If this is a coreturn statement (or one wrapped in a cleanup) then - return the list of statements to replace it. */ - -static tree -coro_maybe_expand_co_return (tree co_ret_expr, coro_ret_data *data) -{ - /* Look inside <(void) (expr)> cleanup */ - if (TREE_CODE (co_ret_expr) == CLEANUP_POINT_EXPR) - co_ret_expr = TREE_OPERAND (co_ret_expr, 0); - - if (TREE_CODE (co_ret_expr) != CO_RETURN_EXPR) - return NULL_TREE; - - location_t loc = EXPR_LOCATION (co_ret_expr); - tree expr = TREE_OPERAND (co_ret_expr, 0); - tree call = TREE_OPERAND (co_ret_expr, 1); - tree stmt_list = NULL; - if (expr && VOID_TYPE_P (TREE_TYPE (expr))) - { - /* [stmt.return.coroutine], 2.2 - If expr is present and void, it is placed immediately before - the call for return_void; */ - expr = maybe_cleanup_point_expr_void (expr); - append_to_statement_list (expr, &stmt_list); - } - - /* Now replace the promise proxy with its real value. */ - proxy_replace p_data; - p_data.from = data->promise_proxy; - p_data.to = data->real_promise; - cp_walk_tree (&call, replace_proxy, &p_data, NULL); - - /* The types of p.return_void and p.return_value are not explicitly stated - at least in n4835, it is expected that they will return void. */ - call = maybe_cleanup_point_expr_void (call); - append_to_statement_list (call, &stmt_list); - tree r = build1_loc (loc, GOTO_EXPR, void_type_node, data->fs_label); - append_to_statement_list (r, &stmt_list); - return stmt_list; -} - -/* Callback that rewrites co_return as per [stmt.return.coroutine] - - for co_return; - { p.return_void (); goto final_suspend; } - - for co_return [void expr]; - { expr; p.return_void(); goto final_suspend;} - - for co_return [non void expr]; - { p.return_value(expr); goto final_suspend; } */ - -static tree -co_return_expander (tree *stmt, int *do_subtree, void *d) -{ - coro_ret_data *data = (coro_ret_data *) d; - - /* To avoid nesting statement lists, walk them and insert as needed. */ - if (TREE_CODE (*stmt) == STATEMENT_LIST) - { - tree_stmt_iterator i; - for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i)) - { - tree *new_stmt = tsi_stmt_ptr (i); - tree replace = coro_maybe_expand_co_return (*new_stmt, data); - /* If we got something, it will be list and we want to splice - it in. */ - if (replace != NULL_TREE) - { - /* Splice it in ... */ - tsi_link_before (&i, replace, TSI_SAME_STMT); - /* ... and delete what we expanded. */ - tsi_delink (&i); - /* Maybe, even likely, we replaced the last in the list. */ - if (tsi_end_p (i)) - break; - } - else /* Continue the walk. */ - cp_walk_tree (new_stmt, co_return_expander, d, NULL); - } - *do_subtree = 0; /* Done subtrees. */ - } - else - { - /* We might have a single co_return statement, in which case, we do - have to replace it with a list. */ - tree replace = coro_maybe_expand_co_return (*stmt, data); - if (replace != NULL_TREE) - { - *stmt = replace; - *do_subtree = 0; /* Done here. */ - } - } - return NULL_TREE; -} - -/* Walk the original function body, rewriting co_returns. */ - -static tree -expand_co_returns (tree *fnbody, tree promise_proxy, tree promise, - tree fs_label) -{ - coro_ret_data data = {promise_proxy, promise, fs_label}; - cp_walk_tree (fnbody, co_return_expander, &data, NULL); - return *fnbody; -} - /* Support for expansion of co_await statements. */ struct coro_aw_data @@ -1519,7 +1393,7 @@ struct coro_aw_data unsigned index; /* This is our current resume index. */ }; -/* Lighweight search for the first await expression in tree-walk order. +/* Lightweight search for the first await expression in tree-walk order. returns: The first await expression found in STMT. NULL_TREE if there are none. @@ -1527,7 +1401,7 @@ struct coro_aw_data awaits. */ static tree -co_await_find_in_subtree (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) +co_await_find_in_subtree (tree *stmt, int *, void *d) { tree **p = (tree **) d; if (TREE_CODE (*stmt) == CO_AWAIT_EXPR) @@ -1538,13 +1412,13 @@ co_await_find_in_subtree (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) return NULL_TREE; } -/* Starting with a statment: +/* Starting with a statement: stmt => some tree containing one or more await expressions. We replace the statement with: <STATEMENT_LIST> { - initialise awaitable + initialize awaitable if (!ready) { suspension context. @@ -1731,7 +1605,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) *await_expr = resume_call; /* Replace the co_await expr with its result. */ append_to_statement_list_force (saved_statement, &stmt_list); - /* Get a pointer to the revised statment. */ + /* Get a pointer to the revised statement. */ tree *revised = tsi_stmt_ptr (tsi_last (stmt_list)); if (needs_dtor) { @@ -2090,8 +1964,7 @@ static void build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree orig, hash_map<tree, param_info> *param_uses, hash_map<tree, local_var_info> *local_var_uses, - vec<tree, va_gc> *param_dtor_list, - tree fs_label, tree resume_fn_field, + vec<tree, va_gc> *param_dtor_list, tree resume_fn_field, unsigned body_count, tree frame_size) { verify_stmt_tree (fnbody); @@ -2161,7 +2034,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, bool existed; param_info &parm = param_uses->get_or_insert (arg, &existed); if (!parm.body_uses) - continue; /* Wasn't used in the orignal function body. */ + continue; /* Wasn't used in the original function body. */ tree fld_ref = lookup_member (coro_frame_type, parm.field_id, /*protect=*/1, /*want_type=*/0, @@ -2307,9 +2180,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, await_xform_data xform = {actor, actor_frame, promise_proxy, ap, self_h_proxy, ash}; - /* Expand co_returns in the saved function body */ - fnbody = expand_co_returns (&fnbody, promise_proxy, ap, fs_label); - /* Transform the await expressions in the function body. Only do each await tree once! */ hash_set<tree> pset; @@ -2645,7 +2515,7 @@ register_await_info (tree await_expr, tree aw_type, tree aw_nam) = suspend_points->get_or_insert (await_expr, &seen); if (seen) { - error_at (EXPR_LOCATION (await_expr), "duplicate info for %qE", + warning_at (EXPR_LOCATION (await_expr), 0, "duplicate info for %qE", await_expr); return false; } @@ -2654,26 +2524,14 @@ register_await_info (tree await_expr, tree aw_type, tree aw_nam) return true; } -/* Small helper for the repetitive task of adding a new field to the coro - frame type. */ - -static tree -coro_make_frame_entry (tree *field_list, const char *name, tree fld_type, - location_t loc) -{ - tree id = get_identifier (name); - tree decl = build_decl (loc, FIELD_DECL, id, fld_type); - DECL_CHAIN (decl) = *field_list; - *field_list = decl; - return id; -} - /* This data set is used when analyzing statements for await expressions. */ + struct susp_frame_data { /* Function-wide. */ tree *field_list; /* The current coroutine frame field list. */ tree handle_type; /* The self-handle type for this coroutine. */ + tree fs_label; /* The destination for co_returns. */ vec<tree, va_gc> *block_stack; /* Track block scopes. */ vec<tree, va_gc> *bind_stack; /* Track current bind expr. */ unsigned await_number; /* Which await in the function. */ @@ -2685,275 +2543,575 @@ struct susp_frame_data unsigned saw_awaits; /* Count of awaits in this statement */ bool captures_temporary; /* This expr captures temps by ref. */ bool needs_truth_if_exp; /* We must expand a truth_if expression. */ + bool has_awaiter_init; /* We must handle initializing an awaiter. */ }; -/* Walk the sub-tree looking for call expressions that both capture - references and have compiler-temporaries as parms. */ +/* If this is an await expression, then count it (both uniquely within the + function and locally within a single statement). */ static tree -captures_temporary (tree *stmt, int *do_subtree, void *d) +register_awaits (tree *stmt, int *, void *d) { + tree aw_expr = *stmt; + /* We should have already lowered co_yields to their co_await. */ - gcc_checking_assert (TREE_CODE (*stmt) != CO_YIELD_EXPR); + gcc_checking_assert (TREE_CODE (aw_expr) != CO_YIELD_EXPR); + + if (TREE_CODE (aw_expr) != CO_AWAIT_EXPR) + return NULL_TREE; + + /* Count how many awaits the current expression contains. */ + susp_frame_data *data = (susp_frame_data *) d; + data->saw_awaits++; + /* Each await suspend context is unique, this is a function-wide value. */ + data->await_number++; + + /* Awaitables should either be user-locals or promoted to coroutine frame + entries at this point, and their initializers should have been broken + out. */ + tree aw = TREE_OPERAND (aw_expr, 1); + gcc_checking_assert (!TREE_OPERAND (aw_expr, 2)); + + tree aw_field_type = TREE_TYPE (aw); + tree aw_field_nam = NULL_TREE; + register_await_info (aw_expr, aw_field_type, aw_field_nam); + + /* Rewrite target expressions on the await_suspend () to remove extraneous + cleanups for the awaitables, which are now promoted to frame vars and + managed via that. */ + tree v = TREE_OPERAND (aw_expr, 3); + tree o = TREE_VEC_ELT (v, 1); + if (TREE_CODE (o) == TARGET_EXPR) + TREE_VEC_ELT (v, 1) = get_target_expr (TREE_OPERAND (o, 1)); + return NULL_TREE; +} - /* Stop recursing if we see an await expression, the subtrees - of that will be handled when it is processed. */ +/* There are cases where any await expression is relevant. */ +static tree +find_any_await (tree *stmt, int *dosub, void *d) +{ if (TREE_CODE (*stmt) == CO_AWAIT_EXPR) { - *do_subtree = 0; - return NULL_TREE; + *dosub = 0; /* We don't need to consider this any further. */ + tree **p = (tree **) d; + *p = stmt; + return *stmt; } + return NULL_TREE; +} - /* We're only interested in calls. */ - if (TREE_CODE (*stmt) != CALL_EXPR) - return NULL_TREE; +static bool +tmp_target_expr_p (tree t) +{ + if (TREE_CODE (t) != TARGET_EXPR) + return false; + tree v = TREE_OPERAND (t, 0); + if (!DECL_ARTIFICIAL (v)) + return false; + if (DECL_NAME (v)) + return false; + return true; +} - /* Does this call capture references? - Strip the ADDRESS_EXPR to get the fn decl and inspect it. */ - tree fn = TREE_OPERAND (CALL_EXPR_FN (*stmt), 0); - bool is_meth = TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE; - tree arg = TYPE_ARG_TYPES (TREE_TYPE (fn)); - unsigned offset = 3; - for (unsigned anum = 0; arg != NULL; arg = TREE_CHAIN (arg), anum++) +/* Structure to record sub-expressions that need to be handled by the + statement flattener. */ + +struct coro_interesting_subtree +{ + tree* entry; + hash_set<tree> *temps_used; +}; + +/* tree-walk callback that returns the first encountered sub-expression of + a kind that needs to be handled specifically by the statement flattener. */ + +static tree +find_interesting_subtree (tree *expr_p, int *dosub, void *d) +{ + tree expr = *expr_p; + coro_interesting_subtree *p = (coro_interesting_subtree *)d; + if (TREE_CODE (expr) == CO_AWAIT_EXPR) { - tree parm_type = TREE_VALUE (arg); - if (anum == 0 && is_meth && INDIRECT_TYPE_P (parm_type)) + *dosub = 0; /* We don't need to consider this any further. */ + if (TREE_OPERAND (expr, 2)) { - /* Account for 'this' when the fn is a method. Unless it - belongs to a CTOR or DTOR. */ - if (DECL_CONSTRUCTOR_P (fn) || DECL_DESTRUCTOR_P (fn)) - continue; + p->entry = expr_p; + return expr; } - else if (!TYPE_REF_P (parm_type)) - /* If it's not a reference, we don't care. */ - continue; + } + else if (tmp_target_expr_p (expr) + && !p->temps_used->contains (expr)) + { + p->entry = expr_p; + return expr; + } - /* Fetch the value presented to the fn. */ - tree parm = TREE_OPERAND (*stmt, anum + offset); + return NULL_TREE; +} - while (TREE_CODE (parm) == NOP_EXPR) - parm = TREE_OPERAND (parm, 0); +/* Node for a doubly-linked list of promoted variables and their + initializers. When the initializer is a conditional expression + the 'then' and 'else' clauses are represented by a linked list + attached to then_cl and else_cl respectively. */ - /* We only care if we're taking the addr of a temporary. */ - if (TREE_CODE (parm) != ADDR_EXPR) - continue; +struct var_nest_node +{ + var_nest_node () = default; + var_nest_node (tree v, tree i, var_nest_node *p, var_nest_node *n) + : var(v), init(i), prev(p), next(n) + { + if (p) + p->next = this; + if (n) + n->prev = this; + } + tree var; + tree init; + var_nest_node *prev; + var_nest_node *next; + var_nest_node *then_cl; + var_nest_node *else_cl; +}; - parm = TREE_OPERAND (parm, 0); +/* This is called for single statements from the co-await statement walker. + It checks to see if the statement contains any initializers for awaitables + and if any of these capture items by reference. */ - /* In case of component_ref, we need to capture the object of base - class as if it is temporary object. There are two possibilities: - (*base).field and base->field. */ - while (TREE_CODE (parm) == COMPONENT_REF) +static void +flatten_await_stmt (var_nest_node *n, hash_set<tree> *promoted, + hash_set<tree> *temps_used, tree *replace_in) +{ + bool init_expr = false; + switch (TREE_CODE (n->init)) + { + default: break; + /* Compound expressions must be flattened specifically. */ + case COMPOUND_EXPR: { - parm = TREE_OPERAND (parm, 0); - if (TREE_CODE (parm) == INDIRECT_REF) - parm = TREE_OPERAND (parm, 0); - STRIP_NOPS (parm); + tree first = TREE_OPERAND (n->init, 0); + n->init = TREE_OPERAND (n->init, 1); + var_nest_node *ins + = new var_nest_node(NULL_TREE, first, n->prev, n); + /* The compiler (but not the user) can generate temporaries with + uses in the second arm of a compound expr. */ + flatten_await_stmt (ins, promoted, temps_used, &n->init); + flatten_await_stmt (n, promoted, temps_used, NULL); + /* The two arms have been processed separately. */ + return; } + break; + /* Handle conditional expressions. */ + case INIT_EXPR: + init_expr = true; + /* FALLTHROUGH */ + case MODIFY_EXPR: + { + tree old_expr = TREE_OPERAND (n->init, 1); + if (TREE_CODE (old_expr) == COMPOUND_EXPR) + { + tree first = TREE_OPERAND (old_expr, 0); + TREE_OPERAND (n->init, 1) = TREE_OPERAND (old_expr, 1); + var_nest_node *ins + = new var_nest_node(NULL_TREE, first, n->prev, n); + flatten_await_stmt (ins, promoted, temps_used, + &TREE_OPERAND (n->init, 1)); + flatten_await_stmt (n, promoted, temps_used, NULL); + return; + } + if (TREE_CODE (old_expr) != COND_EXPR) + break; + /* Reconstruct x = t ? y : z; + as (void) t ? x = y : x = z; */ + tree var = TREE_OPERAND (n->init, 0); + tree var_type = TREE_TYPE (var); + tree cond = COND_EXPR_COND (old_expr); + /* We are allowed a void type throw in one or both of the cond + expr arms. */ + tree then_cl = COND_EXPR_THEN (old_expr); + if (!VOID_TYPE_P (TREE_TYPE (then_cl))) + { + gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST); + then_cl + = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type, + var, then_cl); + } + tree else_cl = COND_EXPR_ELSE (old_expr); + if (!VOID_TYPE_P (TREE_TYPE (else_cl))) + { + gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST); + else_cl + = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type, + var, else_cl); + } + n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl); + } + /* FALLTHROUGH */ + case COND_EXPR: + { + tree *found; + tree cond = COND_EXPR_COND (n->init); + /* If the condition contains an await expression, then we need to + set that first and use a separate var. */ + if (cp_walk_tree (&cond, find_any_await, &found, NULL)) + { + tree cond_type = TREE_TYPE (cond); + tree cond_var = build_lang_decl (VAR_DECL, NULL_TREE, cond_type); + DECL_ARTIFICIAL (cond_var) = true; + layout_decl (cond_var, 0); + gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type)); + cond = build2 (INIT_EXPR, cond_type, cond_var, cond); + var_nest_node *ins + = new var_nest_node (cond_var, cond, n->prev, n); + COND_EXPR_COND (n->init) = cond_var; + flatten_await_stmt (ins, promoted, temps_used, NULL); + } - /* This isn't a temporary. */ - if ((VAR_P (parm) - && (!DECL_ARTIFICIAL (parm) || DECL_HAS_VALUE_EXPR_P (parm))) - || TREE_CODE (parm) == PARM_DECL - || TREE_CODE (parm) == NON_LVALUE_EXPR) - continue; - - if (TREE_CODE (parm) == TARGET_EXPR) + n->then_cl + = new var_nest_node (n->var, COND_EXPR_THEN (n->init), NULL, NULL); + n->else_cl + = new var_nest_node (n->var, COND_EXPR_ELSE (n->init), NULL, NULL); + flatten_await_stmt (n->then_cl, promoted, temps_used, NULL); + /* Point to the start of the flattened code. */ + while (n->then_cl->prev) + n->then_cl = n->then_cl->prev; + flatten_await_stmt (n->else_cl, promoted, temps_used, NULL); + while (n->else_cl->prev) + n->else_cl = n->else_cl->prev; + return; + } + break; + } + coro_interesting_subtree v = { NULL, temps_used }; + tree t = cp_walk_tree (&n->init, find_interesting_subtree, (void *)&v, NULL); + if (!t) + return; + switch (TREE_CODE (t)) + { + default: break; + case CO_AWAIT_EXPR: { - /* We're taking the address of a temporary and using it as a ref. */ - tree tvar = TREE_OPERAND (parm, 0); - gcc_checking_assert (DECL_ARTIFICIAL (tvar)); - - susp_frame_data *data = (susp_frame_data *) d; - data->captures_temporary = true; - /* Record this one so we don't duplicate, and on the first - occurrence note the target expr to be replaced. */ - if (!data->captured_temps.add (tvar)) - vec_safe_push (data->to_replace, parm); - /* Now see if the initializer contains any more cases. */ - hash_set<tree> visited; - tree res = cp_walk_tree (&TREE_OPERAND (parm, 1), - captures_temporary, d, &visited); - if (res) - return res; - /* Otherwise, we're done with sub-trees for this. */ + /* Await expressions with initializers have a compiler-temporary + as the awaitable. 'promote' this. */ + tree var = TREE_OPERAND (t, 1); + bool already_present = promoted->add (var); + gcc_checking_assert (!already_present); + tree init = TREE_OPERAND (t, 2); + switch (TREE_CODE (init)) + { + default: break; + case INIT_EXPR: + case MODIFY_EXPR: + { + tree inner = TREE_OPERAND (init, 1); + /* We can have non-lvalue-expressions here, but when we see + a target expression, mark it as already used. */ + if (TREE_CODE (inner) == TARGET_EXPR) + { + temps_used->add (inner); + gcc_checking_assert + (TREE_CODE (TREE_OPERAND (inner, 1)) != COND_EXPR); + } + } + break; + case CALL_EXPR: + /* If this is a call and not a CTOR, then we didn't expect it. */ + gcc_checking_assert + (DECL_CONSTRUCTOR_P (TREE_OPERAND (CALL_EXPR_FN (init), 0))); + break; + } + var_nest_node *ins = new var_nest_node (var, init, n->prev, n); + TREE_OPERAND (t, 2) = NULL_TREE; + flatten_await_stmt (ins, promoted, temps_used, NULL); + flatten_await_stmt (n, promoted, temps_used, NULL); + return; } - else if (TREE_CODE (parm) == CO_AWAIT_EXPR) + break; + case TARGET_EXPR: { - /* CO_AWAIT expressions behave in a similar manner to target - expressions when the await_resume call is contained in one. */ - tree awr = TREE_OPERAND (parm, 3); /* call vector. */ - awr = TREE_VEC_ELT (awr, 2); /* resume call. */ - if (TREE_CODE (awr) == TARGET_EXPR) + /* We have a temporary; promote it. */ + tree init = t; + temps_used->add (init); + tree var_type = TREE_TYPE (init); + char *buf = xasprintf ("D.%d", DECL_UID (TREE_OPERAND (init, 0))); + tree var = build_lang_decl (VAR_DECL, get_identifier (buf), var_type); + DECL_ARTIFICIAL (var) = true; + free (buf); + bool already_present = promoted->add (var); + gcc_checking_assert (!already_present); + tree inner = TREE_OPERAND (init, 1); + gcc_checking_assert (TREE_CODE (inner) != COND_EXPR); + if (TYPE_NEEDS_CONSTRUCTING (var_type)) { - tree tvar = TREE_OPERAND (awr, 0); - gcc_checking_assert (DECL_ARTIFICIAL (tvar)); - - susp_frame_data *data = (susp_frame_data *) d; - data->captures_temporary = true; - /* Use this as a place-holder. */ - if (!data->captured_temps.add (tvar)) - vec_safe_push (data->to_replace, parm); + releasing_vec p_in (make_tree_vector_single (init)); + init = build_special_member_call (var, complete_ctor_identifier, + &p_in, var_type, LOOKUP_NORMAL, + tf_warning_or_error); } - /* We will walk the sub-trees of this co_await separately. */ + else + init = build2 (INIT_EXPR, var_type, var, init); + var_nest_node *ins + = new var_nest_node (var, init, n->prev, n); + /* We have to replace the target expr... */ + proxy_replace pr = {TREE_OPERAND (t, 0), var}; + *v.entry = var; + /* ... and any uses of its var. */ + cp_walk_tree (&n->init, replace_proxy, &pr, NULL); + /* Compiler-generated temporaries can also have uses in following + arms of compound expressions, which will be listed in 'replace_in' + if present. */ + if (replace_in) + cp_walk_tree (replace_in, replace_proxy, &pr, NULL); + flatten_await_stmt (ins, promoted, temps_used, NULL); + flatten_await_stmt (n, promoted, temps_used, NULL); + return; } - else - gcc_unreachable (); + break; } - /* As far as it's necessary, we've walked the subtrees of the call - expr. */ - *do_subtree = 0; - return NULL_TREE; } -/* If this is an await, then register it and decide on what coro - frame storage is needed. - If this is a co_yield (which embeds an await), drop the yield - and record the await (the yield was kept for diagnostics only). */ +/* Helper for 'process_conditional' that handles recursion into nested + conditionals. */ -static tree -register_awaits (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) +static void +handle_nested_conditionals (var_nest_node *n, vec<tree>& list, + hash_map<tree, tree>& map) { - susp_frame_data *data = (susp_frame_data *) d; + do + { + if (n->var && DECL_NAME (n->var)) + { + list.safe_push (n->var); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (n->var))) + { + bool existed; + tree& flag = map.get_or_insert (n->var, &existed); + if (!existed) + { + /* We didn't see this var before and it needs a DTOR, so + build a guard variable for it. */ + char *nam + = xasprintf ("%s_guard", + IDENTIFIER_POINTER (DECL_NAME (n->var))); + flag = build_lang_decl (VAR_DECL, get_identifier (nam), + boolean_type_node); + free (nam); + DECL_ARTIFICIAL (flag) = true; + } + + /* The initializer for this variable is replaced by a compound + expression that performs the init and then records that the + variable is live (and the DTOR should be run at the scope + exit. */ + tree set_flag = build2 (INIT_EXPR, boolean_type_node, + flag, boolean_true_node); + n->init + = build2 (COMPOUND_EXPR, boolean_type_node, n->init, set_flag); + } + } + if (TREE_CODE (n->init) == COND_EXPR) + { + tree new_then = push_stmt_list (); + handle_nested_conditionals (n->then_cl, list, map); + new_then = pop_stmt_list (new_then); + tree new_else = push_stmt_list (); + handle_nested_conditionals (n->else_cl, list, map); + new_else = pop_stmt_list (new_else); + tree new_if + = build4 (IF_STMT, void_type_node, COND_EXPR_COND (n->init), + new_then, new_else, NULL_TREE); + add_stmt (new_if); + } + else + finish_expr_stmt (n->init); + n = n->next; + } while (n); +} - /* We should have already lowered co_yields to their co_await. */ - gcc_checking_assert (TREE_CODE (*stmt) != CO_YIELD_EXPR); +/* helper for 'maybe_promote_temps'. - if (TREE_CODE (*stmt) != CO_AWAIT_EXPR) - return NULL_TREE; + When we have a conditional expression which might embed await expressions + and/or promoted variables, we need to handle it appropriately. - tree aw_expr = *stmt; - location_t aw_loc = EXPR_LOCATION (aw_expr); /* location of the co_xxxx. */ + The linked lists for the 'then' and 'else' clauses in a conditional node + identify the promoted variables (but these cannot be wrapped in a regular + cleanup). - /* If the awaitable is a parm or a local variable, then we already have - a frame copy, so don't make a new one. */ - tree aw = TREE_OPERAND (aw_expr, 1); - tree o = TREE_OPERAND (aw_expr, 2); /* Initializer for the frame var. */ - /* If we have an initializer, then the var is a temp and we need to make - it in the frame. */ - tree aw_field_type = TREE_TYPE (aw); - tree aw_field_nam = NULL_TREE; - if (o) + So recurse through the lists and build up a composite list of captured vars. + Declare these and any guard variables needed to decide if a DTOR should be + run. Then embed the conditional into a try-finally expression that handles + running each DTOR conditionally on its guard variable. */ + +static void +process_conditional (var_nest_node *n, tree& vlist) +{ + tree init = n->init; + hash_map<tree, tree> var_flags; + vec<tree> var_list = vNULL; + tree new_then = push_stmt_list (); + handle_nested_conditionals (n->then_cl, var_list, var_flags); + new_then = pop_stmt_list (new_then); + tree new_else = push_stmt_list (); + handle_nested_conditionals (n->else_cl, var_list, var_flags); + new_else = pop_stmt_list (new_else); + /* Declare the vars. There are two loops so that the boolean flags are + grouped in the frame. */ + for (unsigned i = 0; i < var_list.length(); i++) { - /* The required field has the same type as the proxy stored in the - await expr. */ - char *nam = xasprintf ("__aw_s.%d", data->await_number); - aw_field_nam = coro_make_frame_entry (data->field_list, nam, - aw_field_type, aw_loc); - free (nam); - - /* If the init is a target expression, then we need to remake it to - strip off any extra cleanups added. */ - if (o && TREE_CODE (o) == TARGET_EXPR) - TREE_OPERAND (aw_expr, 2) = get_target_expr (TREE_OPERAND (o, 1)); + tree var = var_list[i]; + DECL_CHAIN (var) = vlist; + vlist = var; + add_decl_expr (var); } + /* Define the guard flags for variables that need a DTOR. */ + for (unsigned i = 0; i < var_list.length(); i++) + { + tree *flag = var_flags.get (var_list[i]); + if (flag) + { + DECL_INITIAL (*flag) = boolean_false_node; + DECL_CHAIN (*flag) = vlist; + vlist = *flag; + add_decl_expr (*flag); + } + } + tree new_if + = build4 (IF_STMT, void_type_node, COND_EXPR_COND (init), + new_then, new_else, NULL_TREE); + /* Build a set of conditional DTORs. */ + tree final_actions = push_stmt_list (); + while (!var_list.is_empty()) + { + tree var = var_list.pop (); + tree *flag = var_flags.get (var); + if (!flag) + continue; + tree var_type = TREE_TYPE (var); + tree cleanup + = build_special_member_call (var, complete_dtor_identifier, + NULL, var_type, LOOKUP_NORMAL, + tf_warning_or_error); + tree cond_cleanup = begin_if_stmt (); + finish_if_stmt_cond (*flag, cond_cleanup); + finish_expr_stmt (cleanup); + finish_then_clause (cond_cleanup); + finish_if_stmt (cond_cleanup); + } + final_actions = pop_stmt_list (final_actions); + tree try_finally + = build2 (TRY_FINALLY_EXPR, void_type_node, new_if, final_actions); + add_stmt (try_finally); +} - tree v = TREE_OPERAND (aw_expr, 3); - o = TREE_VEC_ELT (v, 1); - if (TREE_CODE (o) == TARGET_EXPR) - TREE_VEC_ELT (v, 1) = get_target_expr (TREE_OPERAND (o, 1)); +/* Given *STMT, that contains at least one await expression. - register_await_info (aw_expr, aw_field_type, aw_field_nam); + The full expression represented in the original source code will contain + suspension points, but it is still required that the lifetime of temporary + values extends to the end of the expression. - /* Count how many awaits the current expression contains. */ - data->saw_awaits++; - /* Each await suspend context is unique, this is a function-wide value. */ - data->await_number++; + We already have a mechanism to 'promote' user-authored local variables + to a coroutine frame counterpart (which allows explicit management of the + lifetime across suspensions). The transform here re-writes STMT into + a bind expression, promotes temporary values into local variables in that + and flattens the statement into a series of cleanups. - /* We now need to know if to take special action on lifetime extension - of temporaries captured by reference. This can only happen if such - a case appears in the initializer for the awaitable. The callback - records captured temporaries including subtrees of initializers. */ - hash_set<tree> visited; - tree res = cp_walk_tree (&TREE_OPERAND (aw_expr, 2), captures_temporary, d, - &visited); - return res; -} + Conditional expressions are re-written to regular 'if' statements. + The cleanups for variables initialized inside a conditional (including + nested cases) are wrapped in a try-finally clause, with guard variables + to determine which DTORs need to be run. */ -/* The gimplifier correctly extends the lifetime of temporaries captured - by reference (per. [class.temporary] (6.9) "A temporary object bound - to a reference parameter in a function call persists until the completion - of the full-expression containing the call"). However, that is not - sufficient to work across a suspension - and we need to promote such - temporaries to be regular vars that will then get a coro frame slot. - We don't want to incur the effort of checking for this unless we have - an await expression in the current full expression. */ - -/* This takes the statement which contains one or more temporaries that have - been 'captured' by reference in the initializer(s) of co_await(s). - The statement is replaced by a bind expression that has actual variables - to replace the temporaries. These variables will be added to the coro- - frame in the same manner as user-authored ones. */ - -static void -replace_statement_captures (tree *stmt, void *d) +static tree +maybe_promote_temps (tree *stmt, void *d) { susp_frame_data *awpts = (susp_frame_data *) d; + location_t sloc = EXPR_LOCATION (*stmt); - tree aw_bind - = build3_loc (sloc, BIND_EXPR, void_type_node, NULL, NULL, NULL); - - /* Any cleanup point expression might no longer be necessary, since we - are removing one or more temporaries. */ - tree aw_statement_current = *stmt; - if (TREE_CODE (aw_statement_current) == CLEANUP_POINT_EXPR) - aw_statement_current = TREE_OPERAND (aw_statement_current, 0); - - /* Collected the scope vars we need move the temps to regular. */ - tree aw_bind_body = push_stmt_list (); - tree varlist = NULL_TREE; - int vnum = -1; - while (!awpts->to_replace->is_empty ()) + tree expr = *stmt; + /* Strip off uninteresting wrappers. */ + if (TREE_CODE (expr) == CLEANUP_POINT_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == EXPR_STMT) + expr = EXPR_STMT_EXPR (expr); + if (TREE_CODE (expr) == CONVERT_EXPR + && VOID_TYPE_P (TREE_TYPE (expr))) + expr = TREE_OPERAND (expr, 0); + STRIP_NOPS (expr); + + /* We walk the statement trees, flattening it into an ordered list of + variables with initializers and fragments corresponding to compound + expressions, truth or/and if and ternary conditionals. Conditional + expressions carry a nested list of fragments for the then and else + clauses. We anchor to the 'bottom' of the fragment list; we will write + a cleanup nest with one shell for each variable initialized. */ + var_nest_node *root = new var_nest_node (NULL_TREE, expr, NULL, NULL); + /* Check to see we didn't promote one twice. */ + hash_set<tree> promoted_vars; + hash_set<tree> used_temps; + flatten_await_stmt (root, &promoted_vars, &used_temps, NULL); + + gcc_checking_assert (root->next == NULL); + tree vlist = NULL_TREE; + var_nest_node *t = root; + gcc_checking_assert (!t->var); + /* We build the bind scope expression from the bottom-up. + EXPR_LIST holds the inner expression nest at the current cleanup + level (becoming the final expression list when we've exhausted the + number of sub-expression fragments). */ + tree expr_list = NULL_TREE; + do { - tree to_replace = awpts->to_replace->pop (); - tree orig_temp; - if (TREE_CODE (to_replace) == CO_AWAIT_EXPR) + tree new_list = push_stmt_list (); + /* When we have a promoted variable, then add that to the bind scope + and initialize it. When there's no promoted variable, we just need + to run the initializer. + If the initializer is a conditional expression, we need to collect + and declare any promoted variables nested within it. DTORs for such + variables must be run conditionally too. */ + if (t->var && DECL_NAME (t->var)) { - orig_temp = TREE_OPERAND (to_replace, 3); - orig_temp = TREE_VEC_ELT (orig_temp, 2); - orig_temp = TREE_OPERAND (orig_temp, 0); + tree var = t->var; + DECL_CHAIN (var) = vlist; + vlist = var; + add_decl_expr (var); + if (TREE_CODE (t->init) == COND_EXPR) + process_conditional (t, vlist); + else + finish_expr_stmt (t->init); + tree var_type = TREE_TYPE (var); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (var_type)) + { + tree cleanup + = build_special_member_call (var, complete_dtor_identifier, + NULL, var_type, LOOKUP_NORMAL, + tf_warning_or_error); + tree cl = build_stmt (sloc, CLEANUP_STMT, expr_list, cleanup, var); + add_stmt (cl); /* push this onto the level above. */ + } + else if (expr_list) + add_stmt (expr_list); + else + gcc_unreachable (); } else - orig_temp = TREE_OPERAND (to_replace, 0); - - tree var_type = TREE_TYPE (orig_temp); - gcc_checking_assert (same_type_p (TREE_TYPE (to_replace), var_type)); - /* Build a variable to hold the captured value, this will be included - in the frame along with any user-authored locals. */ - char *nam = xasprintf ("aw_%d.tmp.%d", awpts->await_number, ++vnum); - tree newvar = build_lang_decl (VAR_DECL, get_identifier (nam), var_type); - free (nam); - /* If we have better location than the whole expression use that, else - fall back to the expression loc. */ - DECL_CONTEXT (newvar) = DECL_CONTEXT (orig_temp); - if (DECL_SOURCE_LOCATION (orig_temp)) - sloc = DECL_SOURCE_LOCATION (orig_temp); - else - sloc = EXPR_LOCATION (*stmt); - DECL_SOURCE_LOCATION (newvar) = sloc; - DECL_CHAIN (newvar) = varlist; - varlist = newvar; /* Chain it onto the list for the bind expr. */ - /* Declare and initialize it in the new bind scope. */ - add_decl_expr (newvar); - tree new_s = build2_loc (sloc, INIT_EXPR, var_type, newvar, to_replace); - new_s = coro_build_cvt_void_expr_stmt (new_s, sloc); - add_stmt (new_s); - - /* Replace all instances of that temp in the original expr. */ - proxy_replace pr = {to_replace, newvar}; - cp_walk_tree (&aw_statement_current, replace_proxy, &pr, NULL); - } - - /* What's left should be the original statement with any co_await captured - temporaries broken out. Other temporaries might remain so see if we - need to wrap the revised statement in a cleanup. */ - aw_statement_current = maybe_cleanup_point_expr_void (aw_statement_current); - add_stmt (aw_statement_current); - - BIND_EXPR_BODY (aw_bind) = pop_stmt_list (aw_bind_body); - awpts->captured_temps.empty (); - - BIND_EXPR_VARS (aw_bind) = nreverse (varlist); + { + if (TREE_CODE (t->init) == COND_EXPR) + process_conditional (t, vlist); + else + finish_expr_stmt (t->init); + if (expr_list) + add_stmt (expr_list); + } + expr_list = pop_stmt_list (new_list); + var_nest_node *old = t; + t = t->prev; + delete old; + } while (t); + + /* Now produce the bind expression containing the 'promoted' temporaries + as its variable list, and the cleanup nest as the statement. */ + tree await_bind = build3_loc (sloc, BIND_EXPR, void_type_node, + NULL, NULL, NULL); + BIND_EXPR_BODY (await_bind) = expr_list; + BIND_EXPR_VARS (await_bind) = nreverse (vlist); tree b_block = make_node (BLOCK); if (!awpts->block_stack->is_empty ()) { @@ -2965,37 +3123,12 @@ replace_statement_captures (tree *stmt, void *d) BLOCK_SUBBLOCKS (s_block) = b_block; } } - BIND_EXPR_BLOCK (aw_bind) = b_block; - TREE_SIDE_EFFECTS (aw_bind) = TREE_SIDE_EFFECTS (BIND_EXPR_BODY (aw_bind)); - *stmt = aw_bind; -} - -/* This is called for single statements from the co-await statement walker. - It checks to see if the statement contains any co-awaits and, if so, - whether any of these 'capture' a temporary by reference. */ - -static tree -maybe_promote_captured_temps (tree *stmt, void *d) -{ - susp_frame_data *awpts = (susp_frame_data *) d; + BLOCK_VARS (b_block) = BIND_EXPR_VARS (await_bind) ; + BIND_EXPR_BLOCK (await_bind) = b_block; + TREE_SIDE_EFFECTS (await_bind) = TREE_SIDE_EFFECTS (BIND_EXPR_BODY (await_bind)); + *stmt = await_bind; hash_set<tree> visited; - awpts->saw_awaits = 0; - - /* When register_awaits sees an await, it walks the initializer for - that await looking for temporaries captured by reference and notes - them in awpts->captured_temps. */ - - if (tree res = cp_walk_tree (stmt, register_awaits, d, &visited)) - return res; /* We saw some reason to abort the tree walk. */ - - /* We only need to take any action here if the statement contained any - awaits and any of those had temporaries captured by reference in their - initializers. */ - - if (awpts->saw_awaits > 0 && !awpts->captured_temps.is_empty ()) - replace_statement_captures (stmt, d); - - return NULL_TREE; + return cp_walk_tree (stmt, register_awaits, d, &visited); } /* Lightweight callback to determine two key factors: @@ -3004,6 +3137,7 @@ maybe_promote_captured_temps (tree *stmt, void *d) TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion so that the await expressions are not processed in the case of the short-circuit arm. + CO_YIELD expressions are re-written to their underlying co_await. */ static tree @@ -3020,6 +3154,9 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d) /* FALLTHROUGH */ case CO_AWAIT_EXPR: awpts->saw_awaits++; + /* A non-null initializer for the awaiter means we need to expand. */ + if (TREE_OPERAND (*stmt, 2)) + awpts->has_awaiter_init = true; break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: @@ -3053,15 +3190,13 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d) /* Given *EXPR If EXPR contains a TRUTH_{AND,OR}IF_EXPR, TAOIE with an await expr on - the conditional branch expand this to: + the conditionally executed branch, change this in a ternary operator. bool not_expr = TAOIE == TRUTH_ORIF_EXPR ? NOT : NOP; - A) bool t = always exec expr - if (not_expr (t)) - B) t = conditionally exec expr - c) EXPR' = EXPR with TAOIE replaced by t. + not_expr (always-exec expr) ? conditionally-exec expr : not_expr; - Then repeat this for A, B and C. */ + Apply this recursively to the condition and the conditionally-exec + branch. */ struct truth_if_transform { tree *orig_stmt; @@ -3087,47 +3222,26 @@ expand_one_truth_if (tree *expr, int *do_subtree, void *d) break; location_t sloc = EXPR_LOCATION (*expr); - tree type = TREE_TYPE (xform->scratch_var); - gcc_checking_assert (TREE_CODE (type) == BOOLEAN_TYPE); - tree new_list = push_stmt_list (); - /* Init our scratch with the unconditionally-evaluated expr. */ - tree new_s = build2_loc (sloc, INIT_EXPR, boolean_type_node, - xform->scratch_var, - TREE_OPERAND (*expr, 0)); - finish_expr_stmt (new_s); - tree *pre = tsi_stmt_ptr (tsi_last (new_list)); - tree if_cond = xform->scratch_var; + /* Transform truth expression into a cond expression with + * the always-executed arm as the condition. + * the conditionally-executed arm as the then clause. + * the 'else' clause is fixed: 'true' for ||,'false' for &&. */ + tree cond = TREE_OPERAND (*expr, 0); + tree test1 = TREE_OPERAND (*expr, 1); + tree fixed = needs_not ? boolean_true_node : boolean_false_node; if (needs_not) - if_cond = build1 (TRUTH_NOT_EXPR, boolean_type_node, if_cond); - tree if_stmt = begin_if_stmt (); - finish_if_stmt_cond (if_cond, if_stmt); - /* If we take the if branch, then overwrite scratch with the cond - executed branch. */ - new_s = build2 (INIT_EXPR, boolean_type_node, - xform->scratch_var, TREE_OPERAND (*expr, 1)); - finish_expr_stmt (new_s); - finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); - *expr = xform->scratch_var; /* now contains the result. */ - /* So now we've got a statement list expanding one TAOIe. */ - add_stmt (*xform->orig_stmt); - tree *post = tsi_stmt_ptr (tsi_last (new_list)); - *xform->orig_stmt = pop_stmt_list (new_list); - /* Now recurse into the pre, if and post parts. */ - truth_if_transform sub_data = {pre, xform->scratch_var, - xform->truth_aoif_to_expand}; - if (tree res = cp_walk_tree (pre, expand_one_truth_if, &sub_data, - NULL)) + cond = build1 (TRUTH_NOT_EXPR, boolean_type_node, cond); + tree cond_expr + = build3_loc (sloc, COND_EXPR, boolean_type_node, + cond, test1, fixed); + *expr = cond_expr; + if (tree res = cp_walk_tree (&COND_EXPR_COND (*expr), + expand_one_truth_if, d, NULL)) return res; - sub_data.orig_stmt = &THEN_CLAUSE (if_stmt); - if (tree res = cp_walk_tree (&THEN_CLAUSE (if_stmt), - expand_one_truth_if, &sub_data, NULL)) + if (tree res = cp_walk_tree (&COND_EXPR_THEN (*expr), + expand_one_truth_if, d, NULL)) return res; - sub_data.orig_stmt = post; - if (tree res = cp_walk_tree (post, expand_one_truth_if, &sub_data, - NULL)) - return res; - /* We've done the sub-trees here. */ + /* We've manually processed necessary sub-trees here. */ *do_subtree = 0; } break; @@ -3142,7 +3256,6 @@ static tree add_var_to_bind (tree& bind, tree var_type, const char *nam_root, unsigned nam_vers) { - tree b_vars = BIND_EXPR_VARS (bind); /* Build a variable to hold the condition, this will be included in the frame as a local var. */ @@ -3208,14 +3321,20 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) } /* We have something to be handled as a single statement. */ + bool has_cleanup_wrapper = TREE_CODE (*stmt) == CLEANUP_POINT_EXPR; hash_set<tree> visited; awpts->saw_awaits = 0; hash_set<tree> truth_aoif_to_expand; awpts->truth_aoif_to_expand = &truth_aoif_to_expand; awpts->needs_truth_if_exp = false; - - if (STATEMENT_CLASS_P (*stmt)) - switch (TREE_CODE (*stmt)) + awpts->has_awaiter_init = false; + tree expr = *stmt; + if (has_cleanup_wrapper) + expr = TREE_OPERAND (expr, 0); + STRIP_NOPS (expr); + + if (STATEMENT_CLASS_P (expr)) + switch (TREE_CODE (expr)) { /* Unless it's a special case, just walk the subtrees as usual. */ default: return NULL_TREE; @@ -3231,7 +3350,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) if (cond) then stmt1 else stmt2. */ tree if_stmt = *stmt; /* We treat the condition as if it was a stand-alone statement, - to see if there are any await expressions which will be analysed + to see if there are any await expressions which will be analyzed and registered. */ if ((res = cp_walk_tree (&IF_COND (if_stmt), analyze_expression_awaits, d, &visited))) @@ -3255,13 +3374,6 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) tree new_s = build2_loc (sloc, MODIFY_EXPR, boolean_type_node, newvar, cond_inner); finish_expr_stmt (new_s); - if (awpts->needs_truth_if_exp) - { - tree *sp = tsi_stmt_ptr (tsi_last (insert_list)); - truth_if_transform xf = {sp, newvar, &truth_aoif_to_expand}; - if ((res = cp_walk_tree (sp, expand_one_truth_if, &xf, NULL))) - return res; - } IF_COND (if_stmt) = newvar; add_stmt (if_stmt); *stmt = pop_stmt_list (insert_list); @@ -3327,7 +3439,6 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) d, NULL); *do_subtree = 0; /* Done subtrees. */ return res; - } break; case SWITCH_STMT: @@ -3371,8 +3482,57 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) return res; } break; + case CO_RETURN_EXPR: + { + /* Expand the co_return as per [stmt.return.coroutine] + - for co_return; + { p.return_void (); goto final_suspend; } + - for co_return [void expr]; + { expr; p.return_void(); goto final_suspend;} + - for co_return [non void expr]; + { p.return_value(expr); goto final_suspend; } */ + if ((res = cp_walk_tree (stmt, analyze_expression_awaits, + d, &visited))) + return res; + location_t loc = EXPR_LOCATION (expr); + tree call = TREE_OPERAND (expr, 1); + expr = TREE_OPERAND (expr, 0); + tree ret_list = push_stmt_list (); + /* [stmt.return.coroutine], 2.2 + If expr is present and void, it is placed immediately before + the call for return_void; */ + tree *maybe_await_stmt = NULL; + if (expr && VOID_TYPE_P (TREE_TYPE (expr))) + { + finish_expr_stmt (expr); + /* If the return argument was a void expression, then any + awaits must be contained in that. */ + maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list)); + } + /* Insert p.return_{void,value(expr)}. */ + finish_expr_stmt (call); + /* Absent a return of a void expression, any awaits must be in + the parameter to return_value(). */ + if (!maybe_await_stmt) + maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list)); + expr = build1_loc (loc, GOTO_EXPR, void_type_node, awpts->fs_label); + finish_expr_stmt (expr); + *stmt = pop_stmt_list (ret_list); + /* Once this is complete, we will have processed subtrees. */ + *do_subtree = 0; + if (awpts->saw_awaits) + { + gcc_checking_assert (maybe_await_stmt); + res = cp_walk_tree (maybe_await_stmt, await_statement_walker, + d, NULL); + if (res) + return res; + } + return NULL_TREE; /* Done. */ + } + break; } - else if (EXPR_P (*stmt)) + else if (EXPR_P (expr)) { if ((res = cp_walk_tree (stmt, analyze_expression_awaits, d, &visited))) return res; @@ -3380,31 +3540,19 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) if (!awpts->saw_awaits) return NULL_TREE; /* Nothing special to do here. */ - /* Unless we need to expand any truth-and/or-if expressions, then the - remaining action is to check for temporaries to await expressions - captured by refence. */ - if (!awpts->needs_truth_if_exp) - return maybe_promote_captured_temps (stmt, d); - - gcc_checking_assert (!awpts->bind_stack->is_empty()); - tree& bind_expr = awpts->bind_stack->last (); - /* Build a variable to hold the condition, this will be - included in the frame as a local var. */ - tree newvar = add_var_to_bind (bind_expr, boolean_type_node, - "taoi", awpts->cond_number++); - tree insert_list = push_stmt_list (); - add_decl_expr (newvar); - add_stmt (*stmt); - tree *sp = tsi_stmt_ptr (tsi_last (insert_list)); - *stmt = pop_stmt_list (insert_list); - - truth_if_transform xf = {sp, newvar, &truth_aoif_to_expand}; - if ((res = cp_walk_tree (sp, expand_one_truth_if, &xf, NULL))) - return res; - /* Process the expanded trees. */ - return cp_walk_tree (stmt, await_statement_walker, d, NULL); + if (awpts->needs_truth_if_exp) + { + /* If a truth-and/or-if expression has an await expression in the + conditionally-taken branch, then it must be rewritten into a + regular conditional. */ + truth_if_transform xf = {stmt, NULL_TREE, &truth_aoif_to_expand}; + if ((res = cp_walk_tree (stmt, expand_one_truth_if, &xf, NULL))) + return res; + } + /* Process this statement, which contains at least one await expression + to 'promote' temporary values to a coroutine frame slot. */ + return maybe_promote_temps (stmt, d); } - /* Continue recursion, if needed. */ return res; } @@ -3420,6 +3568,9 @@ struct param_frame_data bool param_seen; }; +/* A tree-walk callback that records the use of parameters (to allow for + optimizations where handling unused parameters may be omitted). */ + static tree register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) { @@ -3455,7 +3606,21 @@ register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d) return NULL_TREE; } -/* For figuring out what local variable usage we have. */ +/* Small helper for the repetitive task of adding a new field to the coro + frame type. */ + +static tree +coro_make_frame_entry (tree *field_list, const char *name, tree fld_type, + location_t loc) +{ + tree id = get_identifier (name); + tree decl = build_decl (loc, FIELD_DECL, id, fld_type); + DECL_CHAIN (decl) = *field_list; + *field_list = decl; + return id; +} + +/* For recording local variable usage. */ struct local_vars_frame_data { @@ -3467,6 +3632,10 @@ struct local_vars_frame_data bool local_var_seen; }; +/* A tree-walk callback that processes one bind expression noting local + variables, and making a coroutine frame slot available for those that + need it, so that they can be 'promoted' across suspension points. */ + static tree register_local_var_uses (tree *stmt, int *do_subtree, void *d) { @@ -3523,11 +3692,11 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) tree lvname = DECL_NAME (lvar); char *buf; if (lvname != NULL_TREE) - buf = xasprintf ("__lv.%u.%u.%s", lvd->bind_indx, lvd->nest_depth, - IDENTIFIER_POINTER (lvname)); + buf = xasprintf ("__%s.%u.%u", IDENTIFIER_POINTER (lvname), + lvd->nest_depth, lvd->bind_indx); else - buf = xasprintf ("__lv.%u.%u.D%u", lvd->bind_indx, lvd->nest_depth, - DECL_UID (lvar)); + buf = xasprintf ("_D%u.%u.%u", DECL_UID (lvar), lvd->nest_depth, + lvd->bind_indx); /* TODO: Figure out if we should build a local type that has any excess alignment or size from the original decl. */ local_var.field_id @@ -3631,7 +3800,7 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, fn_start, NULL, /*musthave=*/true); /* Create and initialize the initial-await-resume-called variable per [dcl.fct.def.coroutine] / 5.3. */ - tree i_a_r_c = build_lang_decl (VAR_DECL, get_identifier ("__i_a_r_c"), + tree i_a_r_c = build_lang_decl (VAR_DECL, get_identifier ("i_a_r_c"), boolean_type_node); DECL_ARTIFICIAL (i_a_r_c) = true; DECL_CHAIN (i_a_r_c) = var_list; @@ -3760,9 +3929,7 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, short __resume_at; handle_type self_handle; (maybe) parameter copies. - coro1::suspend_never_prt __is; - coro1::suspend_always_prt __fs; - (maybe) local variables saved + (maybe) local variables saved (including awaitables) (maybe) trailing space. }; */ @@ -3844,7 +4011,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* 2. Types we need to define or look up. */ tree fr_name = get_fn_local_identifier (orig, "frame"); - tree coro_frame_type = xref_tag (record_type, fr_name, ts_current, false); + tree coro_frame_type = xref_tag (record_type, fr_name); DECL_CONTEXT (TYPE_NAME (coro_frame_type)) = current_scope (); tree coro_frame_ptr = build_pointer_type (coro_frame_type); tree act_des_fn_type @@ -3885,7 +4052,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) (void) coro_make_frame_entry (&field_list, "__self_h", handle_type, fn_start); /* Now add in fields for function params (if there are any). - We do not attempt elision of copies at this stage, we do analyse the + We do not attempt elision of copies at this stage, we do analyze the uses and build worklists to replace those when the state machine is lowered. */ @@ -3966,8 +4133,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) to promote any temporaries that are captured by reference (to regular vars) they will get added to the coro frame along with other locals. */ susp_frame_data body_aw_points - = {&field_list, handle_type, NULL, NULL, 0, 0, - hash_set<tree> (), NULL, NULL, 0, false, false}; + = {&field_list, handle_type, fs_label, NULL, NULL, 0, 0, + hash_set<tree> (), NULL, NULL, 0, false, false, false}; body_aw_points.block_stack = make_tree_vector (); body_aw_points.bind_stack = make_tree_vector (); body_aw_points.to_replace = make_tree_vector (); @@ -4018,7 +4185,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) add_decl_expr (coro_fp); /* The CO_FRAME internal function is a mechanism to allow the middle end - to adjust the allocation in response to optimisations. We provide the + to adjust the allocation in response to optimizations. We provide the current conservative estimate of the frame size (as per the current) computed layout. */ tree frame_size = TYPE_SIZE_UNIT (coro_frame_type); @@ -4143,7 +4310,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) non-throwing noexcept-specification. So we need std::nothrow. */ tree std_nt = lookup_qualified_name (std_node, get_identifier ("nothrow"), - 0, /*complain=*/true, false); + LOOK_want::NORMAL, + /*complain=*/true); if (!std_nt || std_nt == error_mark_node) error_at (fn_start, "%qE is provided by %qT but %<std::nothrow%> " "cannot be found", grooaf, promise_type); @@ -4555,7 +4723,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Build the actor... */ build_actor_fn (fn_start, coro_frame_type, actor, fnbody, orig, param_uses, - &local_var_uses, param_dtor_list, fs_label, resume_fn_field, + &local_var_uses, param_dtor_list, resume_fn_field, body_aw_points.await_number, frame_size); /* Destroyer ... */ diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 0e949e2..44c9d24 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -49,66 +49,6 @@ static tree cp_fold_r (tree *, int *, void *); static void cp_genericize_tree (tree*, bool); static tree cp_fold (tree); -/* Local declarations. */ - -enum bc_t { bc_break = 0, bc_continue = 1 }; - -/* Stack of labels which are targets for "break" or "continue", - linked through TREE_CHAIN. */ -static tree bc_label[2]; - -/* Begin a scope which can be exited by a break or continue statement. BC - indicates which. - - Just creates a label with location LOCATION and pushes it into the current - context. */ - -static tree -begin_bc_block (enum bc_t bc, location_t location) -{ - tree label = create_artificial_label (location); - DECL_CHAIN (label) = bc_label[bc]; - bc_label[bc] = label; - if (bc == bc_break) - LABEL_DECL_BREAK (label) = true; - else - LABEL_DECL_CONTINUE (label) = true; - return label; -} - -/* Finish a scope which can be exited by a break or continue statement. - LABEL was returned from the most recent call to begin_bc_block. BLOCK is - an expression for the contents of the scope. - - If we saw a break (or continue) in the scope, append a LABEL_EXPR to - BLOCK. Otherwise, just forget the label. */ - -static void -finish_bc_block (tree *block, enum bc_t bc, tree label) -{ - gcc_assert (label == bc_label[bc]); - - if (TREE_USED (label)) - append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label), - block); - - bc_label[bc] = DECL_CHAIN (label); - DECL_CHAIN (label) = NULL_TREE; -} - -/* Get the LABEL_EXPR to represent a break or continue statement - in the current block scope. BC indicates which. */ - -static tree -get_bc_label (enum bc_t bc) -{ - tree label = bc_label[bc]; - - /* Mark the label used for finish_bc_block. */ - TREE_USED (label) = 1; - return label; -} - /* Genericize a TRY_BLOCK. */ static void @@ -231,228 +171,6 @@ genericize_if_stmt (tree *stmt_p) *stmt_p = stmt; } -/* Build a generic representation of one of the C loop forms. COND is the - loop condition or NULL_TREE. BODY is the (possibly compound) statement - controlled by the loop. INCR is the increment expression of a for-loop, - or NULL_TREE. COND_IS_FIRST indicates whether the condition is - evaluated before the loop body as in while and for loops, or after the - loop body as in do-while loops. */ - -static void -genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, - tree incr, bool cond_is_first, int *walk_subtrees, - void *data) -{ - tree blab, clab; - tree exit = NULL; - tree stmt_list = NULL; - tree debug_begin = NULL; - - protected_set_expr_location_if_unset (incr, start_locus); - - cp_walk_tree (&cond, cp_genericize_r, data, NULL); - cp_walk_tree (&incr, cp_genericize_r, data, NULL); - - blab = begin_bc_block (bc_break, start_locus); - clab = begin_bc_block (bc_continue, start_locus); - - cp_walk_tree (&body, cp_genericize_r, data, NULL); - *walk_subtrees = 0; - - if (MAY_HAVE_DEBUG_MARKER_STMTS - && (!cond || !integer_zerop (cond))) - { - debug_begin = build0 (DEBUG_BEGIN_STMT, void_type_node); - SET_EXPR_LOCATION (debug_begin, cp_expr_loc_or_loc (cond, start_locus)); - } - - if (cond && TREE_CODE (cond) != INTEGER_CST) - { - /* If COND is constant, don't bother building an exit. If it's false, - we won't build a loop. If it's true, any exits are in the body. */ - location_t cloc = cp_expr_loc_or_loc (cond, start_locus); - exit = build1_loc (cloc, GOTO_EXPR, void_type_node, - get_bc_label (bc_break)); - exit = fold_build3_loc (cloc, COND_EXPR, void_type_node, cond, - build_empty_stmt (cloc), exit); - } - - if (exit && cond_is_first) - { - append_to_statement_list (debug_begin, &stmt_list); - debug_begin = NULL_TREE; - append_to_statement_list (exit, &stmt_list); - } - append_to_statement_list (body, &stmt_list); - finish_bc_block (&stmt_list, bc_continue, clab); - if (incr) - { - if (MAY_HAVE_DEBUG_MARKER_STMTS) - { - tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); - SET_EXPR_LOCATION (d, cp_expr_loc_or_loc (incr, start_locus)); - append_to_statement_list (d, &stmt_list); - } - append_to_statement_list (incr, &stmt_list); - } - append_to_statement_list (debug_begin, &stmt_list); - if (exit && !cond_is_first) - append_to_statement_list (exit, &stmt_list); - - if (!stmt_list) - stmt_list = build_empty_stmt (start_locus); - - tree loop; - if (cond && integer_zerop (cond)) - { - if (cond_is_first) - loop = fold_build3_loc (start_locus, COND_EXPR, - void_type_node, cond, stmt_list, - build_empty_stmt (start_locus)); - else - loop = stmt_list; - } - else - { - location_t loc = start_locus; - if (!cond || integer_nonzerop (cond)) - loc = EXPR_LOCATION (expr_first (body)); - if (loc == UNKNOWN_LOCATION) - loc = start_locus; - loop = build1_loc (loc, LOOP_EXPR, void_type_node, stmt_list); - } - - stmt_list = NULL; - append_to_statement_list (loop, &stmt_list); - finish_bc_block (&stmt_list, bc_break, blab); - if (!stmt_list) - stmt_list = build_empty_stmt (start_locus); - - *stmt_p = stmt_list; -} - -/* Genericize a FOR_STMT node *STMT_P. */ - -static void -genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - tree expr = NULL; - tree loop; - tree init = FOR_INIT_STMT (stmt); - - if (init) - { - cp_walk_tree (&init, cp_genericize_r, data, NULL); - append_to_statement_list (init, &expr); - } - - genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt), - FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data); - append_to_statement_list (loop, &expr); - if (expr == NULL_TREE) - expr = loop; - *stmt_p = expr; -} - -/* Genericize a WHILE_STMT node *STMT_P. */ - -static void -genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt), - WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees, data); -} - -/* Genericize a DO_STMT node *STMT_P. */ - -static void -genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt), - DO_BODY (stmt), NULL_TREE, 0, walk_subtrees, data); -} - -/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */ - -static void -genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - tree break_block, body, cond, type; - location_t stmt_locus = EXPR_LOCATION (stmt); - - body = SWITCH_STMT_BODY (stmt); - if (!body) - body = build_empty_stmt (stmt_locus); - cond = SWITCH_STMT_COND (stmt); - type = SWITCH_STMT_TYPE (stmt); - - cp_walk_tree (&cond, cp_genericize_r, data, NULL); - - break_block = begin_bc_block (bc_break, stmt_locus); - - cp_walk_tree (&body, cp_genericize_r, data, NULL); - cp_walk_tree (&type, cp_genericize_r, data, NULL); - *walk_subtrees = 0; - - if (TREE_USED (break_block)) - SWITCH_BREAK_LABEL_P (break_block) = 1; - finish_bc_block (&body, bc_break, break_block); - *stmt_p = build2_loc (stmt_locus, SWITCH_EXPR, type, cond, body); - SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt); - gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt) - || !TREE_USED (break_block)); -} - -/* Genericize a CONTINUE_STMT node *STMT_P. */ - -static void -genericize_continue_stmt (tree *stmt_p) -{ - tree stmt_list = NULL; - tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN); - tree label = get_bc_label (bc_continue); - location_t location = EXPR_LOCATION (*stmt_p); - tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label); - append_to_statement_list_force (pred, &stmt_list); - append_to_statement_list (jump, &stmt_list); - *stmt_p = stmt_list; -} - -/* Genericize a BREAK_STMT node *STMT_P. */ - -static void -genericize_break_stmt (tree *stmt_p) -{ - tree label = get_bc_label (bc_break); - location_t location = EXPR_LOCATION (*stmt_p); - *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label); -} - -/* Genericize a OMP_FOR node *STMT_P. */ - -static void -genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) -{ - tree stmt = *stmt_p; - location_t locus = EXPR_LOCATION (stmt); - tree clab = begin_bc_block (bc_continue, locus); - - cp_walk_tree (&OMP_FOR_BODY (stmt), cp_genericize_r, data, NULL); - if (TREE_CODE (stmt) != OMP_TASKLOOP) - cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL); - cp_walk_tree (&OMP_FOR_INIT (stmt), cp_genericize_r, data, NULL); - cp_walk_tree (&OMP_FOR_COND (stmt), cp_genericize_r, data, NULL); - cp_walk_tree (&OMP_FOR_INCR (stmt), cp_genericize_r, data, NULL); - cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_genericize_r, data, NULL); - *walk_subtrees = 0; - - finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab); -} - /* Hook into the middle of gimplifying an OMP_FOR node. */ static enum gimplify_status @@ -1244,7 +962,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) omp_cxx_notice_variable (wtd->omp_ctx, stmt); /* Don't dereference parms in a thunk, pass the references through. */ - if ((TREE_CODE (stmt) == CALL_EXPR && CALL_FROM_THUNK_P (stmt)) + if ((TREE_CODE (stmt) == CALL_EXPR && call_from_lambda_thunk_p (stmt)) || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt))) { *walk_subtrees = 0; @@ -1262,21 +980,17 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) /* Map block scope extern declarations to visible declarations with the same name and type in outer scopes if any. */ - if (cp_function_chain->extern_decl_map - && VAR_OR_FUNCTION_DECL_P (stmt) - && DECL_EXTERNAL (stmt)) - { - struct cxx_int_tree_map *h, in; - in.uid = DECL_UID (stmt); - h = cp_function_chain->extern_decl_map->find_with_hash (&in, in.uid); - if (h) - { - *stmt_p = h->to; - TREE_USED (h->to) |= TREE_USED (stmt); - *walk_subtrees = 0; - return NULL; - } - } + if (VAR_OR_FUNCTION_DECL_P (stmt) && DECL_LOCAL_DECL_P (stmt)) + if (tree alias = DECL_LOCAL_DECL_ALIAS (stmt)) + { + if (alias != error_mark_node) + { + *stmt_p = alias; + TREE_USED (alias) |= TREE_USED (stmt); + } + *walk_subtrees = 0; + return NULL; + } if (TREE_CODE (stmt) == INTEGER_CST && TYPE_REF_P (TREE_TYPE (stmt)) @@ -1495,6 +1209,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) { tree using_directive = make_node (IMPORTED_DECL); TREE_TYPE (using_directive) = void_type_node; + DECL_CONTEXT (using_directive) = current_function_decl; IMPORTED_DECL_ASSOCIATED_DECL (using_directive) = decl; DECL_CHAIN (using_directive) = BLOCK_VARS (block); @@ -1564,7 +1279,8 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) break; } if (TREE_CODE (stmt) == OMP_TASKLOOP) - genericize_omp_for_stmt (stmt_p, walk_subtrees, data); + c_genericize_control_stmt (stmt_p, walk_subtrees, data, + cp_genericize_r, cp_walk_subtrees); else cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL); wtd->omp_ctx = omp_ctx.outer; @@ -1635,103 +1351,10 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); break; - case FOR_STMT: - genericize_for_stmt (stmt_p, walk_subtrees, data); - break; - - case WHILE_STMT: - genericize_while_stmt (stmt_p, walk_subtrees, data); - break; - - case DO_STMT: - genericize_do_stmt (stmt_p, walk_subtrees, data); - break; - - case SWITCH_STMT: - genericize_switch_stmt (stmt_p, walk_subtrees, data); - break; - - case CONTINUE_STMT: - genericize_continue_stmt (stmt_p); - break; - - case BREAK_STMT: - genericize_break_stmt (stmt_p); - break; - case SPACESHIP_EXPR: *stmt_p = genericize_spaceship (*stmt_p); break; - case OMP_DISTRIBUTE: - /* Need to explicitly instantiate copy ctors on class iterators of - composite distribute parallel for. */ - if (OMP_FOR_INIT (*stmt_p) == NULL_TREE) - { - tree *data[4] = { NULL, NULL, NULL, NULL }; - tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p), - find_combined_omp_for, data, NULL); - if (inner != NULL_TREE - && TREE_CODE (inner) == OMP_FOR) - { - for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++) - if (OMP_FOR_ORIG_DECLS (inner) - && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), - i)) == TREE_LIST - && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), - i))) - { - tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i); - /* Class iterators aren't allowed on OMP_SIMD, so the only - case we need to solve is distribute parallel for. */ - gcc_assert (TREE_CODE (inner) == OMP_FOR - && data[1]); - tree orig_decl = TREE_PURPOSE (orig); - tree c, cl = NULL_TREE; - for (c = OMP_FOR_CLAUSES (inner); - c; c = OMP_CLAUSE_CHAIN (c)) - if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) - && OMP_CLAUSE_DECL (c) == orig_decl) - { - cl = c; - break; - } - if (cl == NULL_TREE) - { - for (c = OMP_PARALLEL_CLAUSES (*data[1]); - c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_DECL (c) == orig_decl) - { - cl = c; - break; - } - } - if (cl) - { - orig_decl = require_complete_type (orig_decl); - tree inner_type = TREE_TYPE (orig_decl); - if (orig_decl == error_mark_node) - continue; - if (TYPE_REF_P (TREE_TYPE (orig_decl))) - inner_type = TREE_TYPE (inner_type); - - while (TREE_CODE (inner_type) == ARRAY_TYPE) - inner_type = TREE_TYPE (inner_type); - get_copy_ctor (inner_type, tf_warning_or_error); - } - } - } - } - /* FALLTHRU */ - case OMP_FOR: - case OMP_SIMD: - case OMP_LOOP: - case OACC_LOOP: - genericize_omp_for_stmt (stmt_p, walk_subtrees, data); - break; - case PTRMEM_CST: /* By the time we get here we're handing off to the back end, so we don't need or want to preserve PTRMEM_CST anymore. */ @@ -1867,6 +1490,84 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) } break; + case OMP_DISTRIBUTE: + /* Need to explicitly instantiate copy ctors on class iterators of + composite distribute parallel for. */ + if (OMP_FOR_INIT (*stmt_p) == NULL_TREE) + { + tree *data[4] = { NULL, NULL, NULL, NULL }; + tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p), + find_combined_omp_for, data, NULL); + if (inner != NULL_TREE + && TREE_CODE (inner) == OMP_FOR) + { + for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++) + if (OMP_FOR_ORIG_DECLS (inner) + && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), + i)) == TREE_LIST + && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), + i))) + { + tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i); + /* Class iterators aren't allowed on OMP_SIMD, so the only + case we need to solve is distribute parallel for. */ + gcc_assert (TREE_CODE (inner) == OMP_FOR + && data[1]); + tree orig_decl = TREE_PURPOSE (orig); + tree c, cl = NULL_TREE; + for (c = OMP_FOR_CLAUSES (inner); + c; c = OMP_CLAUSE_CHAIN (c)) + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (c) == orig_decl) + { + cl = c; + break; + } + if (cl == NULL_TREE) + { + for (c = OMP_PARALLEL_CLAUSES (*data[1]); + c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (c) == orig_decl) + { + cl = c; + break; + } + } + if (cl) + { + orig_decl = require_complete_type (orig_decl); + tree inner_type = TREE_TYPE (orig_decl); + if (orig_decl == error_mark_node) + continue; + if (TYPE_REF_P (TREE_TYPE (orig_decl))) + inner_type = TREE_TYPE (inner_type); + + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); + get_copy_ctor (inner_type, tf_warning_or_error); + } + } + } + } + /* FALLTHRU */ + + case FOR_STMT: + case WHILE_STMT: + case DO_STMT: + case SWITCH_STMT: + case CONTINUE_STMT: + case BREAK_STMT: + case OMP_FOR: + case OMP_SIMD: + case OMP_LOOP: + case OACC_LOOP: + /* These cases are handled by shared code. */ + c_genericize_control_stmt (stmt_p, walk_subtrees, data, + cp_genericize_r, cp_walk_subtrees); + break; + default: if (IS_TYPE_OR_DECL_P (stmt)) *walk_subtrees = 0; @@ -2032,11 +1733,8 @@ cp_genericize (tree fndecl) return; /* Allow cp_genericize calls to be nested. */ - tree save_bc_label[2]; - save_bc_label[bc_break] = bc_label[bc_break]; - save_bc_label[bc_continue] = bc_label[bc_continue]; - bc_label[bc_break] = NULL_TREE; - bc_label[bc_continue] = NULL_TREE; + bc_state_t save_state; + save_bc_state (&save_state); /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ @@ -2046,11 +1744,7 @@ cp_genericize (tree fndecl) /* Do everything else. */ c_genericize (fndecl); - - gcc_assert (bc_label[bc_break] == NULL); - gcc_assert (bc_label[bc_continue] == NULL); - bc_label[bc_break] = save_bc_label[bc_break]; - bc_label[bc_continue] = save_bc_label[bc_continue]; + restore_bc_state (&save_state); } /* Build code to apply FN to each member of ARG1 and ARG2. FN may be @@ -2356,7 +2050,7 @@ cxx_omp_predetermined_mapping (tree decl) /* Finalize an implicitly determined clause. */ void -cxx_omp_finish_clause (tree c, gimple_seq *) +cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) { tree decl, inner_type; bool make_shared = false; diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index dfd8be9..e1397b7 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -314,13 +314,8 @@ cxx_block_may_fallthru (const_tree stmt) return true; return block_may_fallthru (ELSE_CLAUSE (stmt)); - case SWITCH_STMT: - return (!SWITCH_STMT_ALL_CASES_P (stmt) - || !SWITCH_STMT_NO_BREAK_P (stmt) - || block_may_fallthru (SWITCH_STMT_BODY (stmt))); - default: - return true; + return c_block_may_fallthru (stmt); } } @@ -332,11 +327,12 @@ cp_get_global_decls () return NAMESPACE_LEVEL (global_namespace)->names; } -/* Push DECL into the current scope. */ +/* Push DECL into the current (namespace) scope. */ tree cp_pushdecl (tree decl) { + DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); return pushdecl (decl); } @@ -354,7 +350,7 @@ identifier_global_value (tree name) tree identifier_global_tag (tree name) { - tree ret = lookup_qualified_name (global_namespace, name, /*prefer_type*/2, + tree ret = lookup_qualified_name (global_namespace, name, LOOK_want::TYPE, /*complain*/false); if (ret == error_mark_node) return NULL_TREE; @@ -477,20 +473,14 @@ cp_common_init_ts (void) MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION); /* Statements. */ - MARK_TS_EXP (BREAK_STMT); MARK_TS_EXP (CLEANUP_STMT); - MARK_TS_EXP (CONTINUE_STMT); - MARK_TS_EXP (DO_STMT); MARK_TS_EXP (EH_SPEC_BLOCK); - MARK_TS_EXP (FOR_STMT); MARK_TS_EXP (HANDLER); MARK_TS_EXP (IF_STMT); MARK_TS_EXP (OMP_DEPOBJ); MARK_TS_EXP (RANGE_FOR_STMT); - MARK_TS_EXP (SWITCH_STMT); MARK_TS_EXP (TRY_BLOCK); MARK_TS_EXP (USING_STMT); - MARK_TS_EXP (WHILE_STMT); /* Random expressions. */ MARK_TS_EXP (ADDRESSOF_EXPR); diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index de8d606..0936f16 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -115,6 +115,8 @@ extern tree cxx_simulate_enum_decl (location_t, const char *, #define LANG_HOOKS_BLOCK_MAY_FALLTHRU cxx_block_may_fallthru #undef LANG_HOOKS_EMITS_BEGIN_STMT #define LANG_HOOKS_EMITS_BEGIN_STMT true +#undef LANG_HOOKS_FINALIZE_EARLY_DEBUG +#define LANG_HOOKS_FINALIZE_EARLY_DEBUG c_common_finalize_early_debug /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 99851eb..a188576 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -194,7 +194,9 @@ DEFTREECODE (BOUND_TEMPLATE_TEMPLATE_PARM, "bound_template_template_parm", /* For template template argument of the form `T::template C'. TYPE_CONTEXT is `T', the template parameter dependent object. - TYPE_NAME is an IDENTIFIER_NODE for `C', the member class template. */ + TYPE_NAME is a TEMPLATE_DECL, whose DECL_TEMPLATE_PARMS are any + template parms of the instantiation. That decl's DECL_NAME is the + IDENTIFIER_NODE for `C', the member class template. */ DEFTREECODE (UNBOUND_CLASS_TEMPLATE, "unbound_class_template", tcc_type, 0) /* A using declaration. USING_DECL_SCOPE contains the specified @@ -298,35 +300,12 @@ DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", tcc_statement, 3) and COND_EXPR for the benefit of templates. */ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4) -/* Used to represent a `for' statement. The operands are - FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively. */ -DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5) - /* Used to represent a range-based `for' statement. The operands are RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE, RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in templates. */ DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6) -/* Used to represent a 'while' statement. The operands are WHILE_COND - and WHILE_BODY, respectively. */ -DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2) - -/* Used to represent a 'do' statement. The operands are DO_BODY and - DO_COND, respectively. */ -DEFTREECODE (DO_STMT, "do_stmt", tcc_statement, 2) - -/* Used to represent a 'break' statement. */ -DEFTREECODE (BREAK_STMT, "break_stmt", tcc_statement, 0) - -/* Used to represent a 'continue' statement. */ -DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_statement, 0) - -/* Used to represent a 'switch' statement. The operands are - SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE, and - SWITCH_STMT_SCOPE, respectively. */ -DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_statement, 4) - /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to obtain the expression. */ DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1) @@ -522,11 +501,13 @@ DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0) of the wildcard. */ DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0) -/* A requires-expr is a binary expression. The first operand is +/* A requires-expr has three operands. The first operand is its parameter list (possibly NULL). The second is a list of requirements, which are denoted by the _REQ* tree codes - below. */ -DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 2) + below. The third is a TREE_VEC of template arguments to + be applied when substituting into the parameter list and + requirements, set by tsubst_requires_expr for partial instantiations. */ +DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 3) /* A requirement for an expression. */ DEFTREECODE (SIMPLE_REQ, "simple_req", tcc_expression, 1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2aa8ebe..4672561 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1,4 +1,4 @@ -/* Definitions for C++ parsing and type checking. +/* Definitions for -*- C++ -*- parsing and type checking. Copyright (C) 1987-2020 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -148,6 +148,7 @@ enum cp_tree_index CPTI_DELTA_IDENTIFIER, CPTI_IN_CHARGE_IDENTIFIER, CPTI_VTT_PARM_IDENTIFIER, + CPTI_AS_BASE_IDENTIFIER, CPTI_THIS_IDENTIFIER, CPTI_PFN_IDENTIFIER, CPTI_VPTR_IDENTIFIER, @@ -289,6 +290,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; /* The name of the parameter that contains a pointer to the VTT to use for this subobject constructor or destructor. */ #define vtt_parm_identifier cp_global_trees[CPTI_VTT_PARM_IDENTIFIER] +#define as_base_identifier cp_global_trees[CPTI_AS_BASE_IDENTIFIER] #define this_identifier cp_global_trees[CPTI_THIS_IDENTIFIER] #define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER] #define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER] @@ -391,7 +393,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; CLEANUP_P (in TRY_BLOCK) AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF, SCOPE_REF) - PAREN_STRING_LITERAL (in STRING_CST) + PAREN_STRING_LITERAL_P (in STRING_CST) CP_DECL_THREAD_LOCAL_P (in VAR_DECL) KOENIG_LOOKUP_P (in CALL_EXPR) STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST). @@ -462,9 +464,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT) LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR) IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR) - TINFO_VAR_DECLARED_CONSTINIT (in TEMPLATE_INFO) - CALL_FROM_NEW_OR_DELETE_P (in CALL_EXPR) - 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). + 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) BIND_EXPR_BODY_BLOCK (in BIND_EXPR) @@ -486,7 +486,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR) 6: TYPE_MARKED_P (in _TYPE) - DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL) + DECL_NONTRIVIALLY_INITIALIZED_P (in VAR_DECL) RANGE_FOR_IVDEP (in RANGE_FOR_STMT) CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR) CONSTRUCTOR_IS_DESIGNATED_INIT (in CONSTRUCTOR) @@ -504,7 +504,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; Usage of DECL_LANG_FLAG_?: 0: DECL_TEMPLATE_PARM_P (in PARM_DECL, CONST_DECL, TYPE_DECL, or TEMPLATE_DECL) - DECL_LOCAL_FUNCTION_P (in FUNCTION_DECL) + DECL_LOCAL_DECL_P (in FUNCTION_DECL, VAR_DECL) DECL_MUTABLE_P (in FIELD_DECL) DECL_DEPENDENT_P (in USING_DECL) LABEL_DECL_BREAK (in LABEL_DECL) @@ -515,7 +515,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_VLA_CAPTURE_P (in FIELD_DECL) DECL_ARRAY_PARAMETER_P (in PARM_DECL) LABEL_DECL_CONTINUE (in LABEL_DECL) - 2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL). + 2: DECL_THIS_EXTERN (in VAR_DECL, FUNCTION_DECL or PARM_DECL) DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL) DECL_CONSTRAINT_VAR_P (in a PARM_DECL) TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL) @@ -527,11 +527,12 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_SELF_REFERENCE_P (in a TYPE_DECL) DECL_INVALID_OVERRIDER_P (in a FUNCTION_DECL) 5: DECL_INTERFACE_KNOWN. - 6: DECL_THIS_STATIC (in VAR_DECL or FUNCTION_DECL). + 6: DECL_THIS_STATIC (in VAR_DECL, FUNCTION_DECL or PARM_DECL) DECL_FIELD_IS_BASE (in FIELD_DECL) TYPE_DECL_ALIAS_P (in TYPE_DECL) 7: DECL_THUNK_P (in a member FUNCTION_DECL) DECL_NORMAL_CAPTURE_P (in FIELD_DECL) + DECL_DECLARED_CONSTINIT_P (in VAR_DECL) 8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL) Usage of language-independent fields in a language-dependent manner: @@ -783,8 +784,7 @@ struct GTY(()) tree_overload { /* Iterator for a 1 dimensional overload. Permits iterating over the outer level of a 2-d overload when explicitly enabled. */ -class ovl_iterator -{ +class ovl_iterator { tree ovl; const bool allow_inner; /* Only used when checking. */ @@ -872,8 +872,7 @@ class ovl_iterator /* Iterator over a (potentially) 2 dimensional overload, which is produced by name lookup. */ -class lkp_iterator : public ovl_iterator -{ +class lkp_iterator : public ovl_iterator { typedef ovl_iterator parent; tree outer; @@ -905,8 +904,7 @@ class lkp_iterator : public ovl_iterator /* hash traits for declarations. Hashes potential overload sets via DECL_NAME. */ -struct named_decl_hash : ggc_remove <tree> -{ +struct named_decl_hash : ggc_remove <tree> { typedef tree value_type; /* A DECL or OVERLOAD */ typedef tree compare_type; /* An identifier. */ @@ -1356,8 +1354,8 @@ struct GTY (()) tree_trait_expr { (IDENTIFIER_NODE_CHECK(NODE)->base.protected_flag) /* Based off of TYPE_UNNAMED_P. */ -#define LAMBDA_TYPE_P(NODE) \ - (TREE_CODE (NODE) == RECORD_TYPE \ +#define LAMBDA_TYPE_P(NODE) \ + (TREE_CODE (NODE) == RECORD_TYPE \ && TYPE_LINKAGE_IDENTIFIER (NODE) \ && IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE))) @@ -1445,8 +1443,8 @@ struct GTY (()) tree_lambda_expr tree extra_scope; vec<tree, va_gc> *pending_proxies; location_t locus; - enum cp_lambda_default_capture_mode_type default_capture_mode; - int discriminator; + enum cp_lambda_default_capture_mode_type default_capture_mode : 8; + short int discriminator; }; /* Non-zero if this template specialization has access violations that @@ -1463,11 +1461,6 @@ struct GTY (()) tree_lambda_expr #define TINFO_USED_TEMPLATE_ID(NODE) \ (TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE))) -/* Non-zero if this variable template specialization was declared with the - `constinit' specifier. */ -#define TINFO_VAR_DECLARED_CONSTINIT(NODE) \ - (TREE_LANG_FLAG_2 (TEMPLATE_INFO_CHECK (NODE))) - /* The representation of a deferred access check. */ struct GTY(()) deferred_access_check { @@ -1624,6 +1617,21 @@ check_constraint_info (tree t) #define CONSTRAINED_PARM_PROTOTYPE(NODE) \ DECL_INITIAL (TYPE_DECL_CHECK (NODE)) +/* The list of local parameters introduced by this requires-expression, + in the form of a chain of PARM_DECLs. */ +#define REQUIRES_EXPR_PARMS(NODE) \ + TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 0) + +/* A TREE_LIST of the requirements for this requires-expression. + The requirements are stored in lexical order within the TREE_VALUE + of each TREE_LIST node. The TREE_PURPOSE of each node is unused. */ +#define REQUIRES_EXPR_REQS(NODE) \ + TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 1) + +/* Like PACK_EXPANSION_EXTRA_ARGS, for requires-expressions. */ +#define REQUIRES_EXPR_EXTRA_ARGS(NODE) \ + TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 2) + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -1918,7 +1926,6 @@ struct GTY(()) language_function { /* Tracking possibly infinite loops. This is a vec<tree> only because vec<bool> doesn't work with gtype. */ vec<tree, va_gc> *infinite_loops; - hash_table<cxx_int_tree_map_hasher> *extern_decl_map; }; /* The current C++-specific per-function global variables. */ @@ -2056,7 +2063,7 @@ enum languages { lang_c, lang_cplusplus }; #define CLASS_TYPE_P(T) \ (RECORD_OR_UNION_CODE_P (TREE_CODE (T)) && TYPE_LANG_FLAG_5 (T)) -/* Nonzero if T is a class type but not an union. */ +/* Nonzero if T is a class type but not a union. */ #define NON_UNION_CLASS_TYPE_P(T) \ (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T)) @@ -2649,8 +2656,10 @@ struct GTY(()) lang_decl_base { unsigned not_really_extern : 1; /* var or fn */ unsigned initialized_in_class : 1; /* var or fn */ unsigned threadprivate_or_deleted_p : 1; /* var or fn */ - unsigned anticipated_p : 1; /* fn, type or template */ - /* anticipated_p reused as DECL_OMP_PRIVATIZED_MEMBER in var */ + /* anticipated_p is no longer used for anticipated_decls (fn, type + or template). It is used as DECL_OMP_PRIVATIZED_MEMBER in + var. */ + unsigned anticipated_p : 1; unsigned friend_or_tls : 1; /* var, fn, type or template */ unsigned unknown_bound_p : 1; /* var */ unsigned odr_used : 1; /* var or fn */ @@ -2674,7 +2683,7 @@ struct GTY(()) lang_decl_base { /* DECL_LANG_SPECIFIC for the above codes. */ struct GTY(()) lang_decl_min { - struct lang_decl_base base; + struct lang_decl_base base; /* 32-bits. */ /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is THUNK_ALIAS. @@ -2687,6 +2696,7 @@ 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 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; }; @@ -2711,14 +2721,13 @@ struct GTY(()) lang_decl_fn { unsigned thunk_p : 1; unsigned this_thunk_p : 1; - unsigned hidden_friend_p : 1; unsigned omp_declare_reduction_p : 1; unsigned has_dependent_explicit_spec_p : 1; unsigned immediate_fn_p : 1; unsigned maybe_deleted : 1; unsigned coroutine_p : 1; - unsigned spare : 9; + unsigned spare : 10; /* 32-bits padding on 64-bit host. */ @@ -2737,8 +2746,7 @@ struct GTY(()) lang_decl_fn { union lang_decl_u5 { - /* In a non-thunk FUNCTION_DECL or TEMPLATE_DECL, this is - DECL_CLONED_FUNCTION. */ + /* In a non-thunk FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ tree GTY ((tag ("0"))) cloned_function; /* In a FUNCTION_DECL for which THUNK_P holds this is the @@ -2757,10 +2765,10 @@ struct GTY(()) lang_decl_fn { /* DECL_LANG_SPECIFIC for namespaces. */ struct GTY(()) lang_decl_ns { - struct lang_decl_base base; + struct lang_decl_base base; /* 32 bits. */ cp_binding_level *level; - /* Inline children. These need to be va_gc, because of PCH. */ + /* Inline children. Needs to be va_gc, because of PCH. */ vec<tree, va_gc> *inlinees; /* Hash table of bound decls. It'd be nice to have this inline, but @@ -2772,7 +2780,7 @@ struct GTY(()) lang_decl_ns { /* DECL_LANG_SPECIFIC for parameters. */ struct GTY(()) lang_decl_parm { - struct lang_decl_base base; + struct lang_decl_base base; /* 32 bits. */ int level; int index; }; @@ -3226,6 +3234,10 @@ struct GTY(()) lang_decl { #define DECL_EXTERN_C_FUNCTION_P(NODE) \ (DECL_NON_THUNK_FUNCTION_P (NODE) && DECL_EXTERN_C_P (NODE)) +/* Non-zero if this variable is declared `constinit' specifier. */ +#define DECL_DECLARED_CONSTINIT_P(NODE) \ + (DECL_LANG_FLAG_7 (VAR_DECL_CHECK (NODE))) + /* True if DECL is declared 'constexpr'. */ #define DECL_DECLARED_CONSTEXPR_P(DECL) \ DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL))) @@ -3436,7 +3448,10 @@ struct GTY(()) lang_decl { an instantiation of a template -- but, from the point of view of the language, each instantiation of S results in a wholly unrelated global function f. In this case, DECL_TEMPLATE_INFO for S<int>::f - will be non-NULL, but DECL_USE_TEMPLATE will be zero. */ + will be non-NULL, but DECL_USE_TEMPLATE will be zero. + + In a friend declaration, TI_TEMPLATE can be an overload set, or + identifier. */ #define DECL_TEMPLATE_INFO(NODE) \ (DECL_LANG_SPECIFIC (TEMPLATE_INFO_DECL_CHECK (NODE)) \ ->u.min.template_info) @@ -3484,13 +3499,12 @@ struct GTY(()) lang_decl { ? TYPE_ALIAS_TEMPLATE_INFO (NODE) \ : TYPE_TEMPLATE_INFO (NODE)) -/* Set the template information for an ENUMERAL_, RECORD_, or - UNION_TYPE to VAL. */ +/* Set the template information for a non-alias n ENUMERAL_, RECORD_, + or UNION_TYPE to VAL. ALIAS's are dealt with separately. */ #define SET_TYPE_TEMPLATE_INFO(NODE, VAL) \ - (TREE_CODE (NODE) == ENUMERAL_TYPE \ - || (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE)) \ - ? (TYPE_LANG_SLOT_1 (NODE) = (VAL)) \ - : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL))) + (gcc_checking_assert (TREE_CODE (NODE) == ENUMERAL_TYPE \ + || (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))), \ + (TYPE_LANG_SLOT_1 (NODE) = (VAL))) \ #define TI_TEMPLATE(NODE) \ ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->tmpl @@ -3802,6 +3816,11 @@ struct GTY(()) lang_decl { && TREE_TYPE (TREE_OPERAND (NODE, 0)) \ && TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0)))) +/* True iff this represents an lvalue being treated as an rvalue during return + or throw as per [class.copy.elision]. */ +#define IMPLICIT_RVALUE_P(NODE) \ + TREE_LANG_FLAG_3 (TREE_CHECK2 ((NODE), NON_LVALUE_EXPR, STATIC_CAST_EXPR)) + #define NEW_EXPR_USE_GLOBAL(NODE) \ TREE_LANG_FLAG_0 (NEW_EXPR_CHECK (NODE)) #define DELETE_EXPR_USE_GLOBAL(NODE) \ @@ -3821,11 +3840,6 @@ struct GTY(()) lang_decl { should be performed at instantiation time. */ #define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE)) -/* In a CALL_EXPR, true for allocator calls from new or delete - expressions. */ -#define CALL_FROM_NEW_OR_DELETE_P(NODE) \ - TREE_LANG_FLAG_2 (CALL_EXPR_CHECK (NODE)) - /* True if the arguments to NODE should be evaluated in left-to-right order regardless of PUSH_ARGS_REVERSED. */ #define CALL_EXPR_ORDERED_ARGS(NODE) \ @@ -4004,18 +4018,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define TYPE_CONTAINS_VPTR_P(NODE) \ (TYPE_POLYMORPHIC_P (NODE) || CLASSTYPE_VBASECLASSES (NODE)) -/* Nonzero if NODE is a FUNCTION_DECL (for a function with global - scope) declared in a local scope. */ -#define DECL_LOCAL_FUNCTION_P(NODE) \ - DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE)) - -/* Nonzero if NODE is the target for genericization of 'break' stmts. */ -#define LABEL_DECL_BREAK(NODE) \ - DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE)) +/* Nonzero if NODE is a FUNCTION_DECL or VARIABLE_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)) -/* Nonzero if NODE is the target for genericization of 'continue' stmts. */ -#define LABEL_DECL_CONTINUE(NODE) \ - DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE)) +/* The namespace-scope decl a DECL_LOCAL_DECL_P aliases. */ +#define DECL_LOCAL_DECL_ALIAS(NODE) \ + DECL_ACCESS ((gcc_checking_assert (DECL_LOCAL_DECL_P (NODE)), NODE)) /* Nonzero if NODE is the target for genericization of 'return' stmts in constructors/destructors of targetm.cxx.cdtor_returns_this targets. */ @@ -4029,35 +4039,16 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define FNDECL_USED_AUTO(NODE) \ TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE)) -/* Nonzero if NODE is a DECL which we know about but which has not - been explicitly declared, such as a built-in function or a friend - declared inside a class. In the latter case DECL_HIDDEN_FRIEND_P - will be set. */ -#define DECL_ANTICIPATED(NODE) \ - (DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \ - ->u.base.anticipated_p) - -/* Is DECL NODE a hidden name? */ -#define DECL_HIDDEN_P(NODE) \ - (DECL_LANG_SPECIFIC (NODE) && TYPE_FUNCTION_OR_TEMPLATE_DECL_P (NODE) \ - && DECL_ANTICIPATED (NODE)) - -/* True if this is a hidden class type. */ -#define TYPE_HIDDEN_P(NODE) \ - (DECL_LANG_SPECIFIC (TYPE_NAME (NODE)) \ - && DECL_ANTICIPATED (TYPE_NAME (NODE))) +/* True if NODE is an undeclared builtin decl. As soon as the user + declares it, the location will be updated. */ +#define DECL_UNDECLARED_BUILTIN_P(NODE) \ + (DECL_SOURCE_LOCATION(NODE) == BUILTINS_LOCATION) /* True for artificial decls added for OpenMP privatized non-static data members. */ #define DECL_OMP_PRIVATIZED_MEMBER(NODE) \ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.anticipated_p) -/* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend - within a class but has not been declared in the surrounding scope. - The function is invisible except via argument dependent lookup. */ -#define DECL_HIDDEN_FRIEND_P(NODE) \ - (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->hidden_friend_p) - /* Nonzero if NODE is an artificial FUNCTION_DECL for #pragma omp declare reduction. */ #define DECL_OMP_DECLARE_REDUCTION_P(NODE) \ @@ -4669,6 +4660,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) template parameters at each level. Each element in the vector is a TREE_LIST, whose TREE_VALUE is a PARM_DECL (if the parameter is a non-type parameter), or a TYPE_DECL (if the parameter is a type + parameter) or a TEMPLATE_DECL (if the parameter is a template parameter). The TREE_PURPOSE is the default value, if any. The TEMPLATE_PARM_INDEX for the parameter is available as the DECL_INITIAL (for a PARM_DECL) or as the TREE_TYPE (for a @@ -5068,25 +5060,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete. */ #define IF_STMT_EXTRA_ARGS(NODE) IF_SCOPE (NODE) -/* WHILE_STMT accessors. These give access to the condition of the - while statement and the body of the while statement, respectively. */ -#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0) -#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1) - -/* DO_STMT accessors. These give access to the condition of the do - statement and the body of the do statement, respectively. */ -#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0) -#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1) - -/* FOR_STMT accessors. These give access to the init statement, - condition, update expression, and body of the for statement, - respectively. */ -#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0) -#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1) -#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) -#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) -#define FOR_SCOPE(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 4) - /* RANGE_FOR_STMT accessors. These give access to the declarator, expression, body, and scope of the statement, respectively. */ #define RANGE_FOR_DECL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 0) @@ -5097,19 +5070,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) -#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) -#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) -#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) -#define SWITCH_STMT_SCOPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 3) -/* True if there are case labels for all possible values of switch cond, either - because there is a default: case label or because the case label ranges cover - all values. */ -#define SWITCH_STMT_ALL_CASES_P(NODE) \ - TREE_LANG_FLAG_0 (SWITCH_STMT_CHECK (NODE)) -/* True if the body of a switch stmt contains no BREAK_STMTs. */ -#define SWITCH_STMT_NO_BREAK_P(NODE) \ - TREE_LANG_FLAG_2 (SWITCH_STMT_CHECK (NODE)) - /* STMT_EXPR accessor. */ #define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) @@ -5182,7 +5142,8 @@ enum cp_lvalue_kind_flags { clk_rvalueref = 2,/* An xvalue (rvalue formed using an rvalue reference) */ clk_class = 4, /* A prvalue of class or array type. */ clk_bitfield = 8, /* An lvalue for a bit-field. */ - clk_packed = 16 /* An lvalue for a packed field. */ + clk_packed = 16, /* An lvalue for a packed field. */ + clk_implicit_rval = 1<<5 /* An lvalue being treated as an xvalue. */ }; /* This type is used for parameters and variables which hold @@ -5356,8 +5317,9 @@ extern GTY(()) tree integer_two_node; function, two inside the body of a function in a local class, etc.) */ extern int function_depth; -/* Nonzero if we are inside eq_specializations, which affects comparison of - PARM_DECLs in cp_tree_equal. */ +/* Nonzero if we are inside eq_specializations, which affects + comparison of PARM_DECLs in cp_tree_equal and alias specializations + in structrual_comptypes. */ extern int comparing_specializations; /* In parser.c. */ @@ -5558,18 +5520,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define LOOKUP_DESTRUCTOR (1 << 5) /* Do not permit references to bind to temporaries. */ #define LOOKUP_NO_TEMP_BIND (1 << 6) -/* Do not accept objects, and possibly namespaces. */ -#define LOOKUP_PREFER_TYPES (1 << 7) -/* Do not accept objects, and possibly types. */ -#define LOOKUP_PREFER_NAMESPACES (1 << 8) -/* Accept types or namespaces. */ -#define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES) -/* Return friend declarations and un-declared builtin functions. - (Normally, these entities are registered in the symbol table, but - not found by lookup.) */ -#define LOOKUP_HIDDEN (LOOKUP_PREFER_NAMESPACES << 1) /* We're trying to treat an lvalue as an rvalue. */ -#define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1) +/* FIXME remove when we extend the P1825 semantics to all standard modes, the + C++20 approach uses IMPLICIT_RVALUE_P instead. */ +#define LOOKUP_PREFER_RVALUE (LOOKUP_NO_TEMP_BIND << 1) /* We're inside an init-list, so narrowing conversions are ill-formed. */ #define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1) /* We're looking up a constructor for list-initialization. */ @@ -5599,13 +5553,11 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define LOOKUP_DELEGATING_CONS (LOOKUP_NO_NON_INTEGRAL << 1) /* Allow initialization of a flexible array members. */ #define LOOKUP_ALLOW_FLEXARRAY_INIT (LOOKUP_DELEGATING_CONS << 1) -/* Require constant initialization of a non-constant variable. */ -#define LOOKUP_CONSTINIT (LOOKUP_ALLOW_FLEXARRAY_INIT << 1) /* We're looking for either a rewritten comparison operator candidate or the operator to use on the former's result. We distinguish between the two by knowing that comparisons other than == and <=> must be the latter, as must a <=> expression trying to rewrite to <=> without reversing. */ -#define LOOKUP_REWRITTEN (LOOKUP_CONSTINIT << 1) +#define LOOKUP_REWRITTEN (LOOKUP_ALLOW_FLEXARRAY_INIT << 1) /* Reverse the order of the two arguments for comparison rewriting. First we swap the arguments in add_operator_candidates, then we swap the conversions in add_candidate (so that they correspond to the original order of the @@ -5615,13 +5567,6 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; /* We're initializing an aggregate from a parenthesized list of values. */ #define LOOKUP_AGGREGATE_PAREN_INIT (LOOKUP_REVERSED << 1) -#define LOOKUP_NAMESPACES_ONLY(F) \ - (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) -#define LOOKUP_TYPES_ONLY(F) \ - (!((F) & LOOKUP_PREFER_NAMESPACES) && ((F) & LOOKUP_PREFER_TYPES)) -#define LOOKUP_QUALIFIERS_ONLY(F) ((F) & LOOKUP_PREFER_BOTH) - - /* These flags are used by the conversion code. CONV_IMPLICIT : Perform implicit conversions (standard and user-defined). CONV_STATIC : Perform the explicit conversions for static_cast. @@ -5812,28 +5757,26 @@ const unsigned int STF_STRIP_DEPENDENT = 1U << 1; extern void init_reswords (void); /* Various flags for the overloaded operator information. */ -enum ovl_op_flags - { - OVL_OP_FLAG_NONE = 0, /* Don't care. */ - OVL_OP_FLAG_UNARY = 1, /* Is unary. */ - OVL_OP_FLAG_BINARY = 2, /* Is binary. */ - OVL_OP_FLAG_AMBIARY = 3, /* May be unary or binary. */ - OVL_OP_FLAG_ALLOC = 4, /* operator new or delete. */ - OVL_OP_FLAG_DELETE = 1, /* operator delete. */ - OVL_OP_FLAG_VEC = 2 /* vector new or delete. */ - }; +enum ovl_op_flags { + OVL_OP_FLAG_NONE = 0, /* Don't care. */ + OVL_OP_FLAG_UNARY = 1, /* Is unary. */ + OVL_OP_FLAG_BINARY = 2, /* Is binary. */ + OVL_OP_FLAG_AMBIARY = 3, /* May be unary or binary. */ + OVL_OP_FLAG_ALLOC = 4, /* operator new or delete. */ + OVL_OP_FLAG_DELETE = 1, /* operator delete. */ + OVL_OP_FLAG_VEC = 2 /* vector new or delete. */ +}; /* Compressed operator codes. Order is determined by operators.def and does not match that of tree_codes. */ -enum ovl_op_code - { - OVL_OP_ERROR_MARK, - OVL_OP_NOP_EXPR, +enum ovl_op_code { + OVL_OP_ERROR_MARK, + OVL_OP_NOP_EXPR, #define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) OVL_OP_##CODE, #define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) /* NOTHING */ #include "operators.def" - OVL_OP_MAX - }; + OVL_OP_MAX +}; struct GTY(()) ovl_op_info_t { /* The IDENTIFIER_NODE for the operator. */ @@ -6257,7 +6200,8 @@ extern bool null_member_pointer_value_p (tree); extern bool sufficient_parms_p (const_tree); extern tree type_decays_to (tree); extern tree extract_call_expr (tree); -extern tree build_trivial_dtor_call (tree); +extern tree build_trivial_dtor_call (tree, bool = false); +extern bool ref_conv_binds_directly_p (tree, tree); extern tree build_user_type_conversion (tree, tree, int, tsubst_flags_t); extern tree build_new_function_call (tree, vec<tree, va_gc> **, @@ -6363,6 +6307,7 @@ extern bool is_std_init_list (tree); extern bool is_list_ctor (tree); extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); +extern bool unsafe_return_slot_p (tree); extern bool cp_warn_deprecated_use (tree, tsubst_flags_t = tf_warning_or_error); extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); @@ -6497,7 +6442,9 @@ extern void note_iteration_stmt_body_end (bool); extern void determine_local_discriminator (tree); extern int decls_match (tree, tree, bool = true); extern bool maybe_version_functions (tree, tree, bool); -extern tree duplicate_decls (tree, tree, bool); +extern tree duplicate_decls (tree, tree, + bool hiding = false, + bool was_hidden = false); extern tree declare_local_label (tree); extern tree define_label (location_t, tree); extern void check_goto (tree); @@ -6537,8 +6484,9 @@ extern tree get_scope_of_declarator (const cp_declarator *); extern void grok_special_member_properties (tree); extern bool grok_ctor_properties (const_tree, const_tree); extern bool grok_op_properties (tree, bool); -extern tree xref_tag (enum tag_types, tree, tag_scope, bool); -extern tree xref_tag_from_type (tree, tree, tag_scope); +extern tree xref_tag (tag_types, tree, + TAG_how = TAG_how::CURRENT_ONLY, + bool tpl_header_p = false); extern void xref_basetypes (tree, tree); extern tree start_enum (tree, tree, tree, tree, bool, bool *); extern void finish_enum_value_list (tree); @@ -6566,7 +6514,6 @@ extern tree create_implicit_typedef (tree, tree); extern int local_variable_p (const_tree); extern tree register_dtor_fn (tree); extern tmpl_spec_kind current_tmpl_spec_kind (int); -extern tree cp_fname_init (const char *, tree *); extern tree cxx_builtin_function (tree decl); extern tree cxx_builtin_function_ext_scope (tree decl); extern tree cxx_simulate_builtin_function_decl (tree); @@ -6590,6 +6537,7 @@ extern bool check_array_designated_initializer (constructor_elt *, extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern tree build_explicit_specifier (tree, tsubst_flags_t); extern void do_push_parm_decls (tree, tree, tree *); +extern tree do_aggregate_paren_init (tree, tree); /* in decl2.c */ extern void record_mangling (tree, bool); @@ -6764,15 +6712,14 @@ extern tree build_vec_delete (location_t, tree, tree, extern tree create_temporary_var (tree); extern void initialize_vtbl_ptrs (tree); extern tree scalar_constant_value (tree); -extern tree decl_really_constant_value (tree); +extern tree decl_constant_value (tree, bool); +extern tree decl_really_constant_value (tree, bool = true); extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool); extern tree build_vtbl_address (tree); extern bool maybe_reject_flexarray_init (tree, tree); /* in lex.c */ extern void cxx_dup_lang_specific_decl (tree); -extern void yyungetc (int, int); - extern tree unqualified_name_lookup_error (tree, location_t = UNKNOWN_LOCATION); extern tree unqualified_fn_lookup_error (cp_expr); @@ -6801,7 +6748,6 @@ extern tree forward_parm (tree); extern bool is_trivially_xible (enum tree_code, tree, tree); extern bool is_xible (enum tree_code, tree, tree); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); -extern void after_nsdmi_defaulted_late_checks (tree); extern bool maybe_explain_implicit_delete (tree); extern void explain_implicit_non_constexpr (tree); extern void deduce_inheriting_ctor (tree); @@ -6818,6 +6764,7 @@ extern tree get_default_ctor (tree); extern tree get_dtor (tree, tsubst_flags_t); extern tree strip_inheriting_ctors (tree); extern tree inherited_ctor_binfo (tree); +extern bool base_ctor_omit_inherited_parms (tree); extern bool ctor_omit_inherited_parms (tree); extern tree locate_ctor (tree); extern tree implicitly_declare_fn (special_function_kind, tree, @@ -6887,8 +6834,7 @@ extern void end_template_parm_list (void); extern void end_template_decl (void); extern tree maybe_update_decl_type (tree, tree); extern bool check_default_tmpl_args (tree, tree, bool, bool, int); -extern tree push_template_decl (tree); -extern tree push_template_decl_real (tree, bool); +extern tree push_template_decl (tree, bool is_friend = false); extern tree add_inherited_template_parms (tree, tree); extern void template_parm_level_and_index (tree, int*, int*); extern bool redeclare_class_template (tree, tree, tree); @@ -6914,6 +6860,7 @@ extern void do_type_instantiation (tree, tree, tsubst_flags_t); extern bool always_instantiate_p (tree); extern bool maybe_instantiate_noexcept (tree, tsubst_flags_t = tf_warning_or_error); extern tree instantiate_decl (tree, bool, bool); +extern void maybe_instantiate_decl (tree); extern int comp_template_parms (const_tree, const_tree); extern bool template_heads_equivalent_p (const_tree, const_tree); extern bool builtin_pack_fn_p (tree); @@ -6991,7 +6938,9 @@ extern bool template_parm_object_p (const_tree); extern tree tparm_object_argument (tree); extern bool explicit_class_specialization_p (tree); extern bool push_tinst_level (tree); +extern bool push_tinst_level (tree, tree); extern bool push_tinst_level_loc (tree, location_t); +extern bool push_tinst_level_loc (tree, tree, location_t); extern void pop_tinst_level (void); extern struct tinst_level *outermost_tinst_level(void); extern void init_template_processing (void); @@ -7022,6 +6971,8 @@ extern bool template_guide_p (const_tree); extern bool builtin_guide_p (const_tree); extern void store_explicit_specifier (tree, tree); extern tree add_outermost_template_args (tree, tree); +extern tree add_extra_args (tree, tree); +extern tree build_extra_args (tree, tree, tsubst_flags_t); /* in rtti.c */ /* A vector of all tinfo decls that haven't been emitted yet. */ @@ -7237,7 +7188,7 @@ extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern tree omp_reduction_id (enum tree_code, tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); -extern void cp_check_omp_declare_reduction (tree); +extern bool cp_check_omp_declare_reduction (tree); extern void finish_omp_declare_simd_methods (tree); extern tree finish_omp_clauses (tree, enum c_omp_region_type); extern tree push_omp_privatization_clauses (bool); @@ -7311,6 +7262,7 @@ extern bool lambda_fn_in_template_p (tree); extern void maybe_add_lambda_conv_op (tree); extern bool is_lambda_ignored_entity (tree); extern bool lambda_static_thunk_p (tree); +extern bool call_from_lambda_thunk_p (tree); extern tree finish_builtin_launder (location_t, tree, tsubst_flags_t); extern tree cp_build_vec_convert (tree, location_t, tree, @@ -7397,7 +7349,7 @@ inline tree ovl_first (tree) ATTRIBUTE_PURE; extern tree ovl_make (tree fn, tree next = NULL_TREE); extern tree ovl_insert (tree fn, tree maybe_ovl, - bool using_p = false); + int using_or_hidden = 0); extern tree ovl_skip_hidden (tree) ATTRIBUTE_PURE; extern void lookup_mark (tree lookup, bool val); extern tree lookup_add (tree fns, tree lookup); @@ -7646,7 +7598,7 @@ extern tree cp_perform_integral_promotions (tree, tsubst_flags_t); extern tree finish_left_unary_fold_expr (tree, int); extern tree finish_right_unary_fold_expr (tree, int); extern tree finish_binary_fold_expr (tree, tree, int); -extern bool treat_lvalue_as_rvalue_p (tree, bool); +extern tree treat_lvalue_as_rvalue_p (tree, bool); extern bool decl_in_std_namespace_p (tree); /* in typeck2.c */ @@ -7729,7 +7681,7 @@ extern tree mangle_tls_wrapper_fn (tree); extern bool decl_tls_wrapper_p (tree); extern tree mangle_ref_init_variable (tree); extern tree mangle_template_parm_object (tree); -extern char * get_mangled_vtable_map_var_name (tree); +extern char *get_mangled_vtable_map_var_name (tree); extern bool mangle_return_type_p (tree); extern tree mangle_decomp (tree, vec<tree> &); @@ -7758,7 +7710,7 @@ extern tree cxx_omp_clause_default_ctor (tree, tree, tree); 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 *); +extern void cxx_omp_finish_clause (tree, gimple_seq *, bool); extern bool cxx_omp_privatize_by_reference (const_tree); extern bool cxx_omp_disregard_value_expr (tree, bool); extern void cp_fold_function (tree); @@ -7983,7 +7935,7 @@ extern tree coro_validate_builtin_call (tree, extern bool morph_fn_to_coro (tree, tree *, tree *); /* Inline bodies. */ - + inline tree ovl_first (tree node) { @@ -8117,6 +8069,27 @@ concept_check_p (const_tree t) return false; } +/* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference. */ + +inline bool +implicit_rvalue_p (const_tree t) +{ + if (REFERENCE_REF_P (t)) + t = TREE_OPERAND (t, 0); + return ((TREE_CODE (t) == NON_LVALUE_EXPR + || TREE_CODE (t) == STATIC_CAST_EXPR) + && IMPLICIT_RVALUE_P (t)); +} +inline tree +set_implicit_rvalue_p (tree ot) +{ + tree t = ot; + if (REFERENCE_REF_P (t)) + t = TREE_OPERAND (t, 0); + IMPLICIT_RVALUE_P (t) = 1; + return ot; +} + /* True if t is a "constrained auto" type-specifier. */ inline bool @@ -8125,6 +8098,24 @@ is_constrained_auto (const_tree t) return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS (t); } +/* RAII class to push/pop class scope T; if T is not a class, do nothing. */ + +struct push_nested_class_guard +{ + bool push; + push_nested_class_guard (tree t) + : push (t && CLASS_TYPE_P (t)) + { + if (push) + push_nested_class (t); + } + ~push_nested_class_guard () + { + if (push) + pop_nested_class (); + } +}; + #if CHECKING_P namespace selftest { extern void run_cp_tests (void); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 263f225..8bea79b 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1910,6 +1910,8 @@ pp_cxx_template_argument_list (cxx_pretty_printer *pp, tree t) if (TYPE_P (arg) || (TREE_CODE (arg) == TEMPLATE_DECL && TYPE_P (DECL_TEMPLATE_RESULT (arg)))) pp->type_id (arg); + else if (template_parm_object_p (arg)) + pp->expression (DECL_INITIAL (arg)); else pp->expression (arg); } @@ -2019,73 +2021,6 @@ cxx_pretty_printer::statement (tree t) } break; - case SWITCH_STMT: - pp_cxx_ws_string (this, "switch"); - pp_space (this); - pp_cxx_left_paren (this); - expression (SWITCH_STMT_COND (t)); - pp_cxx_right_paren (this); - pp_indentation (this) += 3; - pp_needs_newline (this) = true; - statement (SWITCH_STMT_BODY (t)); - pp_newline_and_indent (this, -3); - break; - - /* iteration-statement: - while ( expression ) statement - do statement while ( expression ) ; - for ( expression(opt) ; expression(opt) ; expression(opt) ) statement - for ( declaration expression(opt) ; expression(opt) ) statement */ - case WHILE_STMT: - pp_cxx_ws_string (this, "while"); - pp_space (this); - pp_cxx_left_paren (this); - expression (WHILE_COND (t)); - pp_cxx_right_paren (this); - pp_newline_and_indent (this, 3); - statement (WHILE_BODY (t)); - pp_indentation (this) -= 3; - pp_needs_newline (this) = true; - break; - - case DO_STMT: - pp_cxx_ws_string (this, "do"); - pp_newline_and_indent (this, 3); - statement (DO_BODY (t)); - pp_newline_and_indent (this, -3); - pp_cxx_ws_string (this, "while"); - pp_space (this); - pp_cxx_left_paren (this); - expression (DO_COND (t)); - pp_cxx_right_paren (this); - pp_cxx_semicolon (this); - pp_needs_newline (this) = true; - break; - - case FOR_STMT: - pp_cxx_ws_string (this, "for"); - pp_space (this); - pp_cxx_left_paren (this); - if (FOR_INIT_STMT (t)) - statement (FOR_INIT_STMT (t)); - else - pp_cxx_semicolon (this); - pp_needs_newline (this) = false; - pp_cxx_whitespace (this); - if (FOR_COND (t)) - expression (FOR_COND (t)); - pp_cxx_semicolon (this); - pp_needs_newline (this) = false; - pp_cxx_whitespace (this); - if (FOR_EXPR (t)) - expression (FOR_EXPR (t)); - pp_cxx_right_paren (this); - pp_newline_and_indent (this, 3); - statement (FOR_BODY (t)); - pp_indentation (this) -= 3; - pp_needs_newline (this) = true; - break; - case RANGE_FOR_STMT: pp_cxx_ws_string (this, "for"); pp_space (this); @@ -2109,17 +2044,6 @@ cxx_pretty_printer::statement (tree t) pp_needs_newline (this) = true; break; - /* jump-statement: - goto identifier; - continue ; - return expression(opt) ; */ - case BREAK_STMT: - case CONTINUE_STMT: - pp_string (this, TREE_CODE (t) == BREAK_STMT ? "break" : "continue"); - pp_cxx_semicolon (this); - pp_needs_newline (this) = true; - break; - /* expression-statement: expression(opt) ; */ case EXPR_STMT: diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 60a09e9..0fe74b2 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -75,7 +75,7 @@ static void record_unknown_type (tree, const char *); static int member_function_or_else (tree, tree, enum overload_flags); static tree local_variable_p_walkfn (tree *, int *, void *); static const char *tag_name (enum tag_types); -static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool); +static tree lookup_and_check_tag (enum tag_types, tree, TAG_how, bool); static void maybe_deduce_size_from_array_init (tree, tree); static void layout_var_decl (tree); static tree check_initializer (tree, tree, int, vec<tree, va_gc> **); @@ -692,8 +692,18 @@ poplevel (int keep, int reverse, int functionbody) /* Remove declarations for all the DECLs in this level. */ for (link = decls; link; link = TREE_CHAIN (link)) { - decl = TREE_CODE (link) == TREE_LIST ? TREE_VALUE (link) : link; - tree name = OVL_NAME (decl); + tree name; + if (TREE_CODE (link) == TREE_LIST) + { + decl = TREE_VALUE (link); + name = TREE_PURPOSE (link); + gcc_checking_assert (name); + } + else + { + decl = link; + name = DECL_NAME (decl); + } /* Remove the binding. */ if (TREE_CODE (decl) == LABEL_DECL) @@ -942,8 +952,11 @@ function_requirements_equivalent_p (tree newfn, tree oldfn) tree reqs2 = get_trailing_function_requirements (oldfn); if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE)) return false; + + /* Substitution is needed when friends are involved. */ reqs1 = maybe_substitute_reqs_for (reqs1, newfn); reqs2 = maybe_substitute_reqs_for (reqs2, oldfn); + return cp_tree_equal (reqs1, reqs2); } @@ -971,12 +984,6 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) if (TREE_CODE (newdecl) == FUNCTION_DECL) { - tree f1 = TREE_TYPE (newdecl); - tree f2 = TREE_TYPE (olddecl); - tree p1 = TYPE_ARG_TYPES (f1); - tree p2 = TYPE_ARG_TYPES (f2); - tree r2; - /* Specializations of different templates are different functions even if they have the same type. */ tree t1 = (DECL_USE_TEMPLATE (newdecl) @@ -999,14 +1006,20 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) && DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (newdecl)) return 0; + tree f1 = TREE_TYPE (newdecl); + tree f2 = TREE_TYPE (olddecl); if (TREE_CODE (f1) != TREE_CODE (f2)) return 0; /* A declaration with deduced return type should use its pre-deduction type for declaration matching. */ - r2 = fndecl_declared_return_type (olddecl); + tree r2 = fndecl_declared_return_type (olddecl); + tree r1 = fndecl_declared_return_type (newdecl); - if (same_type_p (TREE_TYPE (f1), r2)) + tree p1 = TYPE_ARG_TYPES (f1); + tree p2 = TYPE_ARG_TYPES (f2); + + if (same_type_p (r1, r2)) { if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl) && fndecl_built_in_p (olddecl)) @@ -1328,17 +1341,16 @@ check_redeclaration_no_default_args (tree decl) static void check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl, - bool olddecl_hidden_friend_p) + bool olddecl_hidden_p) { - if (!olddecl_hidden_friend_p && !DECL_FRIEND_P (newdecl)) + if (!olddecl_hidden_p && !DECL_FRIEND_P (newdecl)) return; - tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); - tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); - - for (; t1 && t1 != void_list_node; + for (tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl), + t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl); + t1 && t1 != void_list_node; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) - if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1)) + if ((olddecl_hidden_p && TREE_PURPOSE (t1)) || (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2))) { auto_diagnostic_group d; @@ -1422,13 +1434,17 @@ duplicate_function_template_decls (tree newdecl, tree olddecl) If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is returned. - NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */ + HIDING is true if the new decl is being hidden. WAS_HIDDEN is true + if the old decl was hidden. + + Hidden decls can be anticipated builtins, injected friends, or + (coming soon) injected from a local-extern decl. */ tree -duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) +duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) { unsigned olddecl_uid = DECL_UID (olddecl); - int olddecl_friend = 0, types_match = 0, hidden_friend = 0; + int olddecl_friend = 0, types_match = 0; int olddecl_hidden_friend = 0; int new_defines_function = 0; tree new_template_info; @@ -1451,15 +1467,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Check for redeclaration and other discrepancies. */ if (TREE_CODE (olddecl) == FUNCTION_DECL - && DECL_ARTIFICIAL (olddecl) - /* A C++20 implicit friend operator== uses the normal path (94462). */ - && !DECL_HIDDEN_FRIEND_P (olddecl)) + && DECL_UNDECLARED_BUILTIN_P (olddecl)) { if (TREE_CODE (newdecl) != FUNCTION_DECL) { /* Avoid warnings redeclaring built-ins which have not been explicitly declared. */ - if (DECL_ANTICIPATED (olddecl)) + if (was_hidden) { if (TREE_PUBLIC (newdecl) && CP_DECL_CONTEXT (newdecl) == global_namespace) @@ -1495,20 +1509,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) "declaration %q#D", newdecl, olddecl); return NULL_TREE; } - else if (DECL_OMP_DECLARE_REDUCTION_P (olddecl)) - { - gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (newdecl)); - error_at (newdecl_loc, - "redeclaration of %<pragma omp declare reduction%>"); - inform (olddecl_loc, - "previous %<pragma omp declare reduction%> declaration"); - return error_mark_node; - } else if (!types_match) { /* Avoid warnings redeclaring built-ins which have not been explicitly declared. */ - if (DECL_ANTICIPATED (olddecl)) + if (was_hidden) { tree t1, t2; @@ -1548,7 +1553,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) types_match = decls_match (newdecl, olddecl); if (types_match) return duplicate_decls (newdecl, olddecl, - newdecl_is_friend); + hiding, was_hidden); TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs; } goto next_arg; @@ -1640,7 +1645,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* If a function is explicitly declared "throw ()", propagate that to the corresponding builtin. */ if (DECL_BUILT_IN_CLASS (olddecl) == BUILT_IN_NORMAL - && DECL_ANTICIPATED (olddecl) + && was_hidden && TREE_NOTHROW (newdecl) && !TREE_NOTHROW (olddecl)) { @@ -1803,6 +1808,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) } } else if (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (newdecl)) + { + /* OMP UDRs are never duplicates. */ + gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (olddecl)); + error_at (newdecl_loc, + "redeclaration of %<pragma omp declare reduction%>"); + inform (olddecl_loc, + "previous %<pragma omp declare reduction%> declaration"); + return error_mark_node; + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL && ((DECL_TEMPLATE_SPECIALIZATION (olddecl) && (!DECL_TEMPLATE_INFO (newdecl) || (DECL_TI_TEMPLATE (newdecl) @@ -1972,7 +1988,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) declaration of the function or function template in the translation unit." */ check_no_redeclaration_friend_default_args - (olddecl, newdecl, DECL_HIDDEN_FRIEND_P (olddecl)); + (olddecl, newdecl, was_hidden); } } } @@ -2062,8 +2078,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE) /* Don't warn about extern decl followed by definition. */ && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)) - /* Don't warn about friends, let add_friend take care of it. */ - && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl)) + /* Don't warn if at least one is/was hidden. */ + && !(hiding || was_hidden) /* Don't warn about declaration followed by specialization. */ && (! DECL_TEMPLATE_SPECIALIZATION (newdecl) || DECL_TEMPLATE_SPECIALIZATION (olddecl))) @@ -2121,16 +2137,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (DECL_DECLARES_FUNCTION_P (olddecl)) { - olddecl_friend = DECL_FRIEND_P (olddecl); - olddecl_hidden_friend = DECL_HIDDEN_FRIEND_P (olddecl); - hidden_friend = (DECL_ANTICIPATED (olddecl) - && DECL_HIDDEN_FRIEND_P (olddecl) - && newdecl_is_friend); - if (!hidden_friend) - { - DECL_ANTICIPATED (olddecl) = 0; - DECL_HIDDEN_FRIEND_P (olddecl) = 0; - } + olddecl_friend = DECL_FRIEND_P (STRIP_TEMPLATE (olddecl)); + olddecl_hidden_friend = olddecl_friend && was_hidden; } if (TREE_CODE (newdecl) == TEMPLATE_DECL) @@ -2299,6 +2307,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl); DECL_DECLARED_CONSTEXPR_P (newdecl) |= DECL_DECLARED_CONSTEXPR_P (olddecl); + DECL_DECLARED_CONSTINIT_P (newdecl) + |= DECL_DECLARED_CONSTINIT_P (olddecl); /* Merge the threadprivate attribute from OLDDECL into NEWDECL. */ if (DECL_LANG_SPECIFIC (olddecl) @@ -2454,14 +2464,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) || (TREE_CODE (olddecl) == TEMPLATE_DECL && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL)))) - { - tree fn = olddecl; - - if (TREE_CODE (fn) == TEMPLATE_DECL) - fn = DECL_TEMPLATE_RESULT (olddecl); - - new_redefines_gnu_inline = GNU_INLINE_P (fn) && DECL_INITIAL (fn); - } + new_redefines_gnu_inline = GNU_INLINE_P (STRIP_TEMPLATE (olddecl)); if (!new_redefines_gnu_inline) { @@ -2527,7 +2530,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Merge parameter attributes. */ tree oldarg, newarg; - for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl); + for (oldarg = DECL_ARGUMENTS(olddecl), newarg = DECL_ARGUMENTS(newdecl); oldarg && newarg; oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg)) { @@ -2737,6 +2740,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) TREE_USED (newdecl) = 1; else if (TREE_USED (newdecl)) TREE_USED (olddecl) = 1; + if (VAR_P (newdecl)) { if (DECL_READ_P (olddecl)) @@ -2744,6 +2748,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) else if (DECL_READ_P (newdecl)) DECL_READ_P (olddecl) = 1; } + if (DECL_PRESERVE_P (olddecl)) DECL_PRESERVE_P (newdecl) = 1; else if (DECL_PRESERVE_P (newdecl)) @@ -2881,12 +2886,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) DECL_UID (olddecl) = olddecl_uid; if (olddecl_friend) - DECL_FRIEND_P (olddecl) = 1; - if (hidden_friend) - { - DECL_ANTICIPATED (olddecl) = 1; - DECL_HIDDEN_FRIEND_P (olddecl) = 1; - } + DECL_FRIEND_P (olddecl) = true; /* NEWDECL contains the merged attribute lists. Update OLDDECL to be the same. */ @@ -2993,6 +2993,10 @@ redeclaration_error_message (tree newdecl, tree olddecl) } } + if (deduction_guide_p (olddecl) + && deduction_guide_p (newdecl)) + return G_("deduction guide %q+D redeclared"); + /* [class.compare.default]: A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function. */ @@ -3043,24 +3047,28 @@ redeclaration_error_message (tree newdecl, tree olddecl) "%<gnu_inline%> attribute"); else return G_("%q+D redeclared inline without " - "%<gnu_inline%> attribute"); + "%<gnu_inline%> attribute"); } } - /* Core issue #226 (C++0x): - + if (deduction_guide_p (olddecl) + && deduction_guide_p (newdecl)) + return G_("deduction guide %q+D redeclared"); + + /* Core issue #226 (C++11): + If a friend function template declaration specifies a default template-argument, that declaration shall be a definition and shall be the only declaration of the function template in the translation unit. */ - if ((cxx_dialect != cxx98) + if ((cxx_dialect != cxx98) && TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot) - && !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl), + && !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl), /*is_primary=*/true, /*is_partial=*/false, /*is_friend_decl=*/2)) return G_("redeclaration of friend %q#D " - "may not have default template arguments"); + "may not have default template arguments"); return NULL; } @@ -3847,11 +3855,7 @@ tree build_typename_type (tree context, tree name, tree fullname, enum tag_types tag_type) { - tree t; - tree d; typename_info ti; - tree *e; - hashval_t hash; if (typename_htab == NULL) typename_htab = hash_table<typename_hasher>::create_ggc (61); @@ -3863,11 +3867,12 @@ build_typename_type (tree context, tree name, tree fullname, ti.class_p = (tag_type == class_type || tag_type == record_type || tag_type == union_type); - hash = (htab_hash_pointer (ti.scope) - ^ htab_hash_pointer (ti.name)); + hashval_t hash = (htab_hash_pointer (ti.scope) + ^ htab_hash_pointer (ti.name)); /* See if we already have this type. */ - e = typename_htab->find_slot_with_hash (&ti, hash, INSERT); + tree *e = typename_htab->find_slot_with_hash (&ti, hash, INSERT); + tree t = *e; if (*e) t = *e; else @@ -3880,10 +3885,10 @@ build_typename_type (tree context, tree name, tree fullname, TYPENAME_IS_CLASS_P (t) = ti.class_p; /* Build the corresponding TYPE_DECL. */ - d = build_decl (input_location, TYPE_DECL, name, t); - TYPE_NAME (TREE_TYPE (d)) = d; - TYPE_STUB_DECL (TREE_TYPE (d)) = d; - DECL_CONTEXT (d) = FROB_CONTEXT (context); + tree d = build_decl (input_location, TYPE_DECL, name, t); + TYPE_NAME (t) = d; + TYPE_STUB_DECL (t) = d; + DECL_CONTEXT (d) = ti.scope; DECL_ARTIFICIAL (d) = 1; /* Store it in the hash table. */ @@ -4056,9 +4061,6 @@ tree make_unbound_class_template (tree context, tree name, tree parm_list, tsubst_flags_t complain) { - tree t; - tree d; - if (TYPE_P (name)) name = TYPE_IDENTIFIER (name); else if (DECL_P (name)) @@ -4103,16 +4105,16 @@ make_unbound_class_template (tree context, tree name, tree parm_list, } /* Build the UNBOUND_CLASS_TEMPLATE. */ - t = cxx_make_type (UNBOUND_CLASS_TEMPLATE); + tree t = cxx_make_type (UNBOUND_CLASS_TEMPLATE); TYPE_CONTEXT (t) = FROB_CONTEXT (context); TREE_TYPE (t) = NULL_TREE; SET_TYPE_STRUCTURAL_EQUALITY (t); /* Build the corresponding TEMPLATE_DECL. */ - d = build_decl (input_location, TEMPLATE_DECL, name, t); - TYPE_NAME (TREE_TYPE (d)) = d; - TYPE_STUB_DECL (TREE_TYPE (d)) = d; - DECL_CONTEXT (d) = FROB_CONTEXT (context); + tree d = build_decl (input_location, TEMPLATE_DECL, name, t); + TYPE_NAME (t) = d; + TYPE_STUB_DECL (t) = d; + DECL_CONTEXT (d) = TYPE_CONTEXT (t); DECL_ARTIFICIAL (d) = 1; DECL_TEMPLATE_PARMS (d) = parm_list; @@ -4210,6 +4212,7 @@ initialize_predefined_identifiers (void) {"__dt_del ", &deleting_dtor_identifier, cik_dtor}, {"__conv_op ", &conv_op_identifier, cik_conv_op}, {"__in_chrg", &in_charge_identifier, cik_normal}, + {"__as_base ", &as_base_identifier, cik_normal}, {"this", &this_identifier, cik_normal}, {"__delta", &delta_identifier, cik_normal}, {"__pfn", &pfn_identifier, cik_normal}, @@ -4584,38 +4587,6 @@ cxx_init_decl_processing (void) using_eh_for_cleanups (); } -/* Generate an initializer for a function naming variable from - NAME. NAME may be NULL, to indicate a dependent name. TYPE_P is - filled in with the type of the init. */ - -tree -cp_fname_init (const char* name, tree *type_p) -{ - tree domain = NULL_TREE; - tree type; - tree init = NULL_TREE; - size_t length = 0; - - if (name) - { - length = strlen (name); - domain = build_index_type (size_int (length)); - init = build_string (length + 1, name); - } - - type = cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST); - type = build_cplus_array_type (type, domain); - - *type_p = type; - - if (init) - TREE_TYPE (init) = type; - else - init = error_mark_node; - - return init; -} - /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the decl, LOC is the location to give the decl, NAME is the initialization string and TYPE_DEP indicates whether NAME depended @@ -4626,31 +4597,45 @@ cp_fname_init (const char* name, tree *type_p) static tree cp_make_fname_decl (location_t loc, tree id, int type_dep) { - const char * name = NULL; - bool release_name = false; + tree domain = NULL_TREE; + tree init = NULL_TREE; + if (!(type_dep && in_template_function ())) { + const char *name = NULL; + bool release_name = false; + if (current_function_decl == NULL_TREE) name = "top level"; - else if (type_dep == 1) /* __PRETTY_FUNCTION__ */ - name = cxx_printable_name (current_function_decl, 2); - else if (type_dep == 0) /* __FUNCTION__ */ + else if (type_dep == 0) { + /* __FUNCTION__ */ name = fname_as_string (type_dep); release_name = true; } else - gcc_unreachable (); + { + /* __PRETTY_FUNCTION__ */ + gcc_checking_assert (type_dep == 1); + name = cxx_printable_name (current_function_decl, 2); + } + + size_t length = strlen (name); + domain = build_index_type (size_int (length)); + init = build_string (length + 1, name); + if (release_name) + free (const_cast<char *> (name)); } - tree type; - tree init = cp_fname_init (name, &type); - tree decl = build_decl (loc, VAR_DECL, id, type); - if (release_name) - free (CONST_CAST (char *, name)); + tree type = cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST); + type = build_cplus_array_type (type, domain); - /* As we're using pushdecl_with_scope, we must set the context. */ - DECL_CONTEXT (decl) = current_function_decl; + if (init) + TREE_TYPE (init) = type; + else + init = error_mark_node; + + tree decl = build_decl (loc, VAR_DECL, id, type); TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; @@ -4659,13 +4644,10 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep) TREE_USED (decl) = 1; - if (init) - { - SET_DECL_VALUE_EXPR (decl, init); - DECL_HAS_VALUE_EXPR_P (decl) = 1; - /* For decl_constant_var_p. */ - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; - } + SET_DECL_VALUE_EXPR (decl, init); + DECL_HAS_VALUE_EXPR_P (decl) = 1; + /* For decl_constant_var_p. */ + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1; if (current_function_decl) { @@ -4677,15 +4659,15 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep) else { DECL_THIS_STATIC (decl) = true; - pushdecl_top_level_and_finish (decl, NULL_TREE); + decl = pushdecl_top_level_and_finish (decl, NULL_TREE); } return decl; } -/* Install DECL as a builtin function at current (global) scope. - Return the new decl (if we found an existing version). Also - installs it into ::std, if it's not '_*'. */ +/* Install DECL as a builtin function at current global scope. Return + the new decl (if we found an existing version). Also installs it + into ::std, if it's not '_*'. */ tree cxx_builtin_function (tree decl) @@ -4701,16 +4683,17 @@ cxx_builtin_function (tree decl) tree id = DECL_NAME (decl); const char *name = IDENTIFIER_POINTER (id); + bool hiding = false; if (name[0] != '_' || name[1] != '_') /* In the user's namespace, it must be declared before use. */ - DECL_ANTICIPATED (decl) = 1; + hiding = true; else if (IDENTIFIER_LENGTH (id) > strlen ("___chk") && 0 != strncmp (name + 2, "builtin_", strlen ("builtin_")) && 0 == memcmp (name + IDENTIFIER_LENGTH (id) - strlen ("_chk"), "_chk", strlen ("_chk") + 1)) /* Treat __*_chk fortification functions as anticipated as well, unless they are __builtin_*_chk. */ - DECL_ANTICIPATED (decl) = 1; + hiding = true; /* All builtins that don't begin with an '_' should additionally go in the 'std' namespace. */ @@ -4720,12 +4703,12 @@ cxx_builtin_function (tree decl) push_nested_namespace (std_node); DECL_CONTEXT (std_decl) = FROB_CONTEXT (std_node); - pushdecl (std_decl); + pushdecl (std_decl, hiding); pop_nested_namespace (std_node); } DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); - decl = pushdecl (decl); + decl = pushdecl (decl, hiding); return decl; } @@ -5196,8 +5179,8 @@ groktypename (cp_decl_specifier_seq *type_specifiers, return type; } -/* Process a DECLARATOR for a function-scope variable declaration, - namespace-scope variable declaration, or function declaration. +/* Process a DECLARATOR for a function-scope or namespace-scope + variable or function declaration. (Function definitions go through start_function; class member declarations appearing in the body of the class go through grokfield.) The DECL corresponding to the DECLARATOR is returned. @@ -5348,8 +5331,7 @@ start_decl (const cp_declarator *declarator, about this situation, and so we check here. */ if (initialized && DECL_INITIALIZED_IN_CLASS_P (field)) error ("duplicate initialization of %qD", decl); - field = duplicate_decls (decl, field, - /*newdecl_is_friend=*/false); + field = duplicate_decls (decl, field); if (field == error_mark_node) return error_mark_node; else if (field) @@ -5363,8 +5345,7 @@ start_decl (const cp_declarator *declarator, ? current_template_parms : NULL_TREE); if (field && field != error_mark_node - && duplicate_decls (decl, field, - /*newdecl_is_friend=*/false)) + && duplicate_decls (decl, field)) decl = field; } @@ -5407,6 +5388,11 @@ start_decl (const cp_declarator *declarator, was_public = TREE_PUBLIC (decl); + if ((DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL) + && current_function_decl) + /* A function-scope decl of some namespace-scope decl. */ + DECL_LOCAL_DECL_P (decl) = true; + /* Enter this declaration into the symbol table. Don't push the plain VAR_DECL for a variable template. */ if (!template_parm_scope_p () @@ -5414,14 +5400,8 @@ start_decl (const cp_declarator *declarator, decl = maybe_push_decl (decl); if (processing_template_decl) - { - /* Make sure that for a `constinit' decl push_template_decl creates - a DECL_TEMPLATE_INFO info for us, so that cp_finish_decl can then set - TINFO_VAR_DECLARED_CONSTINIT. */ - if (decl_spec_seq_has_spec_p (declspecs, ds_constinit)) - retrofit_lang_decl (decl); - decl = push_template_decl (decl); - } + decl = push_template_decl (decl); + if (decl == error_mark_node) return error_mark_node; @@ -5554,6 +5534,37 @@ start_decl_1 (tree decl, bool initialized) maybe_push_cleanup_level (type); } +/* Given a parenthesized list of values INIT, create a CONSTRUCTOR to handle + C++20 P0960. TYPE is the type of the object we're initializing. */ + +tree +do_aggregate_paren_init (tree init, tree type) +{ + tree val = TREE_VALUE (init); + + if (TREE_CHAIN (init) == NULL_TREE) + { + /* If the list has a single element and it's a string literal, + then it's the initializer for the array as a whole. */ + if (TREE_CODE (type) == ARRAY_TYPE + && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) + && TREE_CODE (tree_strip_any_location_wrapper (val)) + == STRING_CST) + return val; + /* Handle non-standard extensions like compound literals. This also + prevents triggering aggregate parenthesized-initialization in + compiler-generated code for =default. */ + else if (same_type_ignoring_top_level_qualifiers_p (type, + TREE_TYPE (val))) + return val; + } + + init = build_constructor_from_list (init_list_type_node, init); + CONSTRUCTOR_IS_DIRECT_INIT (init) = true; + CONSTRUCTOR_IS_PAREN_INIT (init) = true; + return init; +} + /* Handle initialization of references. DECL, TYPE, and INIT have the same meaning as in cp_finish_decl. *CLEANUP must be NULL on entry, but will be set to a new CLEANUP_STMT if a temporary is created @@ -5601,11 +5612,7 @@ grok_reference_init (tree decl, tree type, tree init, int flags) /* If the list had more than one element, the code is ill-formed pre-C++20, so we can build a constructor right away. */ else - { - init = build_constructor_from_list (init_list_type_node, init); - CONSTRUCTOR_IS_DIRECT_INIT (init) = true; - CONSTRUCTOR_IS_PAREN_INIT (init) = true; - } + init = do_aggregate_paren_init (init, ttype); } else init = build_x_compound_expr_from_list (init, ELK_INIT, @@ -5823,7 +5830,8 @@ layout_var_decl (tree decl) && DECL_SIZE (decl) != NULL_TREE && ! TREE_CONSTANT (DECL_SIZE (decl))) { - if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST) + if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST + && !DECL_LOCAL_DECL_P (decl)) constant_expression_warning (DECL_SIZE (decl)); else { @@ -6436,7 +6444,7 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, non-empty subaggregate, brace elision is assumed and the initializer is considered for the initialization of the first member of the subaggregate. */ - if (TREE_CODE (init) != CONSTRUCTOR + if ((TREE_CODE (init) != CONSTRUCTOR || COMPOUND_LITERAL_P (init)) /* But don't try this for the first initializer, since that would be looking through the outermost braces; A a2 = { a1 }; is not a valid aggregate initialization. */ @@ -6569,7 +6577,17 @@ reshape_init (tree type, tree init, tsubst_flags_t complain) /* Brace elision is not performed for a CONSTRUCTOR representing parenthesized aggregate initialization. */ if (CONSTRUCTOR_IS_PAREN_INIT (init)) - return init; + { + tree elt = (*v)[0].value; + /* If we're initializing a char array from a string-literal that is + enclosed in braces, unwrap it here. */ + if (TREE_CODE (type) == ARRAY_TYPE + && vec_safe_length (v) == 1 + && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) + && TREE_CODE (tree_strip_any_location_wrapper (elt)) == STRING_CST) + return elt; + return init; + } /* Handle [dcl.init.list] direct-list-initialization from single element of enumeration with a fixed underlying type. */ @@ -6791,30 +6809,7 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups) && TREE_CODE (type) == ARRAY_TYPE && !DECL_DECOMPOSITION_P (decl) && (cxx_dialect >= cxx20)) - { - /* [dcl.init.string] "An array of ordinary character type [...] - can be initialized by an ordinary string literal [...] by an - appropriately-typed string literal enclosed in braces" only - talks about braces, but GCC has always accepted - - char a[]("foobar"); - - so we continue to do so. */ - tree val = TREE_VALUE (init); - if (TREE_CHAIN (init) == NULL_TREE - && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))) - && TREE_CODE (tree_strip_any_location_wrapper (val)) - == STRING_CST) - /* If the list has a single element and it's a string literal, - then it's the initializer for the array as a whole. */ - init = val; - else - { - init = build_constructor_from_list (init_list_type_node, init); - CONSTRUCTOR_IS_DIRECT_INIT (init) = true; - CONSTRUCTOR_IS_PAREN_INIT (init) = true; - } - } + init = do_aggregate_paren_init (init, type); else if (TREE_CODE (init) == TREE_LIST && TREE_TYPE (init) != unknown_type_node && !MAYBE_CLASS_TYPE_P (type)) @@ -6868,7 +6863,7 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups) flags |= LOOKUP_ALREADY_DIGESTED; } else if (DECL_DECLARED_CONSTEXPR_P (decl) - || (flags & LOOKUP_CONSTINIT)) + || DECL_DECLARED_CONSTINIT_P (decl)) { /* Declared constexpr or constinit, but no suitable initializer; massage init appropriately so we can pass it into @@ -7343,7 +7338,7 @@ omp_declare_variant_finalize_one (tree decl, tree attr) fn = STRIP_TEMPLATE (fn); if (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn)) || DECL_FUNCTION_MEMBER_P (fn) - || DECL_LOCAL_FUNCTION_P (fn))) + || DECL_LOCAL_DECL_P (fn))) { koenig_p = true; if (!any_type_dependent_arguments_p (args)) @@ -7659,10 +7654,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, DECL_INITIAL (decl) = NULL_TREE; } - /* Handle `constinit' on variable templates. */ - if (flags & LOOKUP_CONSTINIT) - TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (decl)) = true; - /* Generally, initializers in templates are expanded when the template is instantiated. But, if DECL is a variable constant then it can be used in future constant expressions, so its value @@ -7766,7 +7757,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, /* [dcl.constinit]/1 "The constinit specifier shall be applied only to a declaration of a variable with static or thread storage duration." */ - if ((flags & LOOKUP_CONSTINIT) + if (DECL_DECLARED_CONSTINIT_P (decl) && !(dk == dk_thread || dk == dk_static)) { error_at (DECL_SOURCE_LOCATION (decl), @@ -8007,6 +7998,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, NULL_TREE, DECL_ATTRIBUTES (decl)); } + /* This is the last point we can lower alignment so give the target the + chance to do so. */ + if (VAR_P (decl) + && !is_global_var (decl) + && !DECL_HARD_REGISTER (decl)) + targetm.lower_local_decl_alignment (decl); + invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl); } @@ -8100,7 +8098,7 @@ get_tuple_size (tree type) if (inst == error_mark_node || !COMPLETE_TYPE_P (inst)) return NULL_TREE; tree val = lookup_qualified_name (inst, value_identifier, - /*type*/false, /*complain*/false); + LOOK_want::NORMAL, /*complain*/false); if (TREE_CODE (val) == VAR_DECL || TREE_CODE (val) == CONST_DECL) val = maybe_constant_value (val); if (TREE_CODE (val) == INTEGER_CST) @@ -8144,7 +8142,7 @@ get_tuple_decomp_init (tree decl, unsigned i) e = move (e); tree fns = lookup_qualified_name (TREE_TYPE (e), get__identifier, - /*type*/false, /*complain*/false); + LOOK_want::NORMAL, /*complain*/false); bool use_member_get = false; /* To use a member get, member lookup must find at least one @@ -8204,7 +8202,7 @@ cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) && TREE_STATIC (decl)) { auto_vec<tree, 16> v; - v.safe_grow (count); + v.safe_grow (count, true); tree d = first; for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) v[count - i - 1] = d; @@ -8264,7 +8262,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count) } auto_vec<tree, 16> v; - v.safe_grow (count); + v.safe_grow (count, true); tree d = first; for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d)) { @@ -9436,7 +9434,10 @@ grokfndecl (tree ctype, { tree tmpl_reqs = NULL_TREE; tree ctx = friendp ? current_class_type : ctype; - bool memtmpl = (processing_template_decl > template_class_depth (ctx)); + bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL; + bool memtmpl = (!block_local + && (processing_template_decl + > template_class_depth (ctx))); if (memtmpl) tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); tree ci = build_constraints (tmpl_reqs, decl_reqs); @@ -9446,9 +9447,11 @@ grokfndecl (tree ctype, ci = NULL_TREE; } /* C++20 CA378: Remove non-templated constrained functions. */ - if (ci && !flag_concepts_ts - && (!processing_template_decl - || (friendp && !memtmpl && !funcdef_flag))) + if (ci + && (block_local + || (!flag_concepts_ts + && (!processing_template_decl + || (friendp && !memtmpl && !funcdef_flag))))) { error_at (location, "constraints on a non-templated function"); ci = NULL_TREE; @@ -9560,7 +9563,9 @@ grokfndecl (tree ctype, /* If this decl has namespace scope, set that up. */ if (in_namespace) set_decl_namespace (decl, in_namespace, friendp); - else if (!ctype) + else if (ctype) + DECL_CONTEXT (decl) = ctype; + else DECL_CONTEXT (decl) = FROB_CONTEXT (current_decl_namespace ()); /* `main' and builtins have implicit 'C' linkage. */ @@ -9588,12 +9593,8 @@ grokfndecl (tree ctype, if (deletedp) DECL_DELETED_FN (decl) = 1; - if (ctype) - { - DECL_CONTEXT (decl) = ctype; - if (funcdef_flag) - check_class_member_definition_namespace (decl); - } + if (ctype && funcdef_flag) + check_class_member_definition_namespace (decl); if (ctype == NULL_TREE && DECL_MAIN_P (decl)) { @@ -9895,7 +9896,7 @@ grokfndecl (tree ctype, /* Attempt to merge the declarations. This can fail, in the case of some invalid specialization declarations. */ pushed_scope = push_scope (ctype); - ok = duplicate_decls (decl, old_decl, friendp); + ok = duplicate_decls (decl, old_decl); if (pushed_scope) pop_scope (pushed_scope); if (!ok) @@ -12100,106 +12101,100 @@ grokdeclarator (const cp_declarator *declarator, /* Handle a late-specified return type. */ tree late_return_type = declarator->u.function.late_return_type; - if (funcdecl_p - /* This is the case e.g. for - using T = auto () -> int. */ - || inner_declarator == NULL) + if (tree auto_node = type_uses_auto (type)) { - if (tree auto_node = type_uses_auto (type)) + if (!late_return_type && funcdecl_p) { - if (!late_return_type) + if (current_class_type + && LAMBDA_TYPE_P (current_class_type)) + /* OK for C++11 lambdas. */; + else if (cxx_dialect < cxx14) { - if (current_class_type - && LAMBDA_TYPE_P (current_class_type)) - /* OK for C++11 lambdas. */; - else if (cxx_dialect < cxx14) - { - error_at (typespec_loc, "%qs function uses " - "%<auto%> type specifier without " - "trailing return type", name); - inform (typespec_loc, - "deduced return type only available " - "with %<-std=c++14%> or %<-std=gnu++14%>"); - } - else if (virtualp) - { - error_at (typespec_loc, "virtual function " - "cannot have deduced return type"); - virtualp = false; - } + error_at (typespec_loc, "%qs function uses " + "%<auto%> type specifier without " + "trailing return type", name); + inform (typespec_loc, + "deduced return type only available " + "with %<-std=c++14%> or %<-std=gnu++14%>"); } - else if (!is_auto (type) && sfk != sfk_conversion) + else if (virtualp) { - error_at (typespec_loc, "%qs function with trailing " - "return type has %qT as its type rather " - "than plain %<auto%>", name, type); - return error_mark_node; + error_at (typespec_loc, "virtual function " + "cannot have deduced return type"); + virtualp = false; } - else if (is_auto (type) && AUTO_IS_DECLTYPE (type)) + } + else if (!is_auto (type) && sfk != sfk_conversion) + { + error_at (typespec_loc, "%qs function with trailing " + "return type has %qT as its type rather " + "than plain %<auto%>", name, type); + return error_mark_node; + } + else if (is_auto (type) && AUTO_IS_DECLTYPE (type)) + { + if (funcdecl_p) + error_at (typespec_loc, + "%qs function with trailing return type " + "has %<decltype(auto)%> as its type " + "rather than plain %<auto%>", name); + else + error_at (typespec_loc, + "invalid use of %<decltype(auto)%>"); + return error_mark_node; + } + tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node); + if (!tmpl) + if (tree late_auto = type_uses_auto (late_return_type)) + tmpl = CLASS_PLACEHOLDER_TEMPLATE (late_auto); + if (tmpl && funcdecl_p) + { + if (!dguide_name_p (unqualified_id)) { - if (funcdecl_p) - error_at (typespec_loc, - "%qs function with trailing return type " - "has %<decltype(auto)%> as its type " - "rather than plain %<auto%>", name); - else - error_at (typespec_loc, - "invalid use of %<decltype(auto)%>"); + error_at (declarator->id_loc, "deduced class " + "type %qD in function return type", + DECL_NAME (tmpl)); + inform (DECL_SOURCE_LOCATION (tmpl), + "%qD declared here", tmpl); return error_mark_node; } - tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node); - if (!tmpl) - if (tree late_auto = type_uses_auto (late_return_type)) - tmpl = CLASS_PLACEHOLDER_TEMPLATE (late_auto); - if (tmpl && funcdecl_p) + else if (!late_return_type) { - if (!dguide_name_p (unqualified_id)) - { - error_at (declarator->id_loc, "deduced class " - "type %qD in function return type", - DECL_NAME (tmpl)); - inform (DECL_SOURCE_LOCATION (tmpl), - "%qD declared here", tmpl); - return error_mark_node; - } - else if (!late_return_type) - { - error_at (declarator->id_loc, "deduction guide " - "for %qT must have trailing return " - "type", TREE_TYPE (tmpl)); - inform (DECL_SOURCE_LOCATION (tmpl), - "%qD declared here", tmpl); - return error_mark_node; - } - else if (CLASS_TYPE_P (late_return_type) - && CLASSTYPE_TEMPLATE_INFO (late_return_type) - && (CLASSTYPE_TI_TEMPLATE (late_return_type) - == tmpl)) - /* OK */; - else - error ("trailing return type %qT of deduction guide " - "is not a specialization of %qT", - late_return_type, TREE_TYPE (tmpl)); + error_at (declarator->id_loc, "deduction guide " + "for %qT must have trailing return " + "type", TREE_TYPE (tmpl)); + inform (DECL_SOURCE_LOCATION (tmpl), + "%qD declared here", tmpl); + return error_mark_node; } - } - else if (late_return_type - && sfk != sfk_conversion) - { - if (late_return_type == error_mark_node) - return error_mark_node; - if (cxx_dialect < cxx11) - /* Not using maybe_warn_cpp0x because this should - always be an error. */ - error_at (typespec_loc, - "trailing return type only available " - "with %<-std=c++11%> or %<-std=gnu++11%>"); + else if (CLASS_TYPE_P (late_return_type) + && CLASSTYPE_TEMPLATE_INFO (late_return_type) + && (CLASSTYPE_TI_TEMPLATE (late_return_type) + == tmpl)) + /* OK */; else - error_at (typespec_loc, "%qs function with trailing " - "return type not declared with %<auto%> " - "type specifier", name); - return error_mark_node; + error ("trailing return type %qT of deduction guide " + "is not a specialization of %qT", + late_return_type, TREE_TYPE (tmpl)); } } + else if (late_return_type + && sfk != sfk_conversion) + { + if (late_return_type == error_mark_node) + return error_mark_node; + if (cxx_dialect < cxx11) + /* Not using maybe_warn_cpp0x because this should + always be an error. */ + error_at (typespec_loc, + "trailing return type only available " + "with %<-std=c++11%> or %<-std=gnu++11%>"); + else + error_at (typespec_loc, "%qs function with trailing " + "return type not declared with %<auto%> " + "type specifier", name); + return error_mark_node; + } type = splice_late_return_type (type, late_return_type); if (type == error_mark_node) return error_mark_node; @@ -12251,11 +12246,20 @@ grokdeclarator (const cp_declarator *declarator, /* Only plain decltype(auto) is allowed. */ if (tree a = type_uses_auto (type)) { - if (AUTO_IS_DECLTYPE (a) && a != type) + if (AUTO_IS_DECLTYPE (a)) { - error_at (typespec_loc, "%qT as type rather than " - "plain %<decltype(auto)%>", type); - return error_mark_node; + if (a != type) + { + error_at (typespec_loc, "%qT as type rather than " + "plain %<decltype(auto)%>", type); + return error_mark_node; + } + else if (TYPE_QUALS (type) != TYPE_UNQUALIFIED) + { + error_at (typespec_loc, "%<decltype(auto)%> cannot be " + "cv-qualified"); + return error_mark_node; + } } } @@ -13423,6 +13427,7 @@ grokdeclarator (const cp_declarator *declarator, in-class defaulted functions, but that breaks grokfndecl. So set it here. */ funcdef_flag = true; + if (template_class_depth (current_class_type) == 0) { decl = check_explicit_specialization @@ -13804,9 +13809,15 @@ grokdeclarator (const cp_declarator *declarator, else if (storage_class == sc_static) DECL_THIS_STATIC (decl) = 1; - /* Set constexpr flag on vars (functions got it in grokfndecl). */ - if (constexpr_p && VAR_P (decl)) - DECL_DECLARED_CONSTEXPR_P (decl) = true; + if (VAR_P (decl)) + { + /* Set constexpr flag on vars (functions got it in grokfndecl). */ + if (constexpr_p) + DECL_DECLARED_CONSTEXPR_P (decl) = true; + /* And the constinit flag (which only applies to variables). */ + else if (constinit_p) + DECL_DECLARED_CONSTINIT_P (decl) = true; + } /* Record constancy and volatility on the DECL itself . There's no need to do this when processing a template; we'll do this @@ -13851,11 +13862,9 @@ int local_variable_p (const_tree t) { if ((VAR_P (t) - /* A VAR_DECL with a context that is a _TYPE is a static data - member. */ - && !TYPE_P (CP_DECL_CONTEXT (t)) - /* Any other non-local variable must be at namespace scope. */ - && !DECL_NAMESPACE_SCOPE_P (t)) + && (DECL_LOCAL_DECL_P (t) + || !DECL_CONTEXT (t) + || TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)) || (TREE_CODE (t) == PARM_DECL)) return 1; @@ -14817,22 +14826,21 @@ check_elaborated_type_specifier (enum tag_types tag_code, return type; } -/* Lookup NAME in elaborate type specifier in scope according to - SCOPE and issue diagnostics if necessary. - Return *_TYPE node upon success, NULL_TREE when the NAME is not - found, and ERROR_MARK_NODE for type error. */ +/* Lookup NAME of an elaborated type specifier according to SCOPE and + issue diagnostics if necessary. Return *_TYPE node upon success, + NULL_TREE when the NAME is not found, and ERROR_MARK_NODE for type + error. */ static tree lookup_and_check_tag (enum tag_types tag_code, tree name, - tag_scope scope, bool template_header_p) + TAG_how how, bool template_header_p) { - tree t; tree decl; - if (scope == ts_global) + if (how == TAG_how::GLOBAL) { /* First try ordinary name lookup, ignoring hidden class name injected via friend declaration. */ - decl = lookup_name_prefer_type (name, 2); + decl = lookup_name (name, LOOK_want::TYPE); decl = strip_using_decl (decl); /* If that fails, the name will be placed in the smallest non-class, non-function-prototype scope according to 3.3.1/5. @@ -14841,77 +14849,78 @@ lookup_and_check_tag (enum tag_types tag_code, tree name, If we find one, that name will be made visible rather than creating a new tag. */ if (!decl) - decl = lookup_type_scope (name, ts_within_enclosing_non_class); + decl = lookup_elaborated_type (name, TAG_how::INNERMOST_NON_CLASS); } else - decl = lookup_type_scope (name, scope); - - if (decl - && (DECL_CLASS_TEMPLATE_P (decl) - /* If scope is ts_current we're defining a class, so ignore a - template template parameter. */ - || (scope != ts_current - && DECL_TEMPLATE_TEMPLATE_PARM_P (decl)))) - decl = DECL_TEMPLATE_RESULT (decl); - - if (decl && TREE_CODE (decl) == TYPE_DECL) - { - /* Look for invalid nested type: - class C { - class C {}; - }; */ - if (scope == ts_current && DECL_SELF_REFERENCE_P (decl)) - { - error ("%qD has the same name as the class in which it is " - "declared", - decl); - return error_mark_node; - } + decl = lookup_elaborated_type (name, how); - /* Two cases we need to consider when deciding if a class - template is allowed as an elaborated type specifier: - 1. It is a self reference to its own class. - 2. It comes with a template header. - For example: - - template <class T> class C { - class C *c1; // DECL_SELF_REFERENCE_P is true - class D; - }; - template <class U> class C; // template_header_p is true - template <class T> class C<T>::D { - class C *c2; // DECL_SELF_REFERENCE_P is true - }; */ - - t = check_elaborated_type_specifier (tag_code, - decl, - template_header_p - | DECL_SELF_REFERENCE_P (decl)); - if (template_header_p && t && CLASS_TYPE_P (t) - && (!CLASSTYPE_TEMPLATE_INFO (t) - || (!PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))))) - { - error ("%qT is not a template", t); - inform (location_of (t), "previous declaration here"); - if (TYPE_CLASS_SCOPE_P (t) - && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (t))) - inform (input_location, - "perhaps you want to explicitly add %<%T::%>", - TYPE_CONTEXT (t)); - t = error_mark_node; - } + if (!decl) + /* We found nothing. */ + return NULL_TREE; - return t; - } - else if (decl && TREE_CODE (decl) == TREE_LIST) + if (TREE_CODE (decl) == TREE_LIST) { error ("reference to %qD is ambiguous", name); print_candidates (decl); return error_mark_node; } - else + + if (DECL_CLASS_TEMPLATE_P (decl) + /* If scope is TAG_how::CURRENT_ONLY we're defining a class, + so ignore a template template parameter. */ + || (how != TAG_how::CURRENT_ONLY && DECL_TEMPLATE_TEMPLATE_PARM_P (decl))) + decl = DECL_TEMPLATE_RESULT (decl); + + if (TREE_CODE (decl) != TYPE_DECL) + /* Found not-a-type. */ return NULL_TREE; + + /* Look for invalid nested type: + class C { + class C {}; + }; */ + if (how == TAG_how::CURRENT_ONLY && DECL_SELF_REFERENCE_P (decl)) + { + error ("%qD has the same name as the class in which it is " + "declared", decl); + return error_mark_node; + } + + /* Two cases we need to consider when deciding if a class + template is allowed as an elaborated type specifier: + 1. It is a self reference to its own class. + 2. It comes with a template header. + + For example: + + template <class T> class C { + class C *c1; // DECL_SELF_REFERENCE_P is true + class D; + }; + template <class U> class C; // template_header_p is true + template <class T> class C<T>::D { + class C *c2; // DECL_SELF_REFERENCE_P is true + }; */ + + tree t = check_elaborated_type_specifier (tag_code, decl, + template_header_p + | DECL_SELF_REFERENCE_P (decl)); + if (template_header_p && t && CLASS_TYPE_P (t) + && (!CLASSTYPE_TEMPLATE_INFO (t) + || (!PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))))) + { + error ("%qT is not a template", t); + inform (location_of (t), "previous declaration here"); + if (TYPE_CLASS_SCOPE_P (t) + && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (t))) + inform (input_location, + "perhaps you want to explicitly add %<%T::%>", + TYPE_CONTEXT (t)); + return error_mark_node; + } + + return t; } /* Get the struct, enum or union (TAG_CODE says which) with tag NAME. @@ -14931,7 +14940,7 @@ lookup_and_check_tag (enum tag_types tag_code, tree name, static tree xref_tag_1 (enum tag_types tag_code, tree name, - tag_scope scope, bool template_header_p) + TAG_how how, bool template_header_p) { enum tree_code code; tree context = NULL_TREE; @@ -14957,23 +14966,23 @@ xref_tag_1 (enum tag_types tag_code, tree name, /* In case of anonymous name, xref_tag is only called to make type node and push name. Name lookup is not required. */ tree t = NULL_TREE; - if (scope != ts_lambda && !IDENTIFIER_ANON_P (name)) - t = lookup_and_check_tag (tag_code, name, scope, template_header_p); - + if (!IDENTIFIER_ANON_P (name)) + t = lookup_and_check_tag (tag_code, name, how, template_header_p); + if (t == error_mark_node) return error_mark_node; - if (scope != ts_current && t && current_class_type + if (how != TAG_how::CURRENT_ONLY && t && current_class_type && template_class_depth (current_class_type) && template_header_p) { if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM) return t; - /* Since SCOPE is not TS_CURRENT, we are not looking at a - definition of this tag. Since, in addition, we are currently - processing a (member) template declaration of a template - class, we must be very careful; consider: + /* Since HOW is not TAG_how::CURRENT_ONLY, we are not looking at + a definition of this tag. Since, in addition, we are + currently processing a (member) template declaration of a + template class, we must be very careful; consider: template <class X> struct S1 @@ -15012,19 +15021,14 @@ xref_tag_1 (enum tag_types tag_code, tree name, error ("use of enum %q#D without previous declaration", name); return error_mark_node; } - else - { - t = make_class_type (code); - TYPE_CONTEXT (t) = context; - if (scope == ts_lambda) - { - /* Mark it as a lambda type. */ - CLASSTYPE_LAMBDA_EXPR (t) = error_mark_node; - /* And push it into current scope. */ - scope = ts_current; - } - t = pushtag (name, t, scope); - } + + t = make_class_type (code); + TYPE_CONTEXT (t) = context; + 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; + t = pushtag (name, t, how); } else { @@ -15049,23 +15053,6 @@ xref_tag_1 (enum tag_types tag_code, tree name, inform (location_of (t), "previous declaration %qD", t); return error_mark_node; } - - if (scope != ts_within_enclosing_non_class && TYPE_HIDDEN_P (t)) - { - /* This is no longer an invisible friend. Make it - visible. */ - tree decl = TYPE_NAME (t); - - DECL_ANTICIPATED (decl) = false; - DECL_FRIEND_P (decl) = false; - - if (TYPE_TEMPLATE_INFO (t)) - { - tree tmpl = TYPE_TI_TEMPLATE (t); - DECL_ANTICIPATED (tmpl) = false; - DECL_FRIEND_P (tmpl) = false; - } - } } return t; @@ -15075,33 +15062,14 @@ xref_tag_1 (enum tag_types tag_code, tree name, tree xref_tag (enum tag_types tag_code, tree name, - tag_scope scope, bool template_header_p) + TAG_how how, bool template_header_p) { - tree ret; - bool subtime; - subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = xref_tag_1 (tag_code, name, scope, template_header_p); + bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + tree ret = xref_tag_1 (tag_code, name, how, template_header_p); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } - -tree -xref_tag_from_type (tree old, tree id, tag_scope scope) -{ - enum tag_types tag_kind; - - if (TREE_CODE (old) == RECORD_TYPE) - tag_kind = (CLASSTYPE_DECLARED_CLASS (old) ? class_type : record_type); - else - tag_kind = union_type; - - if (id == NULL_TREE) - id = TYPE_IDENTIFIER (old); - - return xref_tag (tag_kind, id, scope, false); -} - /* Create the binfo hierarchy for REF with (possibly NULL) base list BASE_LIST. For each element on BASE_LIST the TREE_PURPOSE is an access_* node, and the TREE_VALUE is the type of the base-class. @@ -15396,7 +15364,7 @@ start_enum (tree name, tree enumtype, tree underlying_type, forward reference. */ if (!enumtype) enumtype = lookup_and_check_tag (enum_type, name, - /*tag_scope=*/ts_current, + /*tag_scope=*/TAG_how::CURRENT_ONLY, /*template_header_p=*/false); /* In case of a template_decl, the only check that should be deferred @@ -15458,7 +15426,7 @@ start_enum (tree name, tree enumtype, tree underlying_type, || TREE_CODE (enumtype) != ENUMERAL_TYPE) { enumtype = cxx_make_type (ENUMERAL_TYPE); - enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current); + enumtype = pushtag (name, enumtype); /* std::byte aliases anything. */ if (enumtype != error_mark_node @@ -15467,8 +15435,7 @@ start_enum (tree name, tree enumtype, tree underlying_type, TYPE_ALIAS_SET (enumtype) = 0; } else - enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current, - false); + enumtype = xref_tag (enum_type, name); if (enumtype == error_mark_node) return error_mark_node; @@ -16239,7 +16206,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) by push_nested_class.) */ if (processing_template_decl) { - tree newdecl1 = push_template_decl (decl1); + tree newdecl1 = push_template_decl (decl1, DECL_FRIEND_P (decl1)); if (newdecl1 == error_mark_node) { if (ctype || DECL_STATIC_FUNCTION_P (decl1)) @@ -16803,8 +16770,6 @@ finish_destructor_body (void) tree begin_function_body (void) { - tree stmt; - if (! FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) return NULL_TREE; @@ -16816,7 +16781,7 @@ begin_function_body (void) operation of dwarfout.c. */ keep_next_level (true); - stmt = begin_compound_stmt (BCS_FN_BODY); + tree stmt = begin_compound_stmt (BCS_FN_BODY); if (processing_template_decl) /* Do nothing now. */; @@ -17112,6 +17077,51 @@ finish_function (bool inline_p) DECL_ATTRIBUTES (fndecl))) omp_declare_variant_finalize (fndecl, attr); + /* Complain if there's just no return statement. */ + if ((warn_return_type + || (cxx_dialect >= cxx14 + && DECL_DECLARED_CONSTEXPR_P (fndecl))) + && !VOID_TYPE_P (TREE_TYPE (fntype)) + && !dependent_type_p (TREE_TYPE (fntype)) + && !current_function_returns_value && !current_function_returns_null + /* Don't complain if we abort or throw. */ + && !current_function_returns_abnormally + /* Don't complain if there's an infinite loop. */ + && !current_function_infinite_loop + /* Don't complain if we are declared noreturn. */ + && !TREE_THIS_VOLATILE (fndecl) + && !DECL_NAME (DECL_RESULT (fndecl)) + && !TREE_NO_WARNING (fndecl) + /* Structor return values (if any) are set by the compiler. */ + && !DECL_CONSTRUCTOR_P (fndecl) + && !DECL_DESTRUCTOR_P (fndecl) + && targetm.warn_func_return (fndecl)) + { + gcc_rich_location richloc (input_location); + /* Potentially add a "return *this;" fix-it hint for + assignment operators. */ + if (IDENTIFIER_ASSIGN_OP_P (DECL_NAME (fndecl))) + { + tree valtype = TREE_TYPE (DECL_RESULT (fndecl)); + if (TREE_CODE (valtype) == REFERENCE_TYPE + && current_class_ref + && same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)) + && global_dc->option_enabled (OPT_Wreturn_type, + global_dc->lang_mask, + global_dc->option_state)) + add_return_star_this_fixit (&richloc, fndecl); + } + if (cxx_dialect >= cxx14 + && DECL_DECLARED_CONSTEXPR_P (fndecl)) + error_at (&richloc, "no return statement in %<constexpr%> function " + "returning non-void"); + else if (warning_at (&richloc, OPT_Wreturn_type, + "no return statement in function returning " + "non-void")) + TREE_NO_WARNING (fndecl) = 1; + } + /* Lambda closure members are implicitly constexpr if possible. */ if (cxx_dialect >= cxx17 && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))) @@ -17163,44 +17173,6 @@ finish_function (bool inline_p) to the FUNCTION_DECL node itself. */ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - /* Complain if there's just no return statement. */ - if (warn_return_type - && !VOID_TYPE_P (TREE_TYPE (fntype)) - && !dependent_type_p (TREE_TYPE (fntype)) - && !current_function_returns_value && !current_function_returns_null - /* Don't complain if we abort or throw. */ - && !current_function_returns_abnormally - /* Don't complain if there's an infinite loop. */ - && !current_function_infinite_loop - /* Don't complain if we are declared noreturn. */ - && !TREE_THIS_VOLATILE (fndecl) - && !DECL_NAME (DECL_RESULT (fndecl)) - && !TREE_NO_WARNING (fndecl) - /* Structor return values (if any) are set by the compiler. */ - && !DECL_CONSTRUCTOR_P (fndecl) - && !DECL_DESTRUCTOR_P (fndecl) - && targetm.warn_func_return (fndecl)) - { - gcc_rich_location richloc (input_location); - /* Potentially add a "return *this;" fix-it hint for - assignment operators. */ - if (IDENTIFIER_ASSIGN_OP_P (DECL_NAME (fndecl))) - { - tree valtype = TREE_TYPE (DECL_RESULT (fndecl)); - if (TREE_CODE (valtype) == REFERENCE_TYPE - && current_class_ref - && same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)) - && global_dc->option_enabled (OPT_Wreturn_type, - global_dc->lang_mask, - global_dc->option_state)) - add_return_star_this_fixit (&richloc, fndecl); - } - if (warning_at (&richloc, OPT_Wreturn_type, - "no return statement in function returning non-void")) - TREE_NO_WARNING (fndecl) = 1; - } - /* Store the end of the function, so that we get good line number info for the epilogue. */ cfun->function_end_locus = input_location; @@ -17339,7 +17311,7 @@ grokmethod (cp_decl_specifier_seq *declspecs, /* We process method specializations in finish_struct_1. */ if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl)) { - fndecl = push_template_decl (fndecl); + fndecl = push_template_decl (fndecl, DECL_FRIEND_P (fndecl)); if (fndecl == error_mark_node) return fndecl; } @@ -17423,10 +17395,11 @@ complete_vars (tree type) && (TYPE_MAIN_VARIANT (strip_array_types (type)) == iv->incomplete_type)) { - /* Complete the type of the variable. The VAR_DECL itself - will be laid out in expand_expr. */ + /* Complete the type of the variable. */ complete_type (type); cp_apply_type_quals_to_decl (cp_type_quals (type), var); + if (COMPLETE_TYPE_P (type)) + layout_var_decl (var); } /* Remove this entry from the list. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ddc2023..db3035d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -81,7 +81,6 @@ static void import_export_class (tree); static tree get_guard_bits (tree); static void determine_visibility_from_class (tree, tree); static bool determine_hidden_inline (tree); -static void maybe_instantiate_decl (tree); /* A list of static class variables. This is needed, because a static class variable can be declared inside the class without @@ -995,9 +994,6 @@ grokfield (const cp_declarator *declarator, else flags = LOOKUP_IMPLICIT; - if (decl_spec_seq_has_spec_p (declspecs, ds_constinit)) - flags |= LOOKUP_CONSTINIT; - switch (TREE_CODE (value)) { case VAR_DECL: @@ -2215,6 +2211,7 @@ decl_needed_p (tree decl) emitted; they may be referred to from other object files. */ if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_REALLY_EXTERN (decl)) return true; + /* Functions marked "dllexport" must be emitted so that they are visible to other DLLs. */ if (flag_keep_inline_dllexport @@ -2725,8 +2722,7 @@ determine_visibility (tree decl) determine_visibility_from_class (decl, class_type); if (decl_anon_ns_mem_p (decl)) - /* Names in an anonymous namespace get internal linkage. - This might change once we implement export. */ + /* Names in an anonymous namespace get internal linkage. */ constrain_visibility (decl, VISIBILITY_ANON, false); else if (TREE_CODE (decl) != TYPE_DECL) { @@ -3294,11 +3290,8 @@ copy_linkage (tree guard, tree decl) tree get_guard (tree decl) { - tree sname; - tree guard; - - sname = mangle_guard_variable (decl); - guard = get_global_binding (sname); + tree sname = mangle_guard_variable (decl); + tree guard = get_global_binding (sname); if (! guard) { tree guard_type; @@ -4492,11 +4485,13 @@ no_linkage_error (tree decl) && TREE_NO_WARNING (decl)))) /* In C++11 it's ok if the decl is defined. */ return; + tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); if (t == NULL_TREE) /* The type that got us on no_linkage_decls must have gotten a name for linkage purposes. */; else if (CLASS_TYPE_P (t) && TYPE_BEING_DEFINED (t)) + // FIXME: This is now invalid, as a DR to c++98 /* The type might end up having a typedef name for linkage purposes. */ vec_safe_push (no_linkage_decls, decl); else if (TYPE_UNNAMED_P (t)) @@ -5387,7 +5382,7 @@ possibly_inlined_p (tree decl) them instantiated for reduction clauses which inline them by hand directly. */ -static void +void maybe_instantiate_decl (tree decl) { if (DECL_LANG_SPECIFIC (decl) @@ -5534,10 +5529,11 @@ mark_used (tree decl, tsubst_flags_t complain) return true; /* Set TREE_USED for the benefit of -Wunused. */ - TREE_USED (decl) = 1; + TREE_USED (decl) = true; + /* And for structured bindings also the underlying decl. */ if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_BASE (decl)) - TREE_USED (DECL_DECOMP_BASE (decl)) = 1; + TREE_USED (DECL_DECOMP_BASE (decl)) = true; if (TREE_CODE (decl) == TEMPLATE_DECL) return true; @@ -5571,6 +5567,22 @@ mark_used (tree decl, tsubst_flags_t complain) return false; } + if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)) + { + if (!DECL_LANG_SPECIFIC (decl)) + /* An unresolved dependent local extern. */ + return true; + + DECL_ODR_USED (decl) = 1; + auto alias = DECL_LOCAL_DECL_ALIAS (decl); + if (!alias || alias == error_mark_node) + return true; + + /* Process the underlying decl. */ + decl = alias; + TREE_USED (decl) = true; + } + cp_warn_deprecated_use (decl, complain); /* We can only check DECL_ODR_USED on variables or functions with @@ -5654,14 +5666,7 @@ mark_used (tree decl, tsubst_flags_t complain) && !DECL_ARTIFICIAL (decl) && !decl_defined_p (decl) && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) - { - if (is_local_extern (decl)) - /* There's no way to define a local extern, and adding it to - the vector interferes with GC, so give an error now. */ - no_linkage_error (decl); - else - vec_safe_push (no_linkage_decls, decl); - } + vec_safe_push (no_linkage_decls, decl); if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl) diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index c509bad..81d2c16 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -280,25 +280,6 @@ cp_dump_tree (void* dump_info, tree t) dump_child ("else", ELSE_CLAUSE (t)); break; - case BREAK_STMT: - case CONTINUE_STMT: - dump_stmt (di, t); - break; - - case DO_STMT: - dump_stmt (di, t); - dump_child ("body", DO_BODY (t)); - dump_child ("cond", DO_COND (t)); - break; - - case FOR_STMT: - dump_stmt (di, t); - dump_child ("init", FOR_INIT_STMT (t)); - dump_child ("cond", FOR_COND (t)); - dump_child ("expr", FOR_EXPR (t)); - dump_child ("body", FOR_BODY (t)); - break; - case RANGE_FOR_STMT: dump_stmt (di, t); dump_child ("init", RANGE_FOR_INIT_STMT (t)); @@ -307,18 +288,6 @@ cp_dump_tree (void* dump_info, tree t) dump_child ("body", RANGE_FOR_BODY (t)); break; - case SWITCH_STMT: - dump_stmt (di, t); - dump_child ("cond", SWITCH_STMT_COND (t)); - dump_child ("body", SWITCH_STMT_BODY (t)); - break; - - case WHILE_STMT: - dump_stmt (di, t); - dump_child ("cond", WHILE_COND (t)); - dump_child ("body", WHILE_BODY (t)); - break; - case STMT_EXPR: dump_child ("stmt", STMT_EXPR_STMT (t)); break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 0d6375e..396558b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -701,7 +701,6 @@ class_key_or_enum_as_string (tree t) static void dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) { - tree name; const char *variety = class_key_or_enum_as_string (t); int typdef = 0; int tmplate = 0; @@ -711,23 +710,23 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) if (flags & TFF_CLASS_KEY_OR_ENUM) pp_cxx_ws_string (pp, variety); - name = TYPE_NAME (t); + tree decl = TYPE_NAME (t); - if (name) + if (decl) { - typdef = (!DECL_ARTIFICIAL (name) + typdef = (!DECL_ARTIFICIAL (decl) /* An alias specialization is not considered to be a typedef. */ && !alias_template_specialization_p (t, nt_opaque)); if ((typdef && ((flags & TFF_CHASE_TYPEDEF) - || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name) - && DECL_TEMPLATE_INFO (name)))) - || DECL_SELF_REFERENCE_P (name)) + || (!flag_pretty_templates && DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl)))) + || DECL_SELF_REFERENCE_P (decl)) { t = TYPE_MAIN_VARIANT (t); - name = TYPE_NAME (t); + decl = TYPE_NAME (t); typdef = 0; } @@ -737,7 +736,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) || PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))); if (! (flags & TFF_UNQUALIFIED_NAME)) - dump_scope (pp, CP_DECL_CONTEXT (name), flags | TFF_SCOPE); + dump_scope (pp, CP_DECL_CONTEXT (decl), flags | TFF_SCOPE); flags &= ~TFF_UNQUALIFIED_NAME; if (tmplate) { @@ -747,9 +746,8 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) while (DECL_TEMPLATE_INFO (tpl)) tpl = DECL_TI_TEMPLATE (tpl); - name = tpl; + decl = tpl; } - name = DECL_NAME (name); } if (LAMBDA_TYPE_P (t)) @@ -762,7 +760,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) flags); pp_greater (pp); } - else if (!name || IDENTIFIER_ANON_P (name)) + else if (!decl || IDENTIFIER_ANON_P (DECL_NAME (decl))) { if (flags & TFF_CLASS_KEY_OR_ENUM) pp_string (pp, M_("<unnamed>")); @@ -770,7 +768,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) pp_printf (pp, M_("<unnamed %s>"), variety); } else - pp_cxx_tree_identifier (pp, name); + pp_cxx_tree_identifier (pp, DECL_NAME (decl)); if (tmplate) dump_template_parms (pp, TYPE_TEMPLATE_INFO (t), @@ -953,8 +951,11 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags) if (tree dtype = TYPE_DOMAIN (t)) { tree max = TYPE_MAX_VALUE (dtype); - /* Zero-length arrays have an upper bound of SIZE_MAX. */ - if (integer_all_onesp (max)) + /* Zero-length arrays have a null upper bound in C and SIZE_MAX + in C++. Handle both since the type might be constructed by + the middle end and end up here as a result of a warning (see + PR c++/97201). */ + if (!max || integer_all_onesp (max)) pp_character (pp, '0'); else if (tree_fits_shwi_p (max)) pp_wide_integer (pp, tree_to_shwi (max) + 1); @@ -2402,6 +2403,64 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) } break; + case TARGET_MEM_REF: + /* TARGET_MEM_REF can't appear directly from source, but can appear + during late GIMPLE optimizations and through late diagnostic we might + need to support it. Print it as dereferencing of a pointer after + cast to the TARGET_MEM_REF type, with pointer arithmetics on some + pointer to single byte types, so + *(type *)((char *) ptr + step * index + index2) if all the operands + are present and the casts are needed. */ + pp_cxx_star (pp); + pp_cxx_left_paren (pp); + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TMR_BASE (t)))) == NULL_TREE + || !integer_onep (TYPE_SIZE_UNIT + (TREE_TYPE (TREE_TYPE (TMR_BASE (t)))))) + { + if (TYPE_SIZE_UNIT (TREE_TYPE (t)) + && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (t)))) + { + pp_cxx_left_paren (pp); + dump_type (pp, build_pointer_type (TREE_TYPE (t)), flags); + } + else + { + dump_type (pp, build_pointer_type (TREE_TYPE (t)), flags); + pp_cxx_right_paren (pp); + pp_cxx_left_paren (pp); + pp_cxx_left_paren (pp); + dump_type (pp, build_pointer_type (char_type_node), flags); + } + pp_cxx_right_paren (pp); + } + else if (!same_type_p (TREE_TYPE (t), + TREE_TYPE (TREE_TYPE (TMR_BASE (t))))) + { + dump_type (pp, build_pointer_type (TREE_TYPE (t)), flags); + pp_cxx_right_paren (pp); + pp_cxx_left_paren (pp); + } + dump_expr (pp, TMR_BASE (t), flags); + if (TMR_STEP (t) && TMR_INDEX (t)) + { + pp_cxx_ws_string (pp, "+"); + dump_expr (pp, TMR_INDEX (t), flags); + pp_cxx_ws_string (pp, "*"); + dump_expr (pp, TMR_STEP (t), flags); + } + if (TMR_INDEX2 (t)) + { + pp_cxx_ws_string (pp, "+"); + dump_expr (pp, TMR_INDEX2 (t), flags); + } + if (!integer_zerop (TMR_OFFSET (t))) + { + pp_cxx_ws_string (pp, "+"); + dump_expr (pp, fold_convert (ssizetype, TMR_OFFSET (t)), flags); + } + pp_cxx_right_paren (pp); + break; + case NEGATE_EXPR: case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: diff --git a/gcc/cp/except.c b/gcc/cp/except.c index aca54f1..cb1a410 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -696,21 +696,25 @@ build_throw (location_t loc, tree exp) /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes treated as an rvalue for the purposes of overload resolution to favor move constructors over copy constructors. */ - if (treat_lvalue_as_rvalue_p (exp, /*parm_ok*/false) - /* The variable must not have the `volatile' qualifier. */ - && !CP_TYPE_VOLATILE_P (TREE_TYPE (exp))) + if (tree moved = treat_lvalue_as_rvalue_p (exp, /*return*/false)) { - tree moved = move (exp); - releasing_vec exp_vec (make_tree_vector_single (moved)); - moved = (build_special_member_call - (object, complete_ctor_identifier, &exp_vec, - TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, - tf_none)); - if (moved != error_mark_node) + if (cxx_dialect < cxx20) { - exp = moved; - converted = true; + releasing_vec exp_vec (make_tree_vector_single (moved)); + moved = (build_special_member_call + (object, complete_ctor_identifier, &exp_vec, + TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE, + tf_none)); + if (moved != error_mark_node) + { + exp = moved; + converted = true; + } } + else + /* In C++20 we just treat the return value as an rvalue that + can bind to lvalue refs. */ + exp = moved; } /* Call the copy constructor. */ diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index a6ab96a..aa60593 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -139,9 +139,7 @@ mark_use (tree expr, bool rvalue_p, bool read_p, break; } } - temp_override<location_t> l (input_location); - if (loc != UNKNOWN_LOCATION) - input_location = loc; + iloc_sentinel l (loc); expr = process_outer_var_ref (expr, tf_warning_or_error, true); if (!(TREE_TYPE (oexpr) && TYPE_REF_P (TREE_TYPE (oexpr)))) diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index fa20a93..6a783a9 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -558,7 +558,7 @@ do_friend (tree ctype, tree declarator, tree decl, else if (class_template_depth) /* We rely on tsubst_friend_function to check the validity of the declaration later. */ - decl = push_template_decl_real (decl, /*is_friend=*/true); + decl = push_template_decl (decl, /*is_friend=*/true); else decl = check_classfn (ctype, decl, template_member_p @@ -598,8 +598,8 @@ do_friend (tree ctype, tree declarator, tree decl, if (! DECL_USE_TEMPLATE (decl)) { /* We must check whether the decl refers to template - arguments before push_template_decl_real adds a - reference to the containing template class. */ + arguments before push_template_decl adds a reference to + the containing template class. */ int warn = (warn_nontemplate_friend && ! funcdef_flag && ! is_friend_template && current_template_parms @@ -611,10 +611,10 @@ do_friend (tree ctype, tree declarator, tree decl, general, such a declaration depends on template parameters. Instead, we call pushdecl when the class is instantiated. */ - decl = push_template_decl_real (decl, /*is_friend=*/true); + decl = push_template_decl (decl, /*is_friend=*/true); else if (current_function_decl) /* pushdecl will check there's a local decl already. */ - decl = pushdecl (decl, /*is_friend=*/true); + decl = pushdecl (decl, /*hiding=*/true); else { /* We can't use pushdecl, as we might be in a template @@ -624,7 +624,7 @@ do_friend (tree ctype, tree declarator, tree decl, tree ns = decl_namespace_context (decl); push_nested_namespace (ns); - decl = pushdecl_namespace_level (decl, /*is_friend=*/true); + decl = pushdecl_namespace_level (decl, /*hiding=*/true); pop_nested_namespace (ns); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ef4b3c4..1bddb655 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "stor-layout.h" +#include "builtins.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); @@ -809,13 +810,25 @@ perform_member_init (tree member, tree init) return; } - if (init && TREE_CODE (init) == TREE_LIST - && (DIRECT_LIST_INIT_P (TREE_VALUE (init)) - /* FIXME C++20 parenthesized aggregate init (PR 92812). */ - || !(/* cxx_dialect >= cxx20 ? CP_AGGREGATE_TYPE_P (type) */ - /* : */CLASS_TYPE_P (type)))) - init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, - tf_warning_or_error); + if (init && TREE_CODE (init) == TREE_LIST) + { + /* A(): a{e} */ + if (DIRECT_LIST_INIT_P (TREE_VALUE (init))) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + /* We are trying to initialize an array from a ()-list. If we + should attempt to do so, conjure up a CONSTRUCTOR. */ + else if (TREE_CODE (type) == ARRAY_TYPE + /* P0960 is a C++20 feature. */ + && cxx_dialect >= cxx20) + init = do_aggregate_paren_init (init, type); + else if (!CLASS_TYPE_P (type)) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + /* If we're initializing a class from a ()-list, leave the TREE_LIST + alone: we might call an appropriate constructor, or (in C++20) + do aggregate-initialization. */ + } if (init == void_type_node) { @@ -1151,6 +1164,8 @@ sort_mem_initializers (tree t, tree mem_inits) /* Record the initialization. */ TREE_VALUE (subobject_init) = TREE_VALUE (init); + /* Carry over the dummy TREE_TYPE node containing the source location. */ + TREE_TYPE (subobject_init) = TREE_TYPE (init); next_subobject = subobject_init; } @@ -1367,6 +1382,10 @@ emit_mem_initializers (tree mem_inits) /* Initialize the data members. */ while (mem_inits) { + /* If this initializer was explicitly provided, then the dummy TREE_TYPE + node contains the source location. */ + iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits))); + perform_member_init (TREE_PURPOSE (mem_inits), TREE_VALUE (mem_inits)); mem_inits = TREE_CHAIN (mem_inits); @@ -1889,7 +1908,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, } if (init && TREE_CODE (init) != TREE_LIST - && (flags & LOOKUP_ONLYCONVERTING)) + && (flags & LOOKUP_ONLYCONVERTING) + && !unsafe_return_slot_p (exp)) { /* Base subobjects should only get direct-initialization. */ gcc_assert (true_exp == exp); @@ -2272,10 +2292,12 @@ build_offset_ref (tree type, tree member, bool address_p, recursively); otherwise, return DECL. If STRICT_P, the initializer is only returned if DECL is a constant-expression. If RETURN_AGGREGATE_CST_OK_P, it is ok to - return an aggregate constant. */ + return an aggregate constant. If UNSHARE_P, return an unshared + copy of the initializer. */ static tree -constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p) +constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p, + bool unshare_p) { while (TREE_CODE (decl) == CONST_DECL || decl_constant_var_p (decl) @@ -2343,9 +2365,9 @@ constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p) && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) && DECL_NONTRIVIALLY_INITIALIZED_P (decl)) break; - decl = unshare_expr (init); + decl = init; } - return decl; + return unshare_p ? unshare_expr (decl) : decl; } /* If DECL is a CONST_DECL, or a constant VAR_DECL initialized by constant @@ -2357,26 +2379,36 @@ tree scalar_constant_value (tree decl) { return constant_value_1 (decl, /*strict_p=*/true, - /*return_aggregate_cst_ok_p=*/false); + /*return_aggregate_cst_ok_p=*/false, + /*unshare_p=*/true); } -/* Like scalar_constant_value, but can also return aggregate initializers. */ +/* Like scalar_constant_value, but can also return aggregate initializers. + If UNSHARE_P, return an unshared copy of the initializer. */ tree -decl_really_constant_value (tree decl) +decl_really_constant_value (tree decl, bool unshare_p /*= true*/) { return constant_value_1 (decl, /*strict_p=*/true, - /*return_aggregate_cst_ok_p=*/true); + /*return_aggregate_cst_ok_p=*/true, + /*unshare_p=*/unshare_p); } -/* A more relaxed version of scalar_constant_value, used by the +/* A more relaxed version of decl_really_constant_value, used by the common C/C++ code. */ tree -decl_constant_value (tree decl) +decl_constant_value (tree decl, bool unshare_p) { return constant_value_1 (decl, /*strict_p=*/processing_template_decl, - /*return_aggregate_cst_ok_p=*/true); + /*return_aggregate_cst_ok_p=*/true, + /*unshare_p=*/unshare_p); +} + +tree +decl_constant_value (tree decl) +{ + return decl_constant_value (decl, /*unshare_p=*/true); } /* Common subroutines of build_new and build_vec_delete. */ @@ -2533,27 +2565,6 @@ throw_bad_array_new_length (void) return build_cxx_call (fn, 0, NULL, tf_warning_or_error); } -/* Attempt to find the initializer for flexible array field T in the - initializer INIT, when non-null. Returns the initializer when - successful and NULL otherwise. */ -static tree -find_flexarray_init (tree t, tree init) -{ - if (!init || init == error_mark_node) - return NULL_TREE; - - unsigned HOST_WIDE_INT idx; - tree field, elt; - - /* Iterate over all top-level initializer elements. */ - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt) - /* If the member T is found, return it. */ - if (field == t) - return elt; - - return NULL_TREE; -} - /* Attempt to verify that the argument, OPER, of a placement new expression refers to an object sufficiently large for an object of TYPE or an array of NELTS of such objects when NELTS is non-null, and issue a warning when @@ -2570,17 +2581,6 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) { location_t loc = cp_expr_loc_or_input_loc (oper); - /* The number of bytes to add to or subtract from the size of the provided - buffer based on an offset into an array or an array element reference. - Although intermediate results may be negative (as in a[3] - 2) a valid - final result cannot be. */ - offset_int adjust = 0; - /* True when the size of the entire destination object should be used - to compute the possibly optimistic estimate of the available space. */ - bool use_obj_size = false; - /* True when the reference to the destination buffer is an ADDR_EXPR. */ - bool addr_expr = false; - STRIP_NOPS (oper); /* Using a function argument or a (non-array) variable as an argument @@ -2594,231 +2594,96 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) /* Evaluate any constant expressions. */ size = fold_non_dependent_expr (size); - /* Handle the common case of array + offset expression when the offset - is a constant. */ - if (TREE_CODE (oper) == POINTER_PLUS_EXPR) - { - /* If the offset is compile-time constant, use it to compute a more - accurate estimate of the size of the buffer. Since the operand - of POINTER_PLUS_EXPR is represented as an unsigned type, convert - it to signed first. - Otherwise, use the size of the entire array as an optimistic - estimate (this may lead to false negatives). */ - tree adj = TREE_OPERAND (oper, 1); - adj = fold_for_warn (adj); - if (CONSTANT_CLASS_P (adj)) - adjust += wi::to_offset (convert (ssizetype, adj)); - else - use_obj_size = true; - - oper = TREE_OPERAND (oper, 0); - - STRIP_NOPS (oper); - } - - if (TREE_CODE (oper) == TARGET_EXPR) - oper = TREE_OPERAND (oper, 1); - else if (TREE_CODE (oper) == ADDR_EXPR) - { - addr_expr = true; - oper = TREE_OPERAND (oper, 0); - } - - STRIP_NOPS (oper); - - if (TREE_CODE (oper) == ARRAY_REF - && (addr_expr || TREE_CODE (TREE_TYPE (oper)) == ARRAY_TYPE)) - { - /* Similar to the offset computed above, see if the array index - is a compile-time constant. If so, and unless the offset was - not a compile-time constant, use the index to determine the - size of the buffer. Otherwise, use the entire array as - an optimistic estimate of the size. */ - const_tree adj = fold_non_dependent_expr (TREE_OPERAND (oper, 1)); - if (!use_obj_size && CONSTANT_CLASS_P (adj)) - adjust += wi::to_offset (adj); - else - { - use_obj_size = true; - adjust = 0; - } + access_ref ref; + ref.eval = [](tree x){ return fold_non_dependent_expr (x); }; + ref.trail1special = warn_placement_new < 2; + tree objsize = compute_objsize (oper, 1, &ref); + if (!objsize) + return; - oper = TREE_OPERAND (oper, 0); - } + offset_int bytes_avail = wi::to_offset (objsize); + offset_int bytes_need; - /* Refers to the declared object that constains the subobject referenced - by OPER. When the object is initialized, makes it possible to determine - the actual size of a flexible array member used as the buffer passed - as OPER to placement new. */ - tree var_decl = NULL_TREE; - /* True when operand is a COMPONENT_REF, to distinguish flexible array - members from arrays of unspecified size. */ - bool compref = TREE_CODE (oper) == COMPONENT_REF; - - /* For COMPONENT_REF (i.e., a struct member) the size of the entire - enclosing struct. Used to validate the adjustment (offset) into - an array at the end of a struct. */ - offset_int compsize = 0; - - /* Descend into a struct or union to find the member whose address - is being used as the argument. */ - if (TREE_CODE (oper) == COMPONENT_REF) + if (CONSTANT_CLASS_P (size)) + bytes_need = wi::to_offset (size); + else if (nelts && CONSTANT_CLASS_P (nelts)) + bytes_need = (wi::to_offset (nelts) + * wi::to_offset (TYPE_SIZE_UNIT (type))); + else if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))) + bytes_need = wi::to_offset (TYPE_SIZE_UNIT (type)); + else { - tree comptype = TREE_TYPE (TREE_OPERAND (oper, 0)); - compsize = wi::to_offset (TYPE_SIZE_UNIT (comptype)); - - tree op0 = oper; - while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF); - STRIP_ANY_LOCATION_WRAPPER (op0); - if (VAR_P (op0)) - var_decl = op0; - oper = TREE_OPERAND (oper, 1); + /* The type is a VLA. */ + return; } - STRIP_ANY_LOCATION_WRAPPER (oper); - tree opertype = TREE_TYPE (oper); - if ((addr_expr || !INDIRECT_TYPE_P (opertype)) - && (VAR_P (oper) - || TREE_CODE (oper) == FIELD_DECL - || TREE_CODE (oper) == PARM_DECL)) - { - /* A possibly optimistic estimate of the number of bytes available - in the destination buffer. */ - offset_int bytes_avail = 0; - /* True when the estimate above is in fact the exact size - of the destination buffer rather than an estimate. */ - bool exact_size = true; - - /* Treat members of unions and members of structs uniformly, even - though the size of a member of a union may be viewed as extending - to the end of the union itself (it is by __builtin_object_size). */ - if ((VAR_P (oper) || use_obj_size) - && DECL_SIZE_UNIT (oper) - && tree_fits_uhwi_p (DECL_SIZE_UNIT (oper))) - { - /* Use the size of the entire array object when the expression - refers to a variable or its size depends on an expression - that's not a compile-time constant. */ - bytes_avail = wi::to_offset (DECL_SIZE_UNIT (oper)); - exact_size = !use_obj_size; - } - else if (tree opersize = TYPE_SIZE_UNIT (opertype)) - { - /* Use the size of the type of the destination buffer object - as the optimistic estimate of the available space in it. - Use the maximum possible size for zero-size arrays and - flexible array members (except of initialized objects - thereof). */ - if (TREE_CODE (opersize) == INTEGER_CST) - bytes_avail = wi::to_offset (opersize); - } - - if (bytes_avail == 0) - { - if (var_decl) - { - /* Constructing into a buffer provided by the flexible array - member of a declared object (which is permitted as a G++ - extension). If the array member has been initialized, - determine its size from the initializer. Otherwise, - the array size is zero. */ - if (tree init = find_flexarray_init (oper, - DECL_INITIAL (var_decl))) - bytes_avail = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (init))); - } - else - bytes_avail = (wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)) - - compsize); - } - - tree_code oper_code = TREE_CODE (opertype); - - if (compref && oper_code == ARRAY_TYPE) - { - tree nelts = array_type_nelts_top (opertype); - tree nelts_cst = maybe_constant_value (nelts); - if (TREE_CODE (nelts_cst) == INTEGER_CST - && integer_onep (nelts_cst) - && !var_decl - && warn_placement_new < 2) - return; - } - - /* Reduce the size of the buffer by the adjustment computed above - from the offset and/or the index into the array. */ - if (bytes_avail < adjust || adjust < 0) - bytes_avail = 0; - else - { - tree elttype = (TREE_CODE (opertype) == ARRAY_TYPE - ? TREE_TYPE (opertype) : opertype); - if (tree eltsize = TYPE_SIZE_UNIT (elttype)) - { - bytes_avail -= adjust * wi::to_offset (eltsize); - if (bytes_avail < 0) - bytes_avail = 0; - } - } + if (bytes_avail >= bytes_need) + return; - /* The minimum amount of space needed for the allocation. This - is an optimistic estimate that makes it possible to detect - placement new invocation for some undersize buffers but not - others. */ - offset_int bytes_need; + /* True when the size to mention in the warning is exact as opposed + to "at least N". */ + const bool exact_size = (ref.offrng[0] == ref.offrng[1] + || ref.sizrng[1] - ref.offrng[0] == 0); - if (nelts) - nelts = fold_for_warn (nelts); - - if (CONSTANT_CLASS_P (size)) - bytes_need = wi::to_offset (size); - else if (nelts && CONSTANT_CLASS_P (nelts)) - bytes_need = (wi::to_offset (nelts) - * wi::to_offset (TYPE_SIZE_UNIT (type))); - else if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))) - bytes_need = wi::to_offset (TYPE_SIZE_UNIT (type)); - else - { - /* The type is a VLA. */ - return; - } + tree opertype = ref.ref ? TREE_TYPE (ref.ref) : TREE_TYPE (oper); + bool warned = false; + if (nelts) + nelts = fold_for_warn (nelts); + if (nelts) + if (CONSTANT_CLASS_P (nelts)) + warned = warning_at (loc, OPT_Wplacement_new_, + (exact_size + ? G_("placement new constructing an object " + "of type %<%T [%wu]%> and size %qwu " + "in a region of type %qT and size %qwi") + : G_("placement new constructing an object " + "of type %<%T [%wu]%> and size %qwu " + "in a region of type %qT and size " + "at most %qwu")), + type, tree_to_uhwi (nelts), + bytes_need.to_uhwi (), + opertype, bytes_avail.to_uhwi ()); + else + warned = warning_at (loc, OPT_Wplacement_new_, + (exact_size + ? G_("placement new constructing an array " + "of objects of type %qT and size %qwu " + "in a region of type %qT and size %qwi") + : G_("placement new constructing an array " + "of objects of type %qT and size %qwu " + "in a region of type %qT and size " + "at most %qwu")), + type, bytes_need.to_uhwi (), opertype, + bytes_avail.to_uhwi ()); + else + warned = warning_at (loc, OPT_Wplacement_new_, + (exact_size + ? G_("placement new constructing an object " + "of type %qT and size %qwu in a region " + "of type %qT and size %qwi") + : G_("placement new constructing an object " + "of type %qT " + "and size %qwu in a region of type %qT " + "and size at most %qwu")), + type, bytes_need.to_uhwi (), opertype, + bytes_avail.to_uhwi ()); + + if (!warned || !ref.ref) + return; - if (bytes_avail < bytes_need) - { - if (nelts) - if (CONSTANT_CLASS_P (nelts)) - warning_at (loc, OPT_Wplacement_new_, - exact_size ? - "placement new constructing an object of type " - "%<%T [%wu]%> and size %qwu in a region of type %qT " - "and size %qwi" - : "placement new constructing an object of type " - "%<%T [%wu]%> and size %qwu in a region of type %qT " - "and size at most %qwu", - type, tree_to_uhwi (nelts), bytes_need.to_uhwi (), - opertype, bytes_avail.to_uhwi ()); - else - warning_at (loc, OPT_Wplacement_new_, - exact_size ? - "placement new constructing an array of objects " - "of type %qT and size %qwu in a region of type %qT " - "and size %qwi" - : "placement new constructing an array of objects " - "of type %qT and size %qwu in a region of type %qT " - "and size at most %qwu", - type, bytes_need.to_uhwi (), opertype, - bytes_avail.to_uhwi ()); - else - warning_at (loc, OPT_Wplacement_new_, - exact_size ? - "placement new constructing an object of type %qT " - "and size %qwu in a region of type %qT and size %qwi" - : "placement new constructing an object of type %qT " - "and size %qwu in a region of type %qT and size " - "at most %qwu", - type, bytes_need.to_uhwi (), opertype, - bytes_avail.to_uhwi ()); - } - } + if (ref.offrng[0] == 0 || !ref.offset_bounded ()) + /* Avoid mentioning the offset when its lower bound is zero + or when it's impossibly large. */ + inform (DECL_SOURCE_LOCATION (ref.ref), + "%qD declared here", ref.ref); + else if (ref.offrng[0] == ref.offrng[1]) + inform (DECL_SOURCE_LOCATION (ref.ref), + "at offset %wi from %qD declared here", + ref.offrng[0].to_shwi (), ref.ref); + else + inform (DECL_SOURCE_LOCATION (ref.ref), + "at offset [%wi, %wi] from %qD declared here", + ref.offrng[0].to_shwi (), ref.offrng[1].to_shwi (), ref.ref); } /* True if alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__. */ @@ -3402,10 +3267,6 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, } } - tree alloc_call_expr = extract_call_expr (alloc_call); - if (TREE_CODE (alloc_call_expr) == CALL_EXPR) - CALL_FROM_NEW_OR_DELETE_P (alloc_call_expr) = 1; - if (cookie_size) alloc_call = maybe_wrap_new_for_constexpr (alloc_call, elt_type, cookie_size); @@ -3540,8 +3401,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, else if (array_p) { tree vecinit = NULL_TREE; - if (vec_safe_length (*init) == 1 - && DIRECT_LIST_INIT_P ((**init)[0])) + const size_t len = vec_safe_length (*init); + if (len == 1 && DIRECT_LIST_INIT_P ((**init)[0])) { vecinit = (**init)[0]; if (CONSTRUCTOR_NELTS (vecinit) == 0) @@ -3556,6 +3417,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* We'll check the length at runtime. */ domain = NULL_TREE; arraytype = build_cplus_array_type (type, domain); + /* If we have new char[4]{"foo"}, we have to reshape + so that the STRING_CST isn't wrapped in { }. */ + vecinit = reshape_init (arraytype, vecinit, complain); + /* The middle end doesn't cope with the location wrapper + around a STRING_CST. */ + STRIP_ANY_LOCATION_WRAPPER (vecinit); vecinit = digest_init (arraytype, vecinit, complain); } } @@ -3615,8 +3482,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, && AGGREGATE_TYPE_P (type) && (*init)->length () > 1) { - ie = build_tree_list_vec (*init); - ie = build_constructor_from_list (init_list_type_node, ie); + ie = build_constructor_from_vec (init_list_type_node, *init); CONSTRUCTOR_IS_DIRECT_INIT (ie) = true; CONSTRUCTOR_IS_PAREN_INIT (ie) = true; ie = digest_init (type, ie, complain); @@ -3898,6 +3764,46 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type, return error_mark_node; } + /* P1009: Array size deduction in new-expressions. */ + const bool array_p = TREE_CODE (type) == ARRAY_TYPE; + if (*init && (array_p || (nelts && cxx_dialect >= cxx20))) + { + /* This means we have 'new T[]()'. */ + if ((*init)->is_empty ()) + { + tree ctor = build_constructor (init_list_type_node, NULL); + CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true; + vec_safe_push (*init, ctor); + } + tree &elt = (**init)[0]; + /* The C++20 'new T[](e_0, ..., e_k)' case allowed by P0960. */ + if (!DIRECT_LIST_INIT_P (elt) && cxx_dialect >= cxx20) + { + tree ctor = build_constructor_from_vec (init_list_type_node, *init); + CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true; + CONSTRUCTOR_IS_PAREN_INIT (ctor) = true; + elt = ctor; + /* We've squashed all the vector elements into the first one; + truncate the rest. */ + (*init)->truncate (1); + } + /* Otherwise we should have 'new T[]{e_0, ..., e_k}'. */ + if (array_p && !TYPE_DOMAIN (type)) + { + /* We need to reshape before deducing the bounds to handle code like + + struct S { int x, y; }; + new S[]{1, 2, 3, 4}; + + which should deduce S[2]. But don't change ELT itself: we want to + pass a list-initializer to build_new_1, even for STRING_CSTs. */ + tree e = elt; + if (BRACE_ENCLOSED_INITIALIZER_P (e)) + e = reshape_init (type, e, complain); + cp_complete_array_type (&type, e, /*do_default*/false); + } + } + /* The type allocated must be complete. If the new-type-id was "T[N]" then we are just checking that "T" is complete here, but that is equivalent, since the value of "N" doesn't matter. */ @@ -4069,10 +3975,6 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type, /*placement=*/NULL_TREE, /*alloc_fn=*/NULL_TREE, complain); - - tree deallocate_call_expr = extract_call_expr (deallocate_expr); - if (TREE_CODE (deallocate_call_expr) == CALL_EXPR) - CALL_FROM_NEW_OR_DELETE_P (deallocate_call_expr) = 1; } body = loop; @@ -4997,12 +4899,6 @@ build_delete (location_t loc, tree otype, tree addr, if (do_delete == error_mark_node) return error_mark_node; - else if (do_delete) - { - tree do_delete_call_expr = extract_call_expr (do_delete); - if (TREE_CODE (do_delete_call_expr) == CALL_EXPR) - CALL_FROM_NEW_OR_DELETE_P (do_delete_call_expr) = 1; - } if (do_delete && !TREE_SIDE_EFFECTS (expr)) expr = do_delete; diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index c94fe8e..1a1647f 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -134,8 +134,7 @@ begin_lambda_type (tree lambda) IDENTIFIER_LAMBDA_P (name) = true; /* Create the new RECORD_TYPE for this lambda. */ - tree type = xref_tag (/*tag_code=*/record_type, name, - /*scope=*/ts_lambda, /*template_header_p=*/false); + tree type = xref_tag (/*tag_code=*/record_type, name); if (type == error_mark_node) return error_mark_node; @@ -476,7 +475,7 @@ static GTY(()) tree max_id; static tree vla_capture_type (tree array_type) { - tree type = xref_tag (record_type, make_anon_name (), ts_current, false); + tree type = xref_tag (record_type, make_anon_name ()); xref_basetypes (type, NULL_TREE); type = begin_class_definition (type); if (!ptr_id) @@ -1189,6 +1188,8 @@ maybe_add_lambda_conv_op (tree type) tree name = make_conv_op_name (rettype); tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); tree fntype = build_method_type_directly (thistype, rettype, void_list_node); + /* DR 1722: The conversion function should be noexcept. */ + fntype = build_exception_variant (fntype, noexcept_true_spec); tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype); SET_DECL_LANGUAGE (convfn, lang_cplusplus); tree fn = convfn; @@ -1324,6 +1325,13 @@ lambda_static_thunk_p (tree fn) && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fn))); } +bool +call_from_lambda_thunk_p (tree call) +{ + return (CALL_FROM_THUNK_P (call) + && lambda_static_thunk_p (current_function_decl)); +} + /* Returns true iff VAL is a lambda-related declaration which should be ignored by unqualified lookup. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index ab2d8ec..9fd3001 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -170,7 +170,7 @@ integer_type_codes[itk_none] = '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; -static int decl_is_template_id (const tree, tree* const); +static tree maybe_template_info (const tree); /* Functions for handling substitutions. */ @@ -272,11 +272,10 @@ static tree mangle_special_for_type (const tree, const char *); write_number ((NUMBER), /*unsigned_p=*/1, 10) /* If DECL is a template instance (including the uninstantiated template - itself), return nonzero and, if TEMPLATE_INFO is non-NULL, set - *TEMPLATE_INFO to its template info. Otherwise return zero. */ + itself), return its TEMPLATE_INFO. Otherwise return NULL. */ -static int -decl_is_template_id (const tree decl, tree* const template_info) +static tree +maybe_template_info (const tree decl) { if (TREE_CODE (decl) == TYPE_DECL) { @@ -285,33 +284,20 @@ decl_is_template_id (const tree decl, tree* const template_info) const tree type = TREE_TYPE (decl); if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_ID_P (type)) - { - if (template_info != NULL) - /* For a templated TYPE_DECL, the template info is hanging - off the type. */ - *template_info = TYPE_TEMPLATE_INFO (type); - return 1; - } + return TYPE_TEMPLATE_INFO (type); } else { - /* Check if this is a primary template. */ + /* Check if the template is a primary template. */ if (DECL_LANG_SPECIFIC (decl) != NULL && VAR_OR_FUNCTION_DECL_P (decl) && DECL_TEMPLATE_INFO (decl) - && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)) - && TREE_CODE (decl) != TEMPLATE_DECL) - { - if (template_info != NULL) - /* For most templated decls, the template info is hanging - off the decl. */ - *template_info = DECL_TEMPLATE_INFO (decl); - return 1; - } + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))) + return DECL_TEMPLATE_INFO (decl); } /* It's not a template id. */ - return 0; + return NULL_TREE; } /* Produce debugging output of current substitution candidates. */ @@ -628,9 +614,7 @@ find_substitution (tree node) { tree args = CLASSTYPE_TI_ARGS (type); if (TREE_VEC_LENGTH (args) == 3 - && (TREE_CODE (TREE_VEC_ELT (args, 0)) - == TREE_CODE (char_type_node)) - && same_type_p (TREE_VEC_ELT (args, 0), char_type_node) + && template_args_equal (TREE_VEC_ELT (args, 0), char_type_node) && is_std_substitution_char (TREE_VEC_ELT (args, 1), SUBID_CHAR_TRAITS) && is_std_substitution_char (TREE_VEC_ELT (args, 2), @@ -654,8 +638,7 @@ find_substitution (tree node) args <char, std::char_traits<char> > . */ tree args = CLASSTYPE_TI_ARGS (type); if (TREE_VEC_LENGTH (args) == 2 - && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_CODE (char_type_node) - && same_type_p (TREE_VEC_ELT (args, 0), char_type_node) + && template_args_equal (TREE_VEC_ELT (args, 0), char_type_node) && is_std_substitution_char (TREE_VEC_ELT (args, 1), SUBID_CHAR_TRAITS)) { @@ -800,7 +783,7 @@ mangle_return_type_p (tree decl) return (!DECL_CONSTRUCTOR_P (decl) && !DECL_DESTRUCTOR_P (decl) && !DECL_CONV_FN_P (decl) - && decl_is_template_id (decl, NULL)); + && maybe_template_info (decl)); } /* <encoding> ::= <function name> <bare-function-type> @@ -827,9 +810,8 @@ write_encoding (const tree decl) { tree fn_type; tree d; - bool tmpl = decl_is_template_id (decl, NULL); - if (tmpl) + if (maybe_template_info (decl)) { fn_type = get_mostly_instantiated_function_type (decl); /* FN_TYPE will not have parameter types for in-charge or @@ -933,13 +915,12 @@ write_name (tree decl, const int ignore_local_scope) || (abi_version_at_least (7) && TREE_CODE (context) == PARM_DECL)))) { - tree template_info; /* Is this a template instance? */ - if (decl_is_template_id (decl, &template_info)) + if (tree info = maybe_template_info (decl)) { /* Yes: use <unscoped-template-name>. */ - write_unscoped_template_name (TI_TEMPLATE (template_info)); - write_template_args (TI_ARGS (template_info)); + write_unscoped_template_name (TI_TEMPLATE (info)); + write_template_args (TI_ARGS (info)); } else /* Everything else gets an <unqualified-name>. */ @@ -1041,8 +1022,6 @@ write_unscoped_template_name (const tree decl) static void write_nested_name (const tree decl) { - tree template_info; - MANGLE_TRACE_TREE ("nested-name", decl); write_char ('N'); @@ -1065,11 +1044,11 @@ write_nested_name (const tree decl) } /* Is this a template instance? */ - if (decl_is_template_id (decl, &template_info)) + if (tree info = maybe_template_info (decl)) { /* Yes, use <template-prefix>. */ write_template_prefix (decl); - write_template_args (TI_ARGS (template_info)); + write_template_args (TI_ARGS (info)); } else if ((!abi_version_at_least (10) || TREE_CODE (decl) == TYPE_DECL) && TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE) @@ -1106,8 +1085,6 @@ static void write_prefix (const tree node) { tree decl; - /* Non-NULL if NODE represents a template-id. */ - tree template_info = NULL; if (node == NULL || node == global_namespace) @@ -1124,6 +1101,7 @@ write_prefix (const tree node) if (find_substitution (node)) return; + tree template_info = NULL_TREE; if (DECL_P (node)) { /* If this is a function or parm decl, that means we've hit function @@ -1136,19 +1114,20 @@ write_prefix (const tree node) return; decl = node; - decl_is_template_id (decl, &template_info); + template_info = maybe_template_info (decl); } else { /* Node is a type. */ decl = TYPE_NAME (node); + /* The DECL might not point at the node. */ if (CLASSTYPE_TEMPLATE_ID_P (node)) template_info = TYPE_TEMPLATE_INFO (node); } if (TREE_CODE (node) == TEMPLATE_TYPE_PARM) write_template_param (node); - else if (template_info != NULL) + else if (template_info) /* Templated. */ { write_template_prefix (decl); @@ -1195,15 +1174,14 @@ write_template_prefix (const tree node) tree decl = DECL_P (node) ? node : TYPE_NAME (node); tree type = DECL_P (node) ? TREE_TYPE (node) : node; tree context = decl_mangling_context (decl); - tree template_info; tree templ; tree substitution; MANGLE_TRACE_TREE ("template-prefix", node); /* Find the template decl. */ - if (decl_is_template_id (decl, &template_info)) - templ = TI_TEMPLATE (template_info); + if (tree info = maybe_template_info (decl)) + templ = TI_TEMPLATE (info); else if (TREE_CODE (type) == TYPENAME_TYPE) /* For a typename type, all we have is the name. */ templ = DECL_NAME (decl); @@ -1369,7 +1347,7 @@ write_unqualified_name (tree decl) /* Conversion operator. Handle it right here. <operator> ::= cv <type> */ tree type; - if (decl_is_template_id (decl, NULL)) + if (maybe_template_info (decl)) { tree fn_type; fn_type = get_mostly_instantiated_function_type (decl); @@ -1413,8 +1391,7 @@ write_unqualified_name (tree decl) if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type)) write_unnamed_type_name (type); - else if (TREE_CODE (decl) == TYPE_DECL - && LAMBDA_TYPE_P (type)) + else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) write_closure_type_name (type); else write_source_name (DECL_NAME (decl)); @@ -2850,6 +2827,60 @@ write_member_name (tree member) write_expression (member); } +/* EXPR is a base COMPONENT_REF; write the minimized base conversion path for + converting to BASE, or just the conversion of EXPR if BASE is null. + + "Given a fully explicit base path P := C_n -> ... -> C_0, the minimized base + path Min(P) is defined as follows: let C_i be the last element for which the + conversion to C_0 is unambiguous; if that element is C_n, the minimized path + is C_n -> C_0; otherwise, the minimized path is Min(C_n -> ... -> C_i) -> + C_0." + + We mangle the conversion to C_i if it's different from C_n. */ + +static bool +write_base_ref (tree expr, tree base = NULL_TREE) +{ + if (TREE_CODE (expr) != COMPONENT_REF) + return false; + + tree field = TREE_OPERAND (expr, 1); + + if (TREE_CODE (field) != FIELD_DECL || !DECL_FIELD_IS_BASE (field)) + return false; + + tree object = TREE_OPERAND (expr, 0); + + tree binfo = NULL_TREE; + if (base) + { + tree cur = TREE_TYPE (object); + binfo = lookup_base (cur, base, ba_unique, NULL, tf_none); + } + else + /* We're at the end of the base conversion chain, so it can't be + ambiguous. */ + base = TREE_TYPE (field); + + if (binfo == error_mark_node) + { + /* cur->base is ambiguous, so make the conversion to + last explicit, expressed as a cast (last&)object. */ + tree last = TREE_TYPE (expr); + write_string (OVL_OP_INFO (false, CAST_EXPR)->mangled_name); + write_type (build_reference_type (last)); + write_expression (object); + } + else if (write_base_ref (object, base)) + /* cur->base is unambiguous, but we had another base conversion + underneath and wrote it out. */; + else + /* No more base conversions, just write out the object. */ + write_expression (object); + + return true; +} + /* <expression> ::= <unary operator-name> <expression> ::= <binary operator-name> <expression> <expression> ::= <expr-primary> @@ -3268,6 +3299,8 @@ write_expression (tree expr) ob = TREE_OPERAND (ob, 0); write_expression (ob); } + else if (write_base_ref (expr)) + return; else if (!is_dummy_object (ob)) { write_string ("dt"); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 8fd7052..6e4c5f7 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -551,28 +551,51 @@ inherited_ctor_binfo (tree fndecl) return inherited_ctor_binfo (binfo, fndecl); } -/* True if we should omit all user-declared parameters from constructor FN, - because it is a base clone of a ctor inherited from a virtual base. */ + +/* True if we should omit all user-declared parameters from a base + construtor built from complete constructor FN. + That's when the ctor is inherited from a virtual base. */ bool -ctor_omit_inherited_parms (tree fn) +base_ctor_omit_inherited_parms (tree comp_ctor) { + gcc_checking_assert (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (comp_ctor)); + if (!flag_new_inheriting_ctors) /* We only optimize away the parameters in the new model. */ return false; - if (!DECL_BASE_CONSTRUCTOR_P (fn) - || !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) + + if (!CLASSTYPE_VBASECLASSES (DECL_CONTEXT (comp_ctor))) return false; - if (FUNCTION_FIRST_USER_PARMTYPE (DECL_ORIGIN (fn)) == void_list_node) + + if (FUNCTION_FIRST_USER_PARMTYPE (comp_ctor) == void_list_node) /* No user-declared parameters to omit. */ return false; - tree binfo = inherited_ctor_binfo (fn); - for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo)) + + for (tree binfo = inherited_ctor_binfo (comp_ctor); + binfo; + binfo = BINFO_INHERITANCE_CHAIN (binfo)) if (BINFO_VIRTUAL_P (binfo)) return true; + return false; } + +/* True if we should omit all user-declared parameters from constructor FN, + because it is a base clone of a ctor inherited from a virtual base. */ + +bool +ctor_omit_inherited_parms (tree fn) +{ + gcc_checking_assert (TREE_CODE (fn) == FUNCTION_DECL); + + if (!DECL_BASE_CONSTRUCTOR_P (fn)) + return false; + + return base_ctor_omit_inherited_parms (DECL_CLONED_FUNCTION (fn)); +} + /* True iff constructor(s) INH inherited into BINFO initializes INIT_BINFO. This can be true for multiple virtual bases as well as one direct non-virtual base. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 159c98a..e3f3712 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see static cxx_binding *cxx_binding_make (tree value, tree type); static cp_binding_level *innermost_nonclass_level (void); +static tree do_pushdecl_with_scope (tree x, cp_binding_level *, bool hiding); static void set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b); static name_hint maybe_suggest_missing_std_header (location_t location, @@ -55,6 +56,15 @@ static name_hint suggest_alternatives_for_1 (location_t location, tree name, #define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N) #define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE) +/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P. + But we also need to indicate hiddenness on implicit type decls + (injected friend classes), and (coming soon) decls injected from + block-scope externs. It is too awkward to press the existing + overload marking for that. If we have a hidden non-function, we + always create a STAT_HACK, and use these two markers as needed. */ +#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N) +#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N) + /* Create a STAT_HACK node with DECL as the value binding and TYPE as the type binding. */ @@ -77,7 +87,6 @@ create_local_binding (cp_binding_level *level, tree name) { cxx_binding *binding = cxx_binding_make (NULL, NULL); - INHERITED_VALUE_BINDING_P (binding) = false; LOCAL_BINDING_P (binding) = true; binding->scope = level; binding->previous = IDENTIFIER_BINDING (name); @@ -124,13 +133,11 @@ add_decl_to_level (cp_binding_level *b, tree decl) TREE_CHAIN (decl) = b->names; b->names = decl; - /* If appropriate, add decl to separate list of statics. We - include extern variables because they might turn out to be - static later. It's OK for this list to contain a few false - positives. */ + /* If appropriate, add decl to separate list of statics. We include + extern variables because they might turn out to be static later. + It's OK for this list to contain a few false positives. */ if (b->kind == sk_namespace - && ((VAR_P (decl) - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) + && ((VAR_P (decl) && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) || (TREE_CODE (decl) == FUNCTION_DECL && (!TREE_PUBLIC (decl) || decl_anon_ns_mem_p (decl) @@ -166,7 +173,8 @@ public: tree name; /* The identifier being looked for. */ tree value; /* A (possibly ambiguous) set of things found. */ tree type; /* A type that has been found. */ - int flags; /* Lookup flags. */ + LOOK_want want; /* What kind of entity we want. */ + bool deduping; /* Full deduping is needed because using declarations are in play. */ vec<tree, va_heap, vl_embed> *scopes; @@ -179,8 +187,9 @@ protected: static name_lookup *active; public: - name_lookup (tree n, int f = 0) - : name (n), value (NULL_TREE), type (NULL_TREE), flags (f), + name_lookup (tree n, LOOK_want w = LOOK_want::NORMAL) + : name (n), value (NULL_TREE), type (NULL_TREE), + want (w), deduping (false), scopes (NULL), previous (NULL) { preserve_state (); @@ -419,7 +428,7 @@ name_lookup::add_overload (tree fns) if (!deduping && TREE_CODE (fns) == OVERLOAD) { tree probe = fns; - if (flags & LOOKUP_HIDDEN) + if (!bool (want & LOOK_want::HIDDEN_FRIEND)) probe = ovl_skip_hidden (probe); if (probe && TREE_CODE (probe) == OVERLOAD && OVL_DEDUP_P (probe)) @@ -480,22 +489,17 @@ name_lookup::add_type (tree new_type) } /* Process a found binding containing NEW_VAL and NEW_TYPE. Returns - true if we actually found something noteworthy. */ + true if we actually found something noteworthy. Hiddenness has + already been handled in the caller. */ bool name_lookup::process_binding (tree new_val, tree new_type) { /* Did we really see a type? */ if (new_type - && (LOOKUP_NAMESPACES_ONLY (flags) - || (!(flags & LOOKUP_HIDDEN) - && DECL_LANG_SPECIFIC (new_type) - && DECL_ANTICIPATED (new_type)))) + && (want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::NAMESPACE) new_type = NULL_TREE; - if (new_val && !(flags & LOOKUP_HIDDEN)) - new_val = ovl_skip_hidden (new_val); - /* Do we really see a value? */ if (new_val) switch (TREE_CODE (new_val)) @@ -503,21 +507,21 @@ name_lookup::process_binding (tree new_val, tree new_type) case TEMPLATE_DECL: /* If we expect types or namespaces, and not templates, or this is not a template class. */ - if ((LOOKUP_QUALIFIERS_ONLY (flags) - && !DECL_TYPE_TEMPLATE_P (new_val))) + if (bool (want & LOOK_want::TYPE_NAMESPACE) + && !DECL_TYPE_TEMPLATE_P (new_val)) new_val = NULL_TREE; break; case TYPE_DECL: - if (LOOKUP_NAMESPACES_ONLY (flags) - || (new_type && (flags & LOOKUP_PREFER_TYPES))) + if ((want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::NAMESPACE + || (new_type && bool (want & LOOK_want::TYPE))) new_val = NULL_TREE; break; case NAMESPACE_DECL: - if (LOOKUP_TYPES_ONLY (flags)) + if ((want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::TYPE) new_val = NULL_TREE; break; default: - if (LOOKUP_QUALIFIERS_ONLY (flags)) + if (bool (want & LOOK_want::TYPE_NAMESPACE)) new_val = NULL_TREE; } @@ -544,8 +548,29 @@ name_lookup::search_namespace_only (tree scope) bool found = false; if (tree *binding = find_namespace_slot (scope, name)) - found |= process_binding (MAYBE_STAT_DECL (*binding), - MAYBE_STAT_TYPE (*binding)); + { + tree value = *binding, type = NULL_TREE; + + if (STAT_HACK_P (value)) + { + type = STAT_TYPE (value); + value = STAT_DECL (value); + + if (!bool (want & LOOK_want::HIDDEN_FRIEND)) + { + if (STAT_TYPE_HIDDEN_P (*binding)) + type = NULL_TREE; + if (STAT_DECL_HIDDEN_P (*binding)) + value = NULL_TREE; + else + value = ovl_skip_hidden (value); + } + } + else if (!bool (want & LOOK_want::HIDDEN_FRIEND)) + value = ovl_skip_hidden (value); + + found |= process_binding (value, type); + } return found; } @@ -717,16 +742,17 @@ name_lookup::search_unqualified (tree scope, cp_binding_level *level) if (scope == global_namespace) break; - /* If looking for hidden names, we only look in the innermost + /* If looking for hidden friends, we only look in the innermost namespace scope. [namespace.memdef]/3 If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. See also [basic.lookup.unqual]/7 */ - if (flags & LOOKUP_HIDDEN) + if (bool (want & LOOK_want::HIDDEN_FRIEND)) break; } + /* Restore to incoming length. */ vec_safe_truncate (queue, length); return found; @@ -817,12 +843,6 @@ name_lookup::adl_class_only (tree type) if (CP_DECL_CONTEXT (fn) != context) continue; - /* Only interested in anticipated friends. (Non-anticipated - ones will have been inserted during the namespace - adl.) */ - if (!DECL_ANTICIPATED (fn)) - continue; - /* Template specializations are never found by name lookup. (Templates themselves can be found, but not template specializations.) */ @@ -1054,11 +1074,8 @@ name_lookup::adl_template_arg (tree arg) tree name_lookup::search_adl (tree fns, vec<tree, va_gc> *args) { - if (fns) - { - deduping = true; - lookup_mark (fns, true); - } + deduping = true; + lookup_mark (fns, true); value = fns; unsigned ix; @@ -1670,7 +1687,7 @@ member_vec_dedup (vec<tree, va_gc> *member_vec) no existing MEMBER_VEC and fewer than 8 fields, do nothing. We know there must be at least 1 field -- the self-reference TYPE_DECL, except for anon aggregates, which will have at least - one field. */ + one field anyway. */ void set_class_bindings (tree klass, unsigned extra) @@ -1953,15 +1970,18 @@ cxx_binding_init (cxx_binding *binding, tree value, tree type) static cxx_binding * cxx_binding_make (tree value, tree type) { - cxx_binding *binding; - if (free_bindings) - { - binding = free_bindings; - free_bindings = binding->previous; - } + cxx_binding *binding = free_bindings; + + if (binding) + free_bindings = binding->previous; else binding = ggc_alloc<cxx_binding> (); + /* Clear flags by default. */ + LOCAL_BINDING_P (binding) = false; + INHERITED_VALUE_BINDING_P (binding) = false; + HIDDEN_TYPE_BINDING_P (binding) = false; + cxx_binding_init (binding, value, type); return binding; @@ -2008,7 +2028,6 @@ push_binding (tree id, tree decl, cp_binding_level* level) /* Now, fill in the binding information. */ binding->previous = IDENTIFIER_BINDING (id); - INHERITED_VALUE_BINDING_P (binding) = 0; LOCAL_BINDING_P (binding) = (level != class_binding_level); /* And put it on the front of the list of bindings for ID. */ @@ -2021,8 +2040,6 @@ push_binding (tree id, tree decl, cp_binding_level* level) void pop_local_binding (tree id, tree decl) { - cxx_binding *binding; - if (id == NULL_TREE) /* It's easiest to write the loops that call this function without checking whether or not the entities involved have names. We @@ -2030,18 +2047,20 @@ pop_local_binding (tree id, tree decl) return; /* Get the innermost binding for ID. */ - binding = IDENTIFIER_BINDING (id); + cxx_binding *binding = IDENTIFIER_BINDING (id); /* The name should be bound. */ gcc_assert (binding != NULL); - /* The DECL will be either the ordinary binding or the type - binding for this identifier. Remove that binding. */ + /* The DECL will be either the ordinary binding or the type binding + for this identifier. Remove that binding. We don't have to + clear HIDDEN_TYPE_BINDING_P, as the whole binding will be going + away. */ if (binding->value == decl) binding->value = NULL_TREE; else { - gcc_assert (binding->type == decl); + gcc_checking_assert (binding->type == decl); binding->type = NULL_TREE; } @@ -2109,19 +2128,9 @@ strip_using_decl (tree decl) static bool anticipated_builtin_p (tree ovl) { - if (TREE_CODE (ovl) != OVERLOAD) - return false; - - if (!OVL_HIDDEN_P (ovl)) - return false; - - tree fn = OVL_FUNCTION (ovl); - gcc_checking_assert (DECL_ANTICIPATED (fn)); - - if (DECL_HIDDEN_FRIEND_P (fn)) - return false; - - return true; + return (TREE_CODE (ovl) == OVERLOAD + && OVL_HIDDEN_P (ovl) + && DECL_UNDECLARED_BUILTIN_P (OVL_FUNCTION (ovl))); } /* BINDING records an existing declaration for a name in the current scope. @@ -2231,7 +2240,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl) && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) && !DECL_CLASS_SCOPE_P (target_decl)) { - duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false); + duplicate_decls (decl, binding->value); ok = false; } else if (TREE_CODE (decl) == NAMESPACE_DECL @@ -2304,7 +2313,7 @@ update_local_overload (cxx_binding *binding, tree newval) if (*d == binding->value) { /* Stitch new list node in. */ - *d = tree_cons (NULL_TREE, NULL_TREE, TREE_CHAIN (*d)); + *d = tree_cons (DECL_NAME (*d), NULL_TREE, TREE_CHAIN (*d)); break; } else if (TREE_CODE (*d) == TREE_LIST && TREE_VALUE (*d) == binding->value) @@ -2353,48 +2362,66 @@ matching_fn_p (tree one, tree two) static tree update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, - tree old, tree decl, bool is_friend) + tree old, tree decl, bool hiding = false) { + tree old_type = NULL_TREE; + bool hide_type = false; + bool hide_value = false; + + if (!slot) + { + old_type = binding->type; + hide_type = HIDDEN_TYPE_BINDING_P (binding); + if (!old_type) + hide_value = hide_type, hide_type = false; + } + else if (STAT_HACK_P (*slot)) + { + old_type = STAT_TYPE (*slot); + hide_type = STAT_TYPE_HIDDEN_P (*slot); + hide_value = STAT_DECL_HIDDEN_P (*slot); + } + tree to_val = decl; - tree old_type = slot ? MAYBE_STAT_TYPE (*slot) : binding->type; tree to_type = old_type; + bool local_overload = false; gcc_assert (level->kind == sk_namespace ? !binding : level->kind != sk_class && !slot); if (old == error_mark_node) old = NULL_TREE; - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)) + if (DECL_IMPLICIT_TYPEDEF_P (decl)) { - tree other = to_type; - - if (old && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old)) - other = old; - - /* Pushing an artificial typedef. See if this matches either - the type slot or the old value slot. */ - if (!other) - ; - else if (same_type_p (TREE_TYPE (other), TREE_TYPE (decl))) - /* Two artificial decls to same type. Do nothing. */ - return other; - else - goto conflict; + /* Pushing an artificial decl. We should not find another + artificial decl here already -- lookup_elaborated_type will + have already found it. */ + gcc_checking_assert (!to_type + && !(old && DECL_IMPLICIT_TYPEDEF_P (old))); if (old) { - /* Slide decl into the type slot, keep old unaltered */ + /* Put DECL into the type slot. */ + gcc_checking_assert (!to_type); + hide_type = hiding; to_type = decl; to_val = old; - goto done; } + else + hide_value = hiding; + + goto done; } - if (old && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old)) + if (old && DECL_IMPLICIT_TYPEDEF_P (old)) { - /* Slide old into the type slot. */ + /* OLD is an implicit typedef. Move it to to_type. */ + gcc_checking_assert (!to_type); + to_type = old; + hide_type = hide_value; old = NULL_TREE; + hide_value = false; } if (DECL_DECLARES_FUNCTION_P (decl)) @@ -2409,13 +2436,14 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, if (iter.using_p () && matching_fn_p (fn, decl)) { + gcc_checking_assert (!iter.hidden_p ()); /* If a function declaration in namespace scope or block scope has the same name and the same parameter-type- list (8.3.5) as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed. [namespace.udecl]/14 */ - if (tree match = duplicate_decls (decl, fn, is_friend)) + if (tree match = duplicate_decls (decl, fn, hiding)) return match; else /* FIXME: To preserve existing error behavior, we @@ -2435,60 +2463,70 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, warning (OPT_Wshadow, "%q#D hides constructor for %q#D", decl, to_type); - to_val = ovl_insert (decl, old); + local_overload = old && level->kind != sk_namespace; + to_val = ovl_insert (decl, old, -int (hiding)); } - else if (!old) - ; - else if (TREE_CODE (old) != TREE_CODE (decl)) - /* Different kinds of decls conflict. */ - goto conflict; - else if (TREE_CODE (old) == TYPE_DECL) - { - if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))) - /* Two type decls to the same type. Do nothing. */ - return old; - else - goto conflict; - } - else if (TREE_CODE (old) == NAMESPACE_DECL) + else if (old) { - /* Two maybe-aliased namespaces. If they're to the same target - namespace, that's ok. */ - if (ORIGINAL_NAMESPACE (old) != ORIGINAL_NAMESPACE (decl)) + if (TREE_CODE (old) != TREE_CODE (decl)) + /* Different kinds of decls conflict. */ goto conflict; - - /* The new one must be an alias at this point. */ - gcc_assert (DECL_NAMESPACE_ALIAS (decl)); - return old; - } - else if (TREE_CODE (old) == VAR_DECL) - { - /* There can be two block-scope declarations of the same - variable, so long as they are `extern' declarations. */ - if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl)) - goto conflict; - else if (tree match = duplicate_decls (decl, old, false)) - return match; + else if (TREE_CODE (old) == TYPE_DECL) + { + if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))) + { + /* Two type decls to the same type. Do nothing. */ + gcc_checking_assert (!hiding); + return old; + } + else + goto conflict; + } + else if (TREE_CODE (old) == NAMESPACE_DECL) + { + /* Two maybe-aliased namespaces. If they're to the same target + namespace, that's ok. */ + if (ORIGINAL_NAMESPACE (old) != ORIGINAL_NAMESPACE (decl)) + goto conflict; + + /* The new one must be an alias at this point. */ + gcc_assert (DECL_NAMESPACE_ALIAS (decl) && !hiding); + return old; + } + else if (TREE_CODE (old) == VAR_DECL) + { + /* There can be two block-scope declarations of the same + variable, so long as they are `extern' declarations. */ + if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl)) + goto conflict; + else if (tree match = duplicate_decls (decl, old)) + { + gcc_checking_assert (!hide_value && !hiding); + return match; + } + else + goto conflict; + } else - goto conflict; - } - else - { - conflict: - diagnose_name_conflict (decl, old); - to_val = NULL_TREE; + { + conflict: + diagnose_name_conflict (decl, old); + to_val = NULL_TREE; + } } + else if (hiding) + hide_value = true; done: if (to_val) { - if (level->kind == sk_namespace || to_type == decl || to_val == decl) - add_decl_to_level (level, decl); - else + if (local_overload) { gcc_checking_assert (binding->value && OVL_P (binding->value)); update_local_overload (binding, to_val); } + else + add_decl_to_level (level, decl); if (slot) { @@ -2496,16 +2534,26 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, { STAT_TYPE (*slot) = to_type; STAT_DECL (*slot) = to_val; + STAT_TYPE_HIDDEN_P (*slot) = hide_type; + STAT_DECL_HIDDEN_P (*slot) = hide_value; + } + else if (to_type || hide_value) + { + *slot = stat_hack (to_val, to_type); + STAT_TYPE_HIDDEN_P (*slot) = hide_type; + STAT_DECL_HIDDEN_P (*slot) = hide_value; } - else if (to_type) - *slot = stat_hack (to_val, to_type); else - *slot = to_val; + { + gcc_checking_assert (!hide_type); + *slot = to_val; + } } else { binding->type = to_type; binding->value = to_val; + HIDDEN_TYPE_BINDING_P (binding) = hide_type || hide_value; } } @@ -2854,14 +2902,16 @@ check_local_shadow (tree decl) static void set_decl_context_in_fn (tree ctx, tree decl) { + if (TREE_CODE (decl) == FUNCTION_DECL + || (VAR_P (decl) && DECL_EXTERNAL (decl))) + /* Make sure local externs are marked as such. OMP UDRs really + are nested functions. */ + gcc_checking_assert (DECL_LOCAL_DECL_P (decl) + && (DECL_NAMESPACE_SCOPE_P (decl) + || (TREE_CODE (decl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (decl)))); + if (!DECL_CONTEXT (decl) - /* A local declaration for a function doesn't constitute - nesting. */ - && TREE_CODE (decl) != FUNCTION_DECL - /* A local declaration for an `extern' variable is in the - scope of the current namespace, not the current - function. */ - && !(VAR_P (decl) && DECL_EXTERNAL (decl)) /* When parsing the parameter list of a function declarator, don't set DECL_CONTEXT to an enclosing function. When we push the PARM_DECLs in order to process the function body, @@ -2870,116 +2920,68 @@ set_decl_context_in_fn (tree ctx, tree decl) && current_binding_level->kind == sk_function_parms && current_binding_level->this_entity == NULL)) DECL_CONTEXT (decl) = ctx; - - /* If this is the declaration for a namespace-scope function, - but the declaration itself is in a local scope, mark the - declaration. */ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (decl)) - DECL_LOCAL_FUNCTION_P (decl) = 1; } -/* DECL is a local-scope decl with linkage. SHADOWED is true if the - name is already bound at the current level. - - [basic.link] If there is a visible declaration of an entity with - linkage having the same name and type, ignoring entities declared - outside the innermost enclosing namespace scope, the block scope - declaration declares that same entity and receives the linkage of - the previous declaration. - - Also, make sure that this decl matches any existing external decl - in the enclosing namespace. */ +/* DECL is a local extern decl. Find or create the namespace-scope + decl that it aliases. Also, determines the linkage of DECL. */ static void -set_local_extern_decl_linkage (tree decl, bool shadowed) +push_local_extern_decl_alias (tree decl) { - tree ns_value = decl; /* Unique marker. */ - - if (!shadowed) - { - tree loc_value = innermost_non_namespace_value (DECL_NAME (decl)); - if (!loc_value) - { - ns_value - = find_namespace_value (current_namespace, DECL_NAME (decl)); - loc_value = ns_value; - } - if (loc_value == error_mark_node - /* An ambiguous lookup. */ - || (loc_value && TREE_CODE (loc_value) == TREE_LIST)) - loc_value = NULL_TREE; - - for (ovl_iterator iter (loc_value); iter; ++iter) - if (!iter.hidden_p () - && (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter)) - && decls_match (*iter, decl)) - { - /* The standard only says that the local extern inherits - linkage from the previous decl; in particular, default - args are not shared. Add the decl into a hash table to - make sure only the previous decl in this case is seen - by the middle end. */ - struct cxx_int_tree_map *h; - - /* We inherit the outer decl's linkage. But we're a - different decl. */ - TREE_PUBLIC (decl) = TREE_PUBLIC (*iter); - - if (cp_function_chain->extern_decl_map == NULL) - cp_function_chain->extern_decl_map - = hash_table<cxx_int_tree_map_hasher>::create_ggc (20); - - h = ggc_alloc<cxx_int_tree_map> (); - h->uid = DECL_UID (decl); - h->to = *iter; - cxx_int_tree_map **loc = cp_function_chain->extern_decl_map - ->find_slot (h, INSERT); - *loc = h; - break; - } - } + if (dependent_type_p (TREE_TYPE (decl))) + return; + /* EH specs were not part of the function type prior to c++17, but + we still can't go pushing dependent eh specs into the namespace. */ + if (cxx_dialect < cxx17 + && TREE_CODE (decl) == FUNCTION_DECL + && (value_dependent_expression_p + (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl))))) + return; - if (TREE_PUBLIC (decl)) - { - /* DECL is externally visible. Make sure it matches a matching - decl in the namespace scope. We only really need to check - this when inserting the decl, not when we find an existing - match in the current scope. However, in practice we're - going to be inserting a new decl in the majority of cases -- - who writes multiple extern decls for the same thing in the - same local scope? Doing it here often avoids a duplicate - namespace lookup. */ + gcc_checking_assert (!DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLATE_INFO (decl)); + if (DECL_LANG_SPECIFIC (decl) && DECL_LOCAL_DECL_ALIAS (decl)) + /* We're instantiating a non-dependent local decl, it already + knows the alias. */ + return; - /* Avoid repeating a lookup. */ - if (ns_value == decl) - ns_value = find_namespace_value (current_namespace, DECL_NAME (decl)); + tree alias = NULL_TREE; - if (ns_value == error_mark_node - || (ns_value && TREE_CODE (ns_value) == TREE_LIST)) - ns_value = NULL_TREE; + if (DECL_SIZE (decl) && !TREE_CONSTANT (DECL_SIZE (decl))) + /* Do not let a VLA creep into a namespace. Diagnostic will be + emitted in layout_var_decl later. */ + alias = error_mark_node; + else + { + /* First look for a decl that matches. */ + tree ns = CP_DECL_CONTEXT (decl); + tree binding = find_namespace_value (ns, DECL_NAME (decl)); - for (ovl_iterator iter (ns_value); iter; ++iter) - { - tree other = *iter; - - if (!(TREE_PUBLIC (other) || DECL_EXTERNAL (other))) - ; /* Not externally visible. */ - else if (DECL_EXTERN_C_P (decl) && DECL_EXTERN_C_P (other)) - ; /* Both are extern "C", we'll check via that mechanism. */ - else if (TREE_CODE (other) != TREE_CODE (decl) - || ((VAR_P (decl) || matching_fn_p (other, decl)) - && !comptypes (TREE_TYPE (decl), TREE_TYPE (other), - COMPARE_REDECLARATION))) + if (binding && TREE_CODE (binding) != TREE_LIST) + for (ovl_iterator iter (binding); iter; ++iter) + if (decls_match (*iter, decl)) { - auto_diagnostic_group d; - if (permerror (DECL_SOURCE_LOCATION (decl), - "local external declaration %q#D", decl)) - inform (DECL_SOURCE_LOCATION (other), - "does not match previous declaration %q#D", other); + alias = *iter; break; } + + if (!alias) + { + /* No existing namespace-scope decl. Make one. */ + alias = copy_decl (decl); + + /* This is the real thing. */ + DECL_LOCAL_DECL_P (alias) = false; + + /* Expected default linkage is from the namespace. */ + TREE_PUBLIC (alias) = TREE_PUBLIC (ns); + alias = do_pushdecl_with_scope (alias, NAMESPACE_LEVEL (ns), + /* hiding= */true); } } + + retrofit_lang_decl (decl); + DECL_LOCAL_DECL_ALIAS (decl) = alias; } /* Record DECL as belonging to the current lexical scope. Check for @@ -2992,12 +2994,12 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) says. */ static tree -do_pushdecl (tree decl, bool is_friend) +do_pushdecl (tree decl, bool hiding) { if (decl == error_mark_node) return error_mark_node; - if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl) + if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl && !hiding) set_decl_context_in_fn (current_function_decl, decl); /* The binding level we will be pushing into. During local class @@ -3037,17 +3039,14 @@ do_pushdecl (tree decl, bool is_friend) old = binding->value; } - if (current_function_decl && VAR_OR_FUNCTION_DECL_P (decl) - && DECL_EXTERNAL (decl)) - set_local_extern_decl_linkage (decl, old != NULL_TREE); - if (old == error_mark_node) old = NULL_TREE; for (ovl_iterator iter (old); iter; ++iter) if (iter.using_p ()) ; /* Ignore using decls here. */ - else if (tree match = duplicate_decls (decl, *iter, is_friend)) + else if (tree match + = duplicate_decls (decl, *iter, hiding, iter.hidden_p ())) { if (match == error_mark_node) ; @@ -3055,18 +3054,14 @@ do_pushdecl (tree decl, bool is_friend) /* The IDENTIFIER will have the type referring to the now-smashed TYPE_DECL, because ...? Reset it. */ SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (match)); - else if (iter.hidden_p () && !DECL_HIDDEN_P (match)) + else if (iter.hidden_p () && !hiding) { /* Unhiding a previously hidden decl. */ tree head = iter.reveal_node (old); if (head != old) { - if (!ns) - { - update_local_overload (binding, head); - binding->value = head; - } - else if (STAT_HACK_P (*slot)) + gcc_checking_assert (ns); + if (STAT_HACK_P (*slot)) STAT_DECL (*slot) = head; else *slot = head; @@ -3075,6 +3070,16 @@ do_pushdecl (tree decl, bool is_friend) /* We need to check and register the decl now. */ check_extern_c_conflict (match); } + else if (slot && !hiding + && STAT_HACK_P (*slot) && STAT_DECL_HIDDEN_P (*slot)) + { + /* Unhide the non-function. */ + gcc_checking_assert (old == match); + if (!STAT_TYPE (*slot)) + *slot = match; + else + STAT_DECL (*slot) = match; + } return match; } @@ -3091,7 +3096,7 @@ do_pushdecl (tree decl, bool is_friend) { check_default_args (decl); - if (is_friend) + if (hiding) { if (level->kind != sk_namespace) { @@ -3104,8 +3109,6 @@ do_pushdecl (tree decl, bool is_friend) /* Don't attempt to push it. */ return error_mark_node; } - /* Hide it from ordinary lookup. */ - DECL_ANTICIPATED (decl) = DECL_HIDDEN_FRIEND_P (decl) = true; } } @@ -3115,7 +3118,7 @@ do_pushdecl (tree decl, bool is_friend) if (TREE_CODE (decl) == NAMESPACE_DECL) /* A local namespace alias. */ - set_identifier_type_value (name, NULL_TREE); + set_identifier_type_value_with_scope (name, NULL_TREE, level); if (!binding) binding = create_local_binding (level, name); @@ -3129,7 +3132,7 @@ do_pushdecl (tree decl, bool is_friend) old = MAYBE_STAT_DECL (*slot); } - old = update_binding (level, binding, slot, old, decl, is_friend); + old = update_binding (level, binding, slot, old, decl, hiding); if (old != decl) /* An existing decl matched, use it. */ @@ -3143,10 +3146,7 @@ do_pushdecl (tree decl, bool is_friend) if (TYPE_NAME (type) != decl) set_underlying_type (decl); - if (!ns) - set_identifier_type_value_with_scope (name, decl, level); - else - SET_IDENTIFIER_TYPE_VALUE (name, global_type_node); + set_identifier_type_value_with_scope (name, decl, level); } /* If this is a locally defined typedef in a function that @@ -3155,12 +3155,21 @@ do_pushdecl (tree decl, bool is_friend) if (!instantiating_current_function_p ()) record_locally_defined_typedef (decl); } - else if (VAR_P (decl)) - maybe_register_incomplete_var (decl); + else + { + if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) + maybe_register_incomplete_var (decl); + + if (VAR_OR_FUNCTION_DECL_P (decl)) + { + if (DECL_LOCAL_DECL_P (decl) + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + push_local_extern_decl_alias (decl); - if ((VAR_P (decl) || TREE_CODE (decl) == FUNCTION_DECL) - && DECL_EXTERN_C_P (decl)) - check_extern_c_conflict (decl); + if (DECL_EXTERN_C_P (decl)) + check_extern_c_conflict (decl); + } + } } else add_decl_to_level (level, decl); @@ -3173,10 +3182,10 @@ do_pushdecl (tree decl, bool is_friend) we push it. */ tree -pushdecl (tree x, bool is_friend) +pushdecl (tree x, bool hiding) { bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = do_pushdecl (x, is_friend); + tree ret = do_pushdecl (x, hiding); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } @@ -3238,7 +3247,7 @@ push_local_binding (tree id, tree decl, bool is_using) if (TREE_CODE (decl) == OVERLOAD || is_using) /* We must put the OVERLOAD or using into a TREE_LIST since we cannot use the decl's chain itself. */ - decl = build_tree_list (NULL_TREE, decl); + decl = build_tree_list (id, decl); /* And put DECL on the list of things declared by the current binding level. */ @@ -3692,7 +3701,6 @@ debug (cp_binding_level *ptr) fprintf (stderr, "<nil>\n"); } - static void print_other_binding_stack (cp_binding_level *stack) { @@ -3704,7 +3712,7 @@ print_other_binding_stack (cp_binding_level *stack) } } -void +DEBUG_FUNCTION void print_binding_stack (void) { cp_binding_level *b; @@ -3743,7 +3751,7 @@ identifier_type_value_1 (tree id) return REAL_IDENTIFIER_TYPE_VALUE (id); /* Have to search for it. It must be on the global level, now. Ask lookup_name not to return non-types. */ - id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, 0); + id = lookup_name (id, LOOK_where::BLOCK_NAMESPACE, LOOK_want::TYPE); if (id) return TREE_TYPE (id); return NULL_TREE; @@ -3762,8 +3770,9 @@ identifier_type_value (tree id) } /* Push a definition of struct, union or enum tag named ID. into - binding_level B. DECL is a TYPE_DECL for the type. We assume that - the tag ID is not already defined. */ + binding_level B. DECL is a TYPE_DECL for the type. DECL has + already been pushed into its binding level. This is bookkeeping to + find it easily. */ static void set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b) @@ -3775,20 +3784,25 @@ set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b) /* Shadow the marker, not the real thing, so that the marker gets restored later. */ tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id); - b->type_shadowed - = tree_cons (id, old_type_value, b->type_shadowed); + b->type_shadowed = tree_cons (id, old_type_value, b->type_shadowed); type = decl ? TREE_TYPE (decl) : NULL_TREE; TREE_TYPE (b->type_shadowed) = type; } else { - tree *slot = find_namespace_slot (current_namespace, id, true); gcc_assert (decl); - update_binding (b, NULL, slot, MAYBE_STAT_DECL (*slot), decl, false); + if (CHECKING_P) + { + tree *slot = find_namespace_slot (current_namespace, id); + gcc_checking_assert (slot + && (decl == MAYBE_STAT_TYPE (*slot) + || decl == MAYBE_STAT_DECL (*slot))); + } /* Store marker instead of real type. */ type = global_type_node; } + SET_IDENTIFIER_TYPE_VALUE (id, type); } @@ -3840,12 +3854,13 @@ constructor_name_p (tree name, tree type) closer binding level than LEVEL. */ static tree -do_pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend) +do_pushdecl_with_scope (tree x, cp_binding_level *level, bool hiding = false) { cp_binding_level *b; if (level->kind == sk_class) { + gcc_checking_assert (!hiding); b = class_binding_level; class_binding_level = level; pushdecl_class_level (x); @@ -3858,7 +3873,7 @@ do_pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend) current_function_decl = NULL_TREE; b = current_binding_level; current_binding_level = level; - x = pushdecl (x, is_friend); + x = do_pushdecl (x, hiding); current_binding_level = b; current_function_decl = function_decl; } @@ -3878,7 +3893,7 @@ pushdecl_outermost_localscope (tree x) n->kind != sk_function_parms; n = b->level_chain) b = n; - tree ret = b ? do_pushdecl_with_scope (x, b, false) : error_mark_node; + tree ret = b ? do_pushdecl_with_scope (x, b) : error_mark_node; timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; @@ -3941,7 +3956,7 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, } else if (old.using_p ()) continue; /* This is a using decl. */ - else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn)) + else if (old.hidden_p () && DECL_UNDECLARED_BUILTIN_P (old_fn)) continue; /* This is an anticipated builtin. */ else if (!matching_fn_p (new_fn, old_fn)) continue; /* Parameters do not match. */ @@ -4397,8 +4412,6 @@ get_class_binding (tree name, cp_binding_level *scope) value_binding, type_binding, scope); - /* This is a class-scope binding, not a block-scope binding. */ - LOCAL_BINDING_P (binding) = 0; set_inherited_value_binding_p (binding, value_binding, class_type); } else @@ -4744,7 +4757,7 @@ do_class_using_decl (tree scope, tree name) || scope == error_mark_node) return NULL_TREE; - name_lookup lookup (name, 0); + name_lookup lookup (name); if (!lookup_using_decl (scope, lookup)) return NULL_TREE; @@ -4817,7 +4830,8 @@ set_decl_namespace (tree decl, tree scope, bool friendp) children. */ tree old = NULL_TREE; { - name_lookup lookup (DECL_NAME (decl), LOOKUP_HIDDEN); + name_lookup lookup (DECL_NAME (decl), + LOOK_want::NORMAL | LOOK_want::HIDDEN_FRIEND); if (!lookup.search_qualified (scope, /*usings=*/false)) /* No old declaration at all. */ goto not_found; @@ -4855,8 +4869,15 @@ set_decl_namespace (tree decl, tree scope, bool friendp) /* Since decl is a function, old should contain a function decl. */ if (!OVL_P (old)) - goto not_found; + { + not_found: + /* It didn't work, go back to the explicit scope. */ + DECL_CONTEXT (decl) = FROB_CONTEXT (scope); + error ("%qD should have been declared inside %qD", decl, scope); + return; + } + /* We handle these in check_explicit_instantiation_namespace. */ if (processing_explicit_instantiation) return; @@ -4866,13 +4887,14 @@ set_decl_namespace (tree decl, tree scope, bool friendp) match. But, we'll check later, when we construct the template. */ return; + /* Instantiations or specializations of templates may be declared as friends in any namespace. */ if (friendp && DECL_USE_TEMPLATE (decl)) return; - tree found; - found = NULL_TREE; + tree found = NULL_TREE; + bool hidden_p = false; for (lkp_iterator iter (old); iter; ++iter) { @@ -4888,17 +4910,20 @@ set_decl_namespace (tree decl, tree scope, bool friendp) { if (found) { - /* We found more than one matching declaration. */ + /* We found more than one matching declaration. This + can happen if we have two inline namespace children, + each containing a suitable declaration. */ DECL_CONTEXT (decl) = FROB_CONTEXT (scope); goto ambiguous; } found = ofn; + hidden_p = iter.hidden_p (); } } if (found) { - if (DECL_HIDDEN_FRIEND_P (found)) + if (hidden_p) { pedwarn (DECL_SOURCE_LOCATION (decl), 0, "%qD has not been declared within %qD", decl, scope); @@ -4909,10 +4934,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp) goto found; } - not_found: - /* It didn't work, go back to the explicit scope. */ - DECL_CONTEXT (decl) = FROB_CONTEXT (scope); - error ("%qD should have been declared inside %qD", decl, scope); + goto not_found; } /* Return the namespace where the current declaration is declared. */ @@ -5075,14 +5097,13 @@ do_namespace_alias (tree alias, tree name_space) if appropriate. */ tree -pushdecl_namespace_level (tree x, bool is_friend) +pushdecl_namespace_level (tree x, bool hiding) { cp_binding_level *b = current_binding_level; tree t; bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - t = do_pushdecl_with_scope - (x, NAMESPACE_LEVEL (current_namespace), is_friend); + t = do_pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace), hiding); /* Now, the type_shadowed stack may screw us. Munge it so it does what we want. */ @@ -5129,7 +5150,7 @@ finish_nonmember_using_decl (tree scope, tree name) if (scope == error_mark_node || name == error_mark_node) return; - name_lookup lookup (name, 0); + name_lookup lookup (name); if (!lookup_using_decl (scope, lookup)) return; @@ -5211,43 +5232,26 @@ cp_namespace_decls (tree ns) return NAMESPACE_LEVEL (ns)->names; } -/* Combine prefer_type and namespaces_only into flags. */ - -static int -lookup_flags (int prefer_type, int namespaces_only) -{ - if (namespaces_only) - return LOOKUP_PREFER_NAMESPACES; - if (prefer_type > 1) - return LOOKUP_PREFER_TYPES; - if (prefer_type > 0) - return LOOKUP_PREFER_BOTH; - return 0; -} - /* Given a lookup that returned VAL, use FLAGS to decide if we want to - ignore it or not. Subroutine of lookup_name_real and - lookup_type_scope. */ + ignore it or not. Subroutine of lookup_name_1 and lookup_type_scope. */ static bool -qualify_lookup (tree val, int flags) +qualify_lookup (tree val, LOOK_want want) { if (val == NULL_TREE) return false; - if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL) - return true; - if (flags & LOOKUP_PREFER_TYPES) + + if (bool (want & LOOK_want::TYPE)) { tree target_val = strip_using_decl (val); - if (TREE_CODE (target_val) == TYPE_DECL - || TREE_CODE (target_val) == TEMPLATE_DECL) + + if (TREE_CODE (STRIP_TEMPLATE (target_val)) == TYPE_DECL) return true; } - if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) - return false; - /* Look through lambda things that we shouldn't be able to see. */ - if (!(flags & LOOKUP_HIDDEN) && is_lambda_ignored_entity (val)) - return false; + + if (bool (want & LOOK_want::TYPE_NAMESPACE)) + return TREE_CODE (val) == NAMESPACE_DECL; + return true; } @@ -5273,7 +5277,6 @@ using_directives_contain_std_p (vec<tree, va_gc> *usings) static bool has_using_namespace_std_directive_p () { - /* Look at local using-directives. */ for (cp_binding_level *level = current_binding_level; level; level = level->level_chain) @@ -5995,8 +5998,7 @@ suggest_alternative_in_scoped_enum (tree name, tree scoped_enum) /* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL or a class TYPE). - If PREFER_TYPE is > 0, we only return TYPE_DECLs or namespaces. - If PREFER_TYPE is > 1, we only return TYPE_DECLs. + WANT as for lookup_name_1. Returns a DECL (or OVERLOAD, or BASELINK) representing the declaration found. If no suitable declaration can be found, @@ -6004,17 +6006,13 @@ suggest_alternative_in_scoped_enum (tree name, tree scoped_enum) neither a class-type nor a namespace a diagnostic is issued. */ tree -lookup_qualified_name (tree scope, tree name, int prefer_type, bool complain, - bool find_hidden /*=false*/) +lookup_qualified_name (tree scope, tree name, LOOK_want want, bool complain) { tree t = NULL_TREE; if (TREE_CODE (scope) == NAMESPACE_DECL) { - int flags = lookup_flags (prefer_type, /*namespaces_only*/false); - if (find_hidden) - flags |= LOOKUP_HIDDEN; - name_lookup lookup (name, flags); + name_lookup lookup (name, want); if (qualified_namespace_lookup (scope, &lookup)) t = lookup.value; @@ -6022,7 +6020,8 @@ lookup_qualified_name (tree scope, tree name, int prefer_type, bool complain, else if (cxx_dialect != cxx98 && TREE_CODE (scope) == ENUMERAL_TYPE) t = lookup_enumerator (scope, name); else if (is_class_type (scope, complain)) - t = lookup_member (scope, name, 2, prefer_type, tf_warning_or_error); + t = lookup_member (scope, name, 2, bool (want & LOOK_want::TYPE), + tf_warning_or_error); if (!t) return error_mark_node; @@ -6032,8 +6031,10 @@ lookup_qualified_name (tree scope, tree name, int prefer_type, bool complain, /* Wrapper for the above that takes a string argument. The function name is not at the beginning of the line to keep this wrapper out of etags. */ -tree lookup_qualified_name (tree t, const char *p, int wt, bool c, bool fh) -{ return lookup_qualified_name (t, get_identifier (p), wt, c, fh); } +tree lookup_qualified_name (tree t, const char *p, LOOK_want w, bool c) +{ + return lookup_qualified_name (t, get_identifier (p), w, c); +} /* [namespace.qual] Accepts the NAME to lookup and its qualifying SCOPE. @@ -6050,6 +6051,101 @@ qualified_namespace_lookup (tree scope, name_lookup *lookup) return found; } +/* If DECL is suitably visible to the user, consider its name for + spelling correction. */ + +static void +consider_decl (tree decl, best_match <tree, const char *> &bm, + bool consider_impl_names) +{ + /* Skip compiler-generated variables (e.g. __for_begin/__for_end + within range for). */ + if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl)) + return; + + tree suggestion = DECL_NAME (decl); + if (!suggestion) + return; + + /* Don't suggest names that are for anonymous aggregate types, as + they are an implementation detail generated by the compiler. */ + if (IDENTIFIER_ANON_P (suggestion)) + return; + + const char *suggestion_str = IDENTIFIER_POINTER (suggestion); + + /* Ignore internal names with spaces in them. */ + if (strchr (suggestion_str, ' ')) + return; + + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (!consider_impl_names + && name_reserved_for_implementation_p (suggestion_str)) + return; + + bm.consider (suggestion_str); +} + +/* If DECL is suitably visible to the user, add its name to VEC and + return true. Otherwise return false. */ + +static bool +maybe_add_fuzzy_decl (auto_vec<tree> &vec, tree decl) +{ + /* Skip compiler-generated variables (e.g. __for_begin/__for_end + within range for). */ + if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl)) + return false; + + tree suggestion = DECL_NAME (decl); + if (!suggestion) + return false; + + /* Don't suggest names that are for anonymous aggregate types, as + they are an implementation detail generated by the compiler. */ + if (IDENTIFIER_ANON_P (suggestion)) + return false; + + vec.safe_push (suggestion); + + return true; +} + +/* Examing the namespace binding BINDING, and add at most one instance + of the name, if it contains a visible entity of interest. */ + +void +maybe_add_fuzzy_binding (auto_vec<tree> &vec, tree binding, + lookup_name_fuzzy_kind kind) +{ + tree value = NULL_TREE; + + if (STAT_HACK_P (binding)) + { + if (!STAT_TYPE_HIDDEN_P (binding) + && STAT_TYPE (binding)) + { + if (maybe_add_fuzzy_decl (vec, STAT_TYPE (binding))) + return; + } + else if (!STAT_DECL_HIDDEN_P (binding)) + value = STAT_DECL (binding); + } + else + value = binding; + + value = ovl_skip_hidden (value); + if (value) + { + value = OVL_FIRST (value); + if (kind != FUZZY_LOOKUP_TYPENAME + || TREE_CODE (STRIP_TEMPLATE (value)) == TYPE_DECL) + if (maybe_add_fuzzy_decl (vec, value)) + return; + } +} + /* Helper function for lookup_name_fuzzy. Traverse binding level LVL, looking for good name matches for NAME (and BM). */ @@ -6073,54 +6169,71 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm, with an underscore. */ bool consider_implementation_names = (IDENTIFIER_POINTER (name)[0] == '_'); - for (tree t = lvl->names; t; t = TREE_CHAIN (t)) - { - tree d = t; - - /* OVERLOADs or decls from using declaration are wrapped into - TREE_LIST. */ - if (TREE_CODE (d) == TREE_LIST) - d = OVL_FIRST (TREE_VALUE (d)); - - /* Don't use bindings from implicitly declared functions, - as they were likely misspellings themselves. */ - if (TREE_TYPE (d) == error_mark_node) - continue; - - /* Skip anticipated decls of builtin functions. */ - if (TREE_CODE (d) == FUNCTION_DECL - && fndecl_built_in_p (d) - && DECL_ANTICIPATED (d)) - continue; - - /* Skip compiler-generated variables (e.g. __for_begin/__for_end - within range for). */ - if (TREE_CODE (d) == VAR_DECL - && DECL_ARTIFICIAL (d)) - continue; + if (lvl->kind != sk_namespace) + for (tree t = lvl->names; t; t = TREE_CHAIN (t)) + { + tree d = t; - tree suggestion = DECL_NAME (d); - if (!suggestion) - continue; + /* OVERLOADs or decls from using declaration are wrapped into + TREE_LIST. */ + if (TREE_CODE (d) == TREE_LIST) + d = OVL_FIRST (TREE_VALUE (d)); - /* Don't suggest names that are for anonymous aggregate types, as - they are an implementation detail generated by the compiler. */ - if (IDENTIFIER_ANON_P (suggestion)) - continue; + /* Don't use bindings from implicitly declared functions, + as they were likely misspellings themselves. */ + if (TREE_TYPE (d) == error_mark_node) + continue; - const char *suggestion_str = IDENTIFIER_POINTER (suggestion); + /* If we want a typename, ignore non-types. */ + if (kind == FUZZY_LOOKUP_TYPENAME + && TREE_CODE (STRIP_TEMPLATE (d)) != TYPE_DECL) + continue; - /* Ignore internal names with spaces in them. */ - if (strchr (suggestion_str, ' ')) - continue; + consider_decl (d, bm, consider_implementation_names); + } + else + { + /* We need to iterate over the namespace hash table, in order to + not mention hidden entities. But hash table iteration is + (essentially) unpredictable, our correction-distance measure + is very granular, and we pick the first of equal distances. + Hence, we need to call the distance-measurer in a predictable + order. So, iterate over the namespace hash, inserting + visible names into a vector. Then sort the vector. Then + determine spelling distance. */ + + tree ns = lvl->this_entity; + auto_vec<tree> vec; + + hash_table<named_decl_hash>::iterator end + (DECL_NAMESPACE_BINDINGS (ns)->end ()); + for (hash_table<named_decl_hash>::iterator iter + (DECL_NAMESPACE_BINDINGS (ns)->begin ()); iter != end; ++iter) + maybe_add_fuzzy_binding (vec, *iter, kind); + + vec.qsort ([] (const void *a_, const void *b_) + { + return strcmp (IDENTIFIER_POINTER (*(const tree *)a_), + IDENTIFIER_POINTER (*(const tree *)b_)); + }); + + /* Examine longest to shortest. */ + for (unsigned ix = vec.length (); ix--;) + { + const char *str = IDENTIFIER_POINTER (vec[ix]); - /* Don't suggest names that are reserved for use by the - implementation, unless NAME began with an underscore. */ - if (name_reserved_for_implementation_p (suggestion_str) - && !consider_implementation_names) - continue; + /* Ignore internal names with spaces in them. */ + if (strchr (str, ' ')) + continue; + + /* Don't suggest names that are reserved for use by the + implementation, unless NAME began with an underscore. */ + if (!consider_implementation_names + && name_reserved_for_implementation_p (str)) + continue; - bm.consider (suggestion_str); + bm.consider (str); + } } } @@ -6416,24 +6529,35 @@ innermost_non_namespace_value (tree name) namespace of variables, functions and typedefs. Return a ..._DECL node of some kind representing its definition if there is only one such declaration, or return a TREE_LIST with all the overloaded - definitions if there are many, or return 0 if it is undefined. + definitions if there are many, or return NULL_TREE if it is undefined. Hidden name, either friend declaration or built-in function, are not ignored. - If PREFER_TYPE is > 0, we prefer TYPE_DECLs or namespaces. - If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces). - Otherwise we prefer non-TYPE_DECLs. + WHERE controls which scopes are considered. It is a bit mask of + LOOK_where::BLOCK (look in block scope), LOOK_where::CLASS + (look in class scopes) & LOOK_where::NAMESPACE (look in namespace + scopes). It is an error for no bits to be set. These scopes are + searched from innermost to outermost. + + WANT controls what kind of entity we'd happy with. + LOOK_want::NORMAL for normal lookup (implicit typedefs can be + hidden). LOOK_want::TYPE for only TYPE_DECLS, LOOK_want::NAMESPACE + for only NAMESPACE_DECLS. These two can be bit-ored to find + namespace or type. - If NONCLASS is nonzero, bindings in class scopes are ignored. If - BLOCK_P is false, bindings in block scopes are ignored. */ + WANT can also have LOOK_want::HIDDEN_FRIEND or + LOOK_want::HIDDEN_LAMBDa added to it. */ static tree -lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, - int namespaces_only, int flags) +lookup_name_1 (tree name, LOOK_where where, LOOK_want want) { - cxx_binding *iter; tree val = NULL_TREE; + gcc_checking_assert (unsigned (where) != 0); + /* If we're looking for hidden lambda things, we shouldn't be + looking in namespace scope. */ + gcc_checking_assert (!bool (want & LOOK_want::HIDDEN_LAMBDA) + || !bool (where & LOOK_where::NAMESPACE)); query_oracle (name); /* Conversion operators are handled specially because ordinary @@ -6466,99 +6590,61 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, return NULL_TREE; } - flags |= lookup_flags (prefer_type, namespaces_only); - /* First, look in non-namespace scopes. */ if (current_class_type == NULL_TREE) - nonclass = 1; + /* Maybe avoid searching the binding stack at all. */ + where = LOOK_where (unsigned (where) & ~unsigned (LOOK_where::CLASS)); - if (block_p || !nonclass) - for (iter = outer_binding (name, NULL, !nonclass); - iter; - iter = outer_binding (name, iter, !nonclass)) + if (bool (where & (LOOK_where::BLOCK | LOOK_where::CLASS))) + for (cxx_binding *iter = nullptr; + (iter = outer_binding (name, iter, bool (where & LOOK_where::CLASS)));) { - tree binding; - /* Skip entities we don't want. */ - if (LOCAL_BINDING_P (iter) ? !block_p : nonclass) + if (!bool (where & (LOCAL_BINDING_P (iter) + ? LOOK_where::BLOCK : LOOK_where::CLASS))) continue; /* If this is the kind of thing we're looking for, we're done. */ - if (qualify_lookup (iter->value, flags)) - binding = iter->value; - else if ((flags & LOOKUP_PREFER_TYPES) - && qualify_lookup (iter->type, flags)) - binding = iter->type; - else - binding = NULL_TREE; - - if (binding) + if (iter->value) { - if (TREE_CODE (binding) == TYPE_DECL && DECL_HIDDEN_P (binding)) + tree binding = NULL_TREE; + + if (!(!iter->type && HIDDEN_TYPE_BINDING_P (iter)) + && (bool (want & LOOK_want::HIDDEN_LAMBDA) + || !is_lambda_ignored_entity (iter->value)) + && qualify_lookup (iter->value, want)) + binding = iter->value; + else if (bool (want & LOOK_want::TYPE) + && !HIDDEN_TYPE_BINDING_P (iter) + && iter->type) + binding = iter->type; + + if (binding) { - /* A non namespace-scope binding can only be hidden in the - presence of a local class, due to friend declarations. - - In particular, consider: - - struct C; - void f() { - struct A { - friend struct B; - friend struct C; - void g() { - B* b; // error: B is hidden - C* c; // OK, finds ::C - } - }; - B *b; // error: B is hidden - C *c; // OK, finds ::C - struct B {}; - B *bb; // OK - } - - The standard says that "B" is a local class in "f" - (but not nested within "A") -- but that name lookup - for "B" does not find this declaration until it is - declared directly with "f". - - In particular: - - [class.friend] - - If a friend declaration appears in a local class and - the name specified is an unqualified name, a prior - declaration is looked up without considering scopes - that are outside the innermost enclosing non-class - scope. For a friend function declaration, if there is - no prior declaration, the program is ill-formed. For a - friend class declaration, if there is no prior - declaration, the class that is specified belongs to the - innermost enclosing non-class scope, but if it is - subsequently referenced, its name is not found by name - lookup until a matching declaration is provided in the - innermost enclosing nonclass scope. - - So just keep looking for a non-hidden binding. - */ - gcc_assert (TREE_CODE (binding) == TYPE_DECL); - continue; + /* The saved lookups for an operator record 'nothing + found' as error_mark_node. We need to stop the search + here, but not return the error mark node. */ + if (binding == error_mark_node) + binding = NULL_TREE; + + val = binding; + goto found; } - val = binding; - break; } } /* Now lookup in namespace scopes. */ - if (!val) + if (bool (where & LOOK_where::NAMESPACE)) { - name_lookup lookup (name, flags); + name_lookup lookup (name, want); if (lookup.search_unqualified (current_decl_namespace (), current_binding_level)) val = lookup.value; } + found:; + /* If we have a single function from a using decl, pull it out. */ if (val && TREE_CODE (val) == OVERLOAD && !really_overloaded_fn (val)) val = OVL_FUNCTION (val); @@ -6566,55 +6652,38 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p, return val; } -/* Wrapper for lookup_name_real_1. */ +/* Wrapper for lookup_name_1. */ tree -lookup_name_real (tree name, int prefer_type, int nonclass, bool block_p, - int namespaces_only, int flags) +lookup_name (tree name, LOOK_where where, LOOK_want want) { - tree ret; bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = lookup_name_real_1 (name, prefer_type, nonclass, block_p, - namespaces_only, flags); + tree ret = lookup_name_1 (name, where, want); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } tree -lookup_name_nonclass (tree name) -{ - return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, 0); -} - -tree lookup_name (tree name) { - return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, 0); -} - -tree -lookup_name_prefer_type (tree name, int prefer_type) -{ - return lookup_name_real (name, prefer_type, 0, /*block_p=*/true, 0, 0); + return lookup_name (name, LOOK_where::ALL, LOOK_want::NORMAL); } /* Look up NAME for type used in elaborated name specifier in - the scopes given by SCOPE. SCOPE can be either TS_CURRENT or - TS_WITHIN_ENCLOSING_NON_CLASS. Although not implied by the - name, more scopes are checked if cleanup or template parameter - scope is encountered. + the scopes given by HOW. - Unlike lookup_name_real, we make sure that NAME is actually + Unlike lookup_name_1, we make sure that NAME is actually declared in the desired scope, not from inheritance, nor using directive. For using declaration, there is DR138 still waiting to be resolved. Hidden name coming from an earlier friend - declaration is also returned. + declaration is also returned, and will be made visible unless HOW + is TAG_how::HIDDEN_FRIEND. A TYPE_DECL best matching the NAME is returned. Catching error and issuing diagnostics are caller's responsibility. */ static tree -lookup_type_scope_1 (tree name, tag_scope scope) +lookup_elaborated_type_1 (tree name, TAG_how how) { cp_binding_level *b = current_binding_level; @@ -6629,30 +6698,66 @@ lookup_type_scope_1 (tree name, tag_scope scope) if (!(b->kind == sk_cleanup || b->kind == sk_template_parms || b->kind == sk_function_parms - || (b->kind == sk_class - && scope == ts_within_enclosing_non_class))) + || (b->kind == sk_class && how != TAG_how::CURRENT_ONLY))) return NULL_TREE; /* Check if this is the kind of thing we're looking for. If - SCOPE is TS_CURRENT, also make sure it doesn't come from - base class. For ITER->VALUE, we can simply use - INHERITED_VALUE_BINDING_P. For ITER->TYPE, we have to - use our own check. + HOW is TAG_how::CURRENT_ONLY, also make sure it doesn't + come from base class. For ITER->VALUE, we can simply use + INHERITED_VALUE_BINDING_P. For ITER->TYPE, we have to use + our own check. We check ITER->TYPE before ITER->VALUE in order to handle typedef struct C {} C; correctly. */ + + tree found = NULL_TREE; + bool reveal = false; if (tree type = iter->type) - if (qualify_lookup (type, LOOKUP_PREFER_TYPES) - && (scope != ts_current - || LOCAL_BINDING_P (iter) - || DECL_CONTEXT (type) == iter->scope->this_entity)) - return type; - - if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES) - && (scope != ts_current - || !INHERITED_VALUE_BINDING_P (iter))) - return iter->value; + { + if (qualify_lookup (type, LOOK_want::TYPE) + && (how != TAG_how::CURRENT_ONLY + || LOCAL_BINDING_P (iter) + || DECL_CONTEXT (type) == iter->scope->this_entity)) + { + found = type; + if (how != TAG_how::HIDDEN_FRIEND) + reveal = HIDDEN_TYPE_BINDING_P (iter); + } + } + else + { + if (qualify_lookup (iter->value, LOOK_want::TYPE) + && (how != TAG_how::CURRENT_ONLY + || !INHERITED_VALUE_BINDING_P (iter))) + { + found = iter->value; + if (how != TAG_how::HIDDEN_FRIEND) + reveal = !iter->type && HIDDEN_TYPE_BINDING_P (iter); + } + } + + if (found) + { + if (reveal) + { + /* It is no longer a hidden binding. */ + HIDDEN_TYPE_BINDING_P (iter) = false; + + /* Unanticipate the decl itself. */ + DECL_FRIEND_P (found) = false; + + gcc_checking_assert (TREE_CODE (found) != TEMPLATE_DECL); + + if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found))) + { + tree tmpl = TI_TEMPLATE (ti); + DECL_FRIEND_P (tmpl) = false; + } + } + + return found; + } } /* Now check if we can look in namespace scope. */ @@ -6660,8 +6765,7 @@ lookup_type_scope_1 (tree name, tag_scope scope) if (!(b->kind == sk_cleanup || b->kind == sk_template_parms || b->kind == sk_function_parms - || (b->kind == sk_class - && scope == ts_within_enclosing_non_class))) + || (b->kind == sk_class && how != TAG_how::CURRENT_ONLY))) return NULL_TREE; /* Look in the innermost namespace. */ @@ -6669,58 +6773,78 @@ lookup_type_scope_1 (tree name, tag_scope scope) if (tree *slot = find_namespace_slot (ns, name)) { /* If this is the kind of thing we're looking for, we're done. */ + tree found = NULL_TREE; + bool reveal = false; + if (tree type = MAYBE_STAT_TYPE (*slot)) - if (qualify_lookup (type, LOOKUP_PREFER_TYPES)) - return type; + { + found = type; + if (how != TAG_how::HIDDEN_FRIEND) + { + reveal = STAT_TYPE_HIDDEN_P (*slot); + STAT_TYPE_HIDDEN_P (*slot) = false; + } + } + else if (tree decl = MAYBE_STAT_DECL (*slot)) + { + if (qualify_lookup (decl, LOOK_want::TYPE)) + { + found = decl; + + if (how != TAG_how::HIDDEN_FRIEND && STAT_HACK_P (*slot)) + { + reveal = STAT_DECL_HIDDEN_P (*slot); + if (reveal) + { + if (STAT_TYPE (*slot)) + STAT_DECL_HIDDEN_P (*slot) = false; + else + /* There is no type, just remove the stat + hack. */ + *slot = decl; + } + } + } + } + + if (found) + { + if (reveal) + { + /* Reveal the previously hidden thing. */ + DECL_FRIEND_P (found) = false; - if (tree decl = MAYBE_STAT_DECL (*slot)) - if (qualify_lookup (decl, LOOKUP_PREFER_TYPES)) - return decl; + if (TREE_CODE (found) == TEMPLATE_DECL) + { + tree res = DECL_TEMPLATE_RESULT (found); + if (DECL_LANG_SPECIFIC (res)) + DECL_FRIEND_P (res) = false; + } + else if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found))) + { + tree tmpl = TI_TEMPLATE (ti); + DECL_FRIEND_P (tmpl) = false; + } + } + + return found; + } } return NULL_TREE; } - + /* Wrapper for lookup_type_scope_1. */ tree -lookup_type_scope (tree name, tag_scope scope) +lookup_elaborated_type (tree name, TAG_how how) { - tree ret; bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = lookup_type_scope_1 (name, scope); + tree ret = lookup_elaborated_type_1 (name, how); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } -/* Returns true iff DECL is a block-scope extern declaration of a function - or variable. */ - -bool -is_local_extern (tree decl) -{ - cxx_binding *binding; - - /* For functions, this is easy. */ - if (TREE_CODE (decl) == FUNCTION_DECL) - return DECL_LOCAL_FUNCTION_P (decl); - - if (!VAR_P (decl)) - return false; - if (!current_function_decl) - return false; - - /* For variables, this is not easy. We need to look at the binding stack - for the identifier to see whether the decl we have is a local. */ - for (binding = IDENTIFIER_BINDING (DECL_NAME (decl)); - binding && binding->scope->kind != sk_namespace; - binding = binding->previous) - if (binding->value == decl) - return LOCAL_BINDING_P (binding); - - return false; -} - /* The type TYPE is being declared. If it is a class template, or a specialization of a class template, do any processing required and perform error-checking. If IS_FRIEND is nonzero, this TYPE is @@ -6756,11 +6880,11 @@ maybe_process_template_type_declaration (tree type, int is_friend, if (processing_template_decl) { - /* This may change after the call to - push_template_decl_real, but we want the original value. */ + /* This may change after the call to push_template_decl, but + we want the original value. */ tree name = DECL_NAME (decl); - decl = push_template_decl_real (decl, is_friend); + decl = push_template_decl (decl, is_friend); if (decl == error_mark_node) return error_mark_node; @@ -6812,7 +6936,7 @@ maybe_process_template_type_declaration (tree type, int is_friend, Returns TYPE upon success and ERROR_MARK_NODE otherwise. */ static tree -do_pushtag (tree name, tree type, tag_scope scope) +do_pushtag (tree name, tree type, TAG_how how) { tree decl; @@ -6829,10 +6953,9 @@ do_pushtag (tree name, tree type, tag_scope scope) declaration, these scopes are not scopes from the point of view of the language. */ || (b->kind == sk_template_parms - && (b->explicit_spec_p || scope == ts_global))) + && (b->explicit_spec_p || how == TAG_how::GLOBAL))) b = b->level_chain; - else if (b->kind == sk_class - && scope != ts_current) + else if (b->kind == sk_class && how != TAG_how::CURRENT_ONLY) { b = b->level_chain; if (b->kind == sk_template_parms) @@ -6866,7 +6989,7 @@ do_pushtag (tree name, tree type, tag_scope scope) : TYPE_P (cs) ? cs == current_class_type : cs == current_namespace); - if (scope == ts_current + if (how == TAG_how::CURRENT_ONLY || (cs && TREE_CODE (cs) == FUNCTION_DECL)) context = cs; else if (cs && TYPE_P (cs)) @@ -6886,18 +7009,18 @@ do_pushtag (tree name, tree type, tag_scope scope) tdef = create_implicit_typedef (name, type); DECL_CONTEXT (tdef) = FROB_CONTEXT (context); - if (scope == ts_within_enclosing_non_class) + bool is_friend = how == TAG_how::HIDDEN_FRIEND; + if (is_friend) { + // FIXME: can go away /* This is a friend. Make this TYPE_DECL node hidden from ordinary name lookup. Its corresponding TEMPLATE_DECL - will be marked in push_template_decl_real. */ + will be marked in push_template_decl. */ retrofit_lang_decl (tdef); - DECL_ANTICIPATED (tdef) = 1; DECL_FRIEND_P (tdef) = 1; } - decl = maybe_process_template_type_declaration - (type, scope == ts_within_enclosing_non_class, b); + decl = maybe_process_template_type_declaration (type, is_friend, b); if (decl == error_mark_node) return decl; @@ -6918,7 +7041,8 @@ do_pushtag (tree name, tree type, tag_scope scope) } else if (b->kind != sk_template_parms) { - decl = do_pushdecl_with_scope (decl, b, /*is_friend=*/false); + decl = do_pushdecl_with_scope + (decl, b, /*hiding=*/(how == TAG_how::HIDDEN_FRIEND)); if (decl == error_mark_node) return decl; @@ -6984,11 +7108,10 @@ do_pushtag (tree name, tree type, tag_scope scope) /* Wrapper for do_pushtag. */ tree -pushtag (tree name, tree type, tag_scope scope) +pushtag (tree name, tree type, TAG_how how) { - tree ret; bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = do_pushtag (name, type, scope); + tree ret = do_pushtag (name, type, how); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } @@ -7316,11 +7439,13 @@ finish_using_directive (tree target, tree attribs) /* Pushes X into the global namespace. */ tree -pushdecl_top_level (tree x, bool is_friend) +pushdecl_top_level (tree x) { bool subtime = timevar_cond_start (TV_NAME_LOOKUP); do_push_to_top_level (); - x = pushdecl_namespace_level (x, is_friend); + gcc_checking_assert (!DECL_CONTEXT (x)); + DECL_CONTEXT (x) = FROB_CONTEXT (global_namespace); + x = pushdecl_namespace_level (x); do_pop_from_top_level (); timevar_cond_stop (TV_NAME_LOOKUP, subtime); return x; @@ -7334,7 +7459,9 @@ pushdecl_top_level_and_finish (tree x, tree init) { bool subtime = timevar_cond_start (TV_NAME_LOOKUP); do_push_to_top_level (); - x = pushdecl_namespace_level (x, false); + gcc_checking_assert (!DECL_CONTEXT (x)); + DECL_CONTEXT (x) = FROB_CONTEXT (global_namespace); + x = pushdecl_namespace_level (x); cp_finish_decl (x, init, false, NULL_TREE, 0); do_pop_from_top_level (); timevar_cond_stop (TV_NAME_LOOKUP, subtime); @@ -7376,7 +7503,7 @@ push_namespace (tree name, bool make_inline) tree ns = NULL_TREE; { - name_lookup lookup (name, 0); + name_lookup lookup (name); if (!lookup.search_qualified (current_namespace, /*usings=*/false)) ; else if (TREE_CODE (lookup.value) == TREE_LIST) @@ -7619,23 +7746,38 @@ op_unqualified_lookup (tree fnname) cp_binding_level *l = binding->scope; while (l && !l->this_entity) l = l->level_chain; + if (l && uses_template_parms (l->this_entity)) /* Don't preserve decls from an uninstantiated template, wait until that template is instantiated. */ return NULL_TREE; } + tree fns = lookup_name (fnname); - if (fns && fns == get_global_binding (fnname)) - /* The instantiation can find these. */ - return NULL_TREE; + if (!fns) + /* Remember we found nothing! */ + return error_mark_node; + + tree d = is_overloaded_fn (fns) ? get_first_fn (fns) : fns; + if (DECL_CLASS_SCOPE_P (d)) + /* We don't need to remember class-scope functions or declarations, + normal unqualified lookup will find them again. */ + fns = NULL_TREE; + return fns; } /* E is an expression representing an operation with dependent type, so we don't know yet whether it will use the built-in meaning of the operator or a - function. Remember declarations of that operator in scope. */ + function. Remember declarations of that operator in scope. + + We then inject a fake binding of that lookup into the + instantiation's parameter scope. This approach fails if the user + has different using declarations or directives in different local + binding of the current function from whence we need to do lookups + (we'll cache what we see on the first lookup). */ -const char *const op_bind_attrname = "operator bindings"; +static const char *const op_bind_attrname = "operator bindings"; void maybe_save_operator_binding (tree e) @@ -7643,13 +7785,14 @@ maybe_save_operator_binding (tree e) /* This is only useful in a generic lambda. */ if (!processing_template_decl) return; + tree cfn = current_function_decl; if (!cfn) return; - /* Let's only do this for generic lambdas for now, we could do it for all - function templates if we wanted to. */ - if (!current_lambda_expr()) + /* Do this for lambdas and code that will emit a CMI. In a module's + GMF we don't yet know whether there will be a CMI. */ + if (!current_lambda_expr ()) return; tree fnname = ovl_op_identifier (false, TREE_CODE (e)); @@ -7657,32 +7800,22 @@ maybe_save_operator_binding (tree e) return; tree attributes = DECL_ATTRIBUTES (cfn); - tree attr = lookup_attribute (op_bind_attrname, attributes); - tree bindings = NULL_TREE; - tree fns = NULL_TREE; - if (attr) + tree op_attr = lookup_attribute (op_bind_attrname, attributes); + if (!op_attr) { - bindings = TREE_VALUE (attr); - if (tree elt = purpose_member (fnname, bindings)) - fns = TREE_VALUE (elt); + op_attr = tree_cons (get_identifier (op_bind_attrname), + NULL_TREE, attributes); + DECL_ATTRIBUTES (cfn) = op_attr; } - if (!fns && (fns = op_unqualified_lookup (fnname))) + tree op_bind = purpose_member (fnname, TREE_VALUE (op_attr)); + if (!op_bind) { - tree d = is_overloaded_fn (fns) ? get_first_fn (fns) : fns; - if (DECL_P (d) && DECL_CLASS_SCOPE_P (d)) - /* We don't need to remember class-scope functions or declarations, - normal unqualified lookup will find them again. */ - return; + tree fns = op_unqualified_lookup (fnname); - bindings = tree_cons (fnname, fns, bindings); - if (attr) - TREE_VALUE (attr) = bindings; - else - DECL_ATTRIBUTES (cfn) - = tree_cons (get_identifier (op_bind_attrname), - bindings, - attributes); + /* Always record, so we don't keep looking for this + operator. */ + TREE_VALUE (op_attr) = tree_cons (fnname, fns, TREE_VALUE (op_attr)); } } @@ -7705,11 +7838,11 @@ push_operator_bindings () if (tree attr = lookup_attribute (op_bind_attrname, DECL_ATTRIBUTES (decl1))) for (tree binds = TREE_VALUE (attr); binds; binds = TREE_CHAIN (binds)) - { - tree name = TREE_PURPOSE (binds); - tree val = TREE_VALUE (binds); - push_local_binding (name, val, /*using*/true); - } + if (tree val = TREE_VALUE (binds)) + { + tree name = TREE_PURPOSE (binds); + push_local_binding (name, val, /*using*/true); + } } #include "gt-cp-name-lookup.h" diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 9a18593..d63ff10 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -47,12 +47,8 @@ struct GTY(()) binding_entry_s { extern void binding_table_foreach (binding_table, bt_foreach_proc, void *); extern binding_entry binding_table_find (binding_table, tree); -/* Datatype that represents binding established by a declaration between - a name and a C++ entity. */ -typedef struct cxx_binding cxx_binding; - /* The datatype used to implement C++ scope. */ -typedef struct cp_binding_level cp_binding_level; +struct cp_binding_level; /* Nonzero if this binding is for a local scope, as opposed to a class or namespace scope. */ @@ -62,6 +58,14 @@ typedef struct cp_binding_level cp_binding_level; currently being defined. */ #define INHERITED_VALUE_BINDING_P(NODE) ((NODE)->value_is_inherited) +/* The IMPLICIT_TYPEDEF is hidden from ordinary name lookup (it was + injected via a local class's friend decl). The typdef may be in the + VALUE or the TYPE slot. We do not get the situation where the + value and type slots are both filled and both hidden. */ +#define HIDDEN_TYPE_BINDING_P(NODE) ((NODE)->type_is_hidden) + +/* Datatype that represents binding established by a declaration between + a name and a C++ entity. */ struct GTY(()) cxx_binding { /* Link to chain together various bindings for this name. */ cxx_binding *previous; @@ -71,8 +75,10 @@ struct GTY(()) cxx_binding { tree type; /* The scope at which this binding was made. */ cp_binding_level *scope; - unsigned value_is_inherited : 1; - unsigned is_local : 1; + + bool value_is_inherited : 1; + bool is_local : 1; + bool type_is_hidden : 1; }; /* Datatype used to temporarily save C++ bindings (for implicit @@ -125,23 +131,6 @@ enum scope_kind { sk_omp /* An OpenMP structured block. */ }; -/* The scope where the class/struct/union/enum tag applies. */ -enum tag_scope { - ts_current = 0, /* Current scope only. This is for the - class-key identifier; - case mentioned in [basic.lookup.elab]/2, - or the class/enum definition - class-key identifier { ... }; */ - ts_global = 1, /* All scopes. This is the 3.4.1 - [basic.lookup.unqual] lookup mentioned - in [basic.lookup.elab]/2. */ - ts_within_enclosing_non_class = 2, /* Search within enclosing non-class - only, for friend class lookup - according to [namespace.memdef]/3 - and [class.friend]/9. */ - ts_lambda = 3 /* Declaring a lambda closure. */ -}; - struct GTY(()) cp_class_binding { cxx_binding *base; /* The bound name. */ @@ -278,21 +267,83 @@ extern void push_binding_level (cp_binding_level *); extern bool handle_namespace_attrs (tree, tree); extern void pushlevel_class (void); extern void poplevel_class (void); -extern tree lookup_name_prefer_type (tree, int); -extern tree lookup_name_real (tree, int, int, bool, int, int); -extern tree lookup_type_scope (tree, tag_scope); + +/* What kind of scopes name lookup looks in. An enum class so we + don't accidentally mix integers. */ +enum class LOOK_where +{ + BLOCK = 1 << 0, /* Consider block scopes. */ + CLASS = 1 << 1, /* Consider class scopes. */ + NAMESPACE = 1 << 2, /* Consider namespace scopes. */ + + ALL = BLOCK | CLASS | NAMESPACE, + BLOCK_NAMESPACE = BLOCK | NAMESPACE, + CLASS_NAMESPACE = CLASS | NAMESPACE, +}; +constexpr LOOK_where operator| (LOOK_where a, LOOK_where b) +{ + return LOOK_where (unsigned (a) | unsigned (b)); +} +constexpr LOOK_where operator& (LOOK_where a, LOOK_where b) +{ + return LOOK_where (unsigned (a) & unsigned (b)); +} + +enum class LOOK_want +{ + NORMAL = 0, /* Normal lookup -- non-types can hide implicit types. */ + TYPE = 1 << 1, /* We only want TYPE_DECLS. */ + NAMESPACE = 1 << 2, /* We only want NAMESPACE_DECLS. */ + + HIDDEN_FRIEND = 1 << 3, /* See hidden friends. */ + HIDDEN_LAMBDA = 1 << 4, /* See lambda-ignored entities. */ + + TYPE_NAMESPACE = TYPE | NAMESPACE, /* Either NAMESPACE or TYPE. */ +}; +constexpr LOOK_want operator| (LOOK_want a, LOOK_want b) +{ + return LOOK_want (unsigned (a) | unsigned (b)); +} +constexpr LOOK_want operator& (LOOK_want a, LOOK_want b) +{ + return LOOK_want (unsigned (a) & unsigned (b)); +} + +extern tree lookup_name (tree, LOOK_where, LOOK_want = LOOK_want::NORMAL); +/* Also declared in c-family/c-common.h. */ +extern tree lookup_name (tree name); +inline tree lookup_name (tree name, LOOK_want want) +{ + return lookup_name (name, LOOK_where::ALL, want); +} + +enum class TAG_how +{ + CURRENT_ONLY = 0, // Look and insert only in current scope + + GLOBAL = 1, // Unqualified lookup, innermost-non-class insertion + + INNERMOST_NON_CLASS = 2, // Look and insert only into + // innermost-non-class + + HIDDEN_FRIEND = 3, // As INNERMOST_NON_CLASS, but hide it +}; + +extern tree lookup_elaborated_type (tree, TAG_how); extern tree get_namespace_binding (tree ns, tree id); extern void set_global_binding (tree decl); inline tree get_global_binding (tree id) { return get_namespace_binding (NULL_TREE, id); } -extern tree lookup_qualified_name (tree, tree, int = 0, bool = true, /*hidden*/bool = false); -extern tree lookup_qualified_name (tree t, const char *p, int = 0, bool = true, bool = false); -extern tree lookup_name_nonclass (tree); -extern bool is_local_extern (tree); +extern tree lookup_qualified_name (tree scope, tree name, + LOOK_want = LOOK_want::NORMAL, + bool = true); +extern tree lookup_qualified_name (tree scope, const char *name, + LOOK_want = LOOK_want::NORMAL, + bool = true); extern bool pushdecl_class_level (tree); -extern tree pushdecl_namespace_level (tree, bool); +extern tree pushdecl_namespace_level (tree, bool hiding = false); extern bool push_class_level_binding (tree, tree); extern tree get_local_decls (); extern int function_parm_depth (void); @@ -318,11 +369,11 @@ extern void cp_emit_debug_info_for_using (tree, tree); extern void finish_nonmember_using_decl (tree scope, tree name); extern void finish_using_directive (tree target, tree attribs); -extern tree pushdecl (tree, bool is_friend = false); +extern tree pushdecl (tree, bool hiding = false); extern tree pushdecl_outermost_localscope (tree); -extern tree pushdecl_top_level (tree, bool is_friend = false); +extern tree pushdecl_top_level (tree); extern tree pushdecl_top_level_and_finish (tree, tree); -extern tree pushtag (tree, tree, tag_scope); +extern tree pushtag (tree, tree, TAG_how = TAG_how::CURRENT_ONLY); extern int push_namespace (tree, bool make_inline = false); extern void pop_namespace (void); extern void push_nested_namespace (tree); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index abdcd7f..00621d6 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -244,19 +244,13 @@ populate_clone_array (tree fn, tree *fns) fns[1] = NULL_TREE; fns[2] = NULL_TREE; - tree ctx = DECL_CONTEXT (fn); - FOR_EACH_CLONE (clone, fn) if (DECL_NAME (clone) == complete_dtor_identifier || DECL_NAME (clone) == complete_ctor_identifier) fns[1] = clone; else if (DECL_NAME (clone) == base_dtor_identifier || DECL_NAME (clone) == base_ctor_identifier) - { - /* We don't need to define the base variants for a final class. */ - if (!CLASSTYPE_FINAL (ctx)) - fns[0] = clone; - } + fns[0] = clone; else if (DECL_NAME (clone) == deleting_dtor_identifier) fns[2] = clone; else @@ -481,7 +475,7 @@ maybe_clone_body (tree fn) /* Remember if we can't have multiple clones for some reason. We need to check this before we remap local static initializers in clone_body. */ - if (!tree_versionable_function_p (fn) && fns[0] && fns[1]) + if (!tree_versionable_function_p (fn)) need_alias = true; /* We know that any clones immediately follow FN in the TYPE_FIELDS diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 528b41b..592ce95 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -212,7 +212,7 @@ static int cp_lexer_saving_tokens static cp_token *cp_lexer_token_at (cp_lexer *, cp_token_position); static void cp_lexer_get_preprocessor_token - (cp_lexer *, cp_token *); + (unsigned, cp_token *); static inline cp_token *cp_lexer_peek_token (cp_lexer *); static cp_token *cp_lexer_peek_nth_token @@ -613,12 +613,8 @@ debug (cp_parser *ptr) static cp_lexer * cp_lexer_alloc (void) { - cp_lexer *lexer; - - c_common_no_more_pch (); - /* Allocate the memory. */ - lexer = ggc_cleared_alloc<cp_lexer> (); + cp_lexer *lexer = ggc_cleared_alloc<cp_lexer> (); /* Initially we are not debugging. */ lexer->debugging_p = false; @@ -631,31 +627,30 @@ cp_lexer_alloc (void) return lexer; } - /* Create a new main C++ lexer, the lexer that gets tokens from the preprocessor. */ static cp_lexer * cp_lexer_new_main (void) { - cp_lexer *lexer; cp_token token; /* It's possible that parsing the first pragma will load a PCH file, which is a GC collection point. So we have to do that before allocating any memory. */ + cp_lexer_get_preprocessor_token (0, &token); cp_parser_initial_pragma (&token); + c_common_no_more_pch (); - lexer = cp_lexer_alloc (); - + cp_lexer *lexer = cp_lexer_alloc (); /* Put the first token in the buffer. */ - lexer->buffer->quick_push (token); + cp_token *tok = lexer->buffer->quick_push (token); /* Get the remaining tokens from the preprocessor. */ - while (token.type != CPP_EOF) + while (tok->type != CPP_EOF) { - cp_lexer_get_preprocessor_token (lexer, &token); - vec_safe_push (lexer->buffer, token); + tok = vec_safe_push (lexer->buffer, cp_token ()); + cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok); } lexer->next_token = lexer->buffer->address (); @@ -698,7 +693,8 @@ cp_lexer_new_from_tokens (cp_token_cache *cache) /* Initially we are not debugging. */ lexer->debugging_p = false; - gcc_assert (!lexer->next_token->purged_p); + gcc_assert (!lexer->next_token->purged_p + && !lexer->last_token->purged_p); return lexer; } @@ -779,14 +775,25 @@ cp_lexer_previous_token (cp_lexer *lexer) /* Same as above, but return NULL when the lexer doesn't own the token buffer or if the next_token is at the start of the token - vector. */ + vector or if all previous tokens are purged. */ static cp_token * cp_lexer_safe_previous_token (cp_lexer *lexer) { - if (lexer->buffer) - if (lexer->next_token != lexer->buffer->address ()) - return cp_lexer_previous_token (lexer); + if (lexer->buffer + && lexer->next_token != lexer->buffer->address ()) + { + cp_token_position tp = cp_lexer_previous_token_position (lexer); + + /* Skip past purged tokens. */ + while (tp->purged_p) + { + if (tp == lexer->buffer->address ()) + return NULL; + tp--; + } + return cp_lexer_token_at (lexer, tp); + } return NULL; } @@ -815,14 +822,14 @@ cp_lexer_saving_tokens (const cp_lexer* lexer) processed strings. */ static void -cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token) +cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token) { static int is_extern_c = 0; /* Get a new token from the preprocessor. */ token->type = c_lex_with_flags (&token->u.value, &token->location, &token->flags, - lexer == NULL ? 0 : C_LEX_STRING_NO_JOIN); + flags); token->keyword = RID_MAX; token->purged_p = false; token->error_reported = false; @@ -1125,8 +1132,6 @@ cp_lexer_consume_token (cp_lexer* lexer) { cp_token *token = lexer->next_token; - gcc_assert (!lexer->in_pragma || token->type != CPP_PRAGMA_EOL); - do { gcc_assert (token->type != CPP_EOF); @@ -2029,7 +2034,7 @@ pop_unparsed_function_queues (cp_parser *parser) /* Constructors and destructors. */ static cp_parser *cp_parser_new - (void); + (cp_lexer *); /* Routines to parse various constructs. @@ -2940,22 +2945,23 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, bool added_matching_location = false; if (missing_token_desc != RT_NONE) - { - /* Potentially supply a fix-it hint, suggesting to add the - missing token immediately after the *previous* token. - This may move the primary location within richloc. */ - enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc); - location_t prev_token_loc - = cp_lexer_previous_token (parser->lexer)->location; - maybe_suggest_missing_token_insertion (&richloc, ttype, prev_token_loc); - - /* If matching_location != UNKNOWN_LOCATION, highlight it. - Attempt to consolidate diagnostics by printing it as a - secondary range within the main diagnostic. */ - if (matching_location != UNKNOWN_LOCATION) - added_matching_location - = richloc.add_location_if_nearby (matching_location); - } + if (cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer)) + { + /* Potentially supply a fix-it hint, suggesting to add the + missing token immediately after the *previous* token. + This may move the primary location within richloc. */ + enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc); + location_t prev_token_loc = prev_token->location; + maybe_suggest_missing_token_insertion (&richloc, ttype, + prev_token_loc); + + /* If matching_location != UNKNOWN_LOCATION, highlight it. + Attempt to consolidate diagnostics by printing it as a + secondary range within the main diagnostic. */ + if (matching_location != UNKNOWN_LOCATION) + added_matching_location + = richloc.add_location_if_nearby (matching_location); + } /* If we were parsing a string-literal and there is an unknown name token right after, then check to see if that could also have been @@ -2963,19 +2969,19 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, standard string literal constants defined in header files. If there is one, then add that as an hint to the error message. */ name_hint h; - cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer); - if (prev_token && cp_parser_is_string_literal (prev_token) - && token->type == CPP_NAME) - { - tree name = token->u.value; - const char *token_name = IDENTIFIER_POINTER (name); - 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)); - } + if (token->type == CPP_NAME) + if (cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer)) + if (cp_parser_is_string_literal (prev_token)) + { + tree name = token->u.value; + const char *token_name = IDENTIFIER_POINTER (name); + 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)); + } /* Actually emit the error. */ c_parse_error (gmsgid, @@ -3693,6 +3699,11 @@ cp_parser_skip_to_closing_parenthesis_1 (cp_parser *parser, condop_depth--; break; + case CPP_PRAGMA: + /* We fell into a pragma. Skip it, and continue. */ + cp_parser_skip_to_pragma_eol (parser, recovering ? token : nullptr); + continue; + default: break; } @@ -3784,6 +3795,13 @@ cp_parser_skip_to_end_of_statement (cp_parser* parser) ++nesting_depth; break; + case CPP_PRAGMA: + /* We fell into a pragma. Skip it, and continue or return. */ + cp_parser_skip_to_pragma_eol (parser, token); + if (!nesting_depth) + return; + continue; + default: break; } @@ -3859,6 +3877,13 @@ cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser) nesting_depth++; break; + case CPP_PRAGMA: + /* Skip it, and continue or return. */ + cp_parser_skip_to_pragma_eol (parser, token); + if (!nesting_depth) + return; + continue; + default: break; } @@ -3915,21 +3940,31 @@ cp_parser_skip_to_closing_brace (cp_parser *parser) /* Consume tokens until we reach the end of the pragma. The PRAGMA_TOK parameter is the PRAGMA token, allowing us to purge the entire pragma - sequence. */ + sequence. PRAGMA_TOK can be NULL, if we're speculatively scanning + forwards (not error recovery). */ static void cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok) { cp_token *token; - parser->lexer->in_pragma = false; - do - token = cp_lexer_consume_token (parser->lexer); - while (token->type != CPP_PRAGMA_EOL && token->type != CPP_EOF); + { + /* The preprocessor makes sure that a PRAGMA_EOL token appears + before an EOF token, even when the EOF is on the pragma line. + We should never get here without being inside a deferred + pragma. */ + gcc_checking_assert (cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)); + token = cp_lexer_consume_token (parser->lexer); + } + while (token->type != CPP_PRAGMA_EOL); - /* Ensure that the pragma is not parsed again. */ - cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); + if (pragma_tok) + { + /* Ensure that the pragma is not parsed again. */ + cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); + parser->lexer->in_pragma = false; + } } /* Require pragma end of line, resyncing with it as necessary. The @@ -3997,22 +4032,14 @@ cp_parser_make_indirect_declarator (enum tree_code code, tree class_type, /* Create a new C++ parser. */ static cp_parser * -cp_parser_new (void) +cp_parser_new (cp_lexer *lexer) { - cp_parser *parser; - cp_lexer *lexer; - unsigned i; - - /* cp_lexer_new_main is called before doing GC allocation because - cp_lexer_new_main might load a PCH file. */ - lexer = cp_lexer_new_main (); - /* Initialize the binops_by_token so that we can get the tree directly from the token. */ - for (i = 0; i < sizeof (binops) / sizeof (binops[0]); i++) + for (unsigned i = 0; i < sizeof (binops) / sizeof (binops[0]); i++) binops_by_token[binops[i].token_type] = binops[i]; - parser = ggc_cleared_alloc<cp_parser> (); + cp_parser *parser = ggc_cleared_alloc<cp_parser> (); parser->lexer = lexer; parser->context = cp_parser_context_new (NULL); @@ -4590,7 +4617,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) if (i14 && ext) { tree cxlit = lookup_qualified_name (std_node, "complex_literals", - 0, false); + LOOK_want::NORMAL, false); if (cxlit == error_mark_node) { /* No <complex>, so pedwarn and use GNU semantics. */ @@ -4728,14 +4755,19 @@ cp_parser_translation_unit (cp_parser* parser) /* Remember where the base of the declarator obstack lies. */ void *declarator_obstack_base = obstack_next_free (&declarator_obstack); + push_deferring_access_checks (flag_access_control + ? dk_no_deferred : dk_no_check); + bool implicit_extern_c = false; + /* Parse until EOF. */ for (;;) { cp_token *token = cp_lexer_peek_token (parser->lexer); /* If we're entering or exiting a region that's implicitly - extern "C", modify the lang context appropriately. */ + extern "C", modify the lang context appropriately. This is + so horrible. Please die. */ if (implicit_extern_c != cp_lexer_peek_token (parser->lexer)->implicit_extern_c) { @@ -7435,7 +7467,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, if ((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn)) || DECL_FUNCTION_MEMBER_P (fn) - || DECL_LOCAL_FUNCTION_P (fn)) + || DECL_LOCAL_DECL_P (fn)) { do_adl_p = false; break; @@ -8979,7 +9011,9 @@ cp_parser_new_type_id (cp_parser* parser, tree *nelts) if (*nelts == error_mark_node) *nelts = integer_one_node; - if (outer_declarator) + if (*nelts == NULL_TREE) + /* Leave [] in the declarator. */; + else if (outer_declarator) outer_declarator->declarator = declarator->declarator; else new_declarator = NULL; @@ -9040,6 +9074,7 @@ static cp_declarator * cp_parser_direct_new_declarator (cp_parser* parser) { cp_declarator *declarator = NULL; + bool first_p = true; while (true) { @@ -9050,14 +9085,17 @@ cp_parser_direct_new_declarator (cp_parser* parser) cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE); token = cp_lexer_peek_token (parser->lexer); - expression = cp_parser_expression (parser); + if (token->type == CPP_CLOSE_SQUARE && first_p) + expression = NULL_TREE; + else + expression = cp_parser_expression (parser); /* The standard requires that the expression have integral type. DR 74 adds enumeration types. We believe that the real intent is that these expressions be handled like the expression in a `switch' condition, which also allows classes with a single conversion to integral or enumeration type. */ - if (!processing_template_decl) + if (expression && !processing_template_decl) { expression = build_expr_type_conversion (WANT_INT | WANT_ENUM, @@ -9082,6 +9120,7 @@ cp_parser_direct_new_declarator (cp_parser* parser) bounds. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE)) break; + first_p = false; } return declarator; @@ -12607,6 +12646,64 @@ do_range_for_auto_deduction (tree decl, tree range_expr) } } +/* Warns when the loop variable should be changed to a reference type to + avoid unnecessary copying. I.e., from + + for (const auto x : range) + + where range returns a reference, to + + for (const auto &x : range) + + if this version doesn't make a copy. DECL is the RANGE_DECL; EXPR is the + *__for_begin expression. + This function is never called when processing_template_decl is on. */ + +static void +warn_for_range_copy (tree decl, tree expr) +{ + if (!warn_range_loop_construct + || decl == error_mark_node) + return; + + location_t loc = DECL_SOURCE_LOCATION (decl); + tree type = TREE_TYPE (decl); + + if (from_macro_expansion_at (loc)) + return; + + if (TYPE_REF_P (type)) + { + /* TODO: Implement reference warnings. */ + return; + } + else if (!CP_TYPE_CONST_P (type)) + return; + + /* Since small trivially copyable types are cheap to copy, we suppress the + warning for them. 64B is a common size of a cache line. */ + if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST + || (tree_to_uhwi (TYPE_SIZE_UNIT (type)) <= 64 + && trivially_copyable_p (type))) + return; + + tree rtype = cp_build_reference_type (type, /*rval*/false); + /* If we could initialize the reference directly, it wouldn't involve any + copies. */ + if (!ref_conv_binds_directly_p (rtype, expr)) + return; + + auto_diagnostic_group d; + if (warning_at (loc, OPT_Wrange_loop_construct, + "loop variable %qD creates a copy from type %qT", + decl, type)) + { + gcc_rich_location richloc (loc); + richloc.add_fixit_insert_before ("&"); + inform (&richloc, "use reference type to prevent copying"); + } +} + /* Converts a range-based for-statement into a normal for-statement, as per the definition. @@ -12617,7 +12714,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr) { auto &&__range = RANGE_EXPR; - for (auto __begin = BEGIN_EXPR, end = END_EXPR; + for (auto __begin = BEGIN_EXPR, __end = END_EXPR; __begin != __end; ++__begin) { @@ -12717,14 +12814,16 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, cp_maybe_mangle_decomp (range_decl, decomp_first_name, decomp_cnt); /* The declaration is initialized with *__begin inside the loop body. */ - cp_finish_decl (range_decl, - build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, - tf_warning_or_error), + tree deref_begin = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR, + tf_warning_or_error); + cp_finish_decl (range_decl, deref_begin, /*is_constant_init*/false, NULL_TREE, LOOKUP_ONLYCONVERTING); if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl)) cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt); + warn_for_range_copy (range_decl, deref_begin); + return statement; } @@ -13383,11 +13482,7 @@ cp_parser_declaration_seq_opt (cp_parser* parser) static void cp_parser_declaration (cp_parser* parser) { - cp_token token1; - cp_token token2; int saved_pedantic; - void *p; - tree attributes = NULL_TREE; /* Check for the `__extension__' keyword. */ if (cp_parser_extension_opt (parser, &saved_pedantic)) @@ -13401,35 +13496,33 @@ cp_parser_declaration (cp_parser* parser) } /* Try to figure out what kind of declaration is present. */ - token1 = *cp_lexer_peek_token (parser->lexer); + cp_token *token1 = cp_lexer_peek_token (parser->lexer); + cp_token *token2 = NULL; - if (token1.type != CPP_EOF) - token2 = *cp_lexer_peek_nth_token (parser->lexer, 2); - else - { - token2.type = CPP_EOF; - token2.keyword = RID_MAX; - } + if (token1->type != CPP_EOF) + token2 = cp_lexer_peek_nth_token (parser->lexer, 2); /* Get the high-water mark for the DECLARATOR_OBSTACK. */ - p = obstack_alloc (&declarator_obstack, 0); + void *p = obstack_alloc (&declarator_obstack, 0); + + tree attributes = NULL_TREE; /* If the next token is `extern' and the following token is a string literal, then we have a linkage specification. */ - if (token1.keyword == RID_EXTERN - && cp_parser_is_pure_string_literal (&token2)) + if (token1->keyword == RID_EXTERN + && cp_parser_is_pure_string_literal (token2)) cp_parser_linkage_specification (parser); /* If the next token is `template', then we have either a template declaration, an explicit instantiation, or an explicit specialization. */ - else if (token1.keyword == RID_TEMPLATE) + else if (token1->keyword == RID_TEMPLATE) { /* `template <>' indicates a template specialization. */ - if (token2.type == CPP_LESS + if (token2->type == CPP_LESS && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER) cp_parser_explicit_specialization (parser); /* `template <' indicates a template declaration. */ - else if (token2.type == CPP_LESS) + else if (token2->type == CPP_LESS) cp_parser_template_declaration (parser, /*member_p=*/false); /* Anything else must be an explicit instantiation. */ else @@ -13437,40 +13530,40 @@ cp_parser_declaration (cp_parser* parser) } /* If the next token is `export', then we have a template declaration. */ - else if (token1.keyword == RID_EXPORT) + else if (token1->keyword == RID_EXPORT) cp_parser_template_declaration (parser, /*member_p=*/false); /* If the next token is `extern', 'static' or 'inline' and the one after that is `template', we have a GNU extended explicit instantiation directive. */ else if (cp_parser_allow_gnu_extensions_p (parser) - && (token1.keyword == RID_EXTERN - || token1.keyword == RID_STATIC - || token1.keyword == RID_INLINE) - && token2.keyword == RID_TEMPLATE) + && token2->keyword == RID_TEMPLATE + && (token1->keyword == RID_EXTERN + || token1->keyword == RID_STATIC + || token1->keyword == RID_INLINE)) cp_parser_explicit_instantiation (parser); /* If the next token is `namespace', check for a named or unnamed namespace definition. */ - else if (token1.keyword == RID_NAMESPACE + else if (token1->keyword == RID_NAMESPACE && (/* A named namespace definition. */ - (token2.type == CPP_NAME + (token2->type == CPP_NAME && (cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_EQ)) - || (token2.type == CPP_OPEN_SQUARE + || (token2->type == CPP_OPEN_SQUARE && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_OPEN_SQUARE) /* An unnamed namespace definition. */ - || token2.type == CPP_OPEN_BRACE - || token2.keyword == RID_ATTRIBUTE)) + || token2->type == CPP_OPEN_BRACE + || token2->keyword == RID_ATTRIBUTE)) cp_parser_namespace_definition (parser); /* An inline (associated) namespace definition. */ - else if (token1.keyword == RID_INLINE - && token2.keyword == RID_NAMESPACE) + else if (token2->keyword == RID_NAMESPACE + && token1->keyword == RID_INLINE) cp_parser_namespace_definition (parser); /* Objective-C++ declaration/definition. */ - else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword)) + else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1->keyword)) cp_parser_objc_declaration (parser, NULL_TREE); else if (c_dialect_objc () - && token1.keyword == RID_ATTRIBUTE + && token1->keyword == RID_ATTRIBUTE && cp_parser_objc_valid_prefix_attributes (parser, &attributes)) cp_parser_objc_declaration (parser, attributes); /* At this point we may have a template declared by a concept @@ -13539,7 +13632,6 @@ static void cp_parser_block_declaration (cp_parser *parser, bool statement_p) { - cp_token *token1; int saved_pedantic; /* Check for the `__extension__' keyword. */ @@ -13555,7 +13647,7 @@ cp_parser_block_declaration (cp_parser *parser, /* Peek at the next token to figure out which kind of declaration is present. */ - token1 = cp_lexer_peek_token (parser->lexer); + cp_token *token1 = cp_lexer_peek_token (parser->lexer); /* If the next keyword is `asm', we have an asm-definition. */ if (token1->keyword == RID_ASM) @@ -14064,12 +14156,9 @@ cp_parser_decomposition_declaration (cp_parser *parser, if (decl != error_mark_node) { - int flags = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit) - ? LOOKUP_CONSTINIT : 0); cp_maybe_mangle_decomp (decl, prev, v.length ()); cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE, - (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT) - | flags); + (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)); cp_finish_decomp (decl, prev, v.length ()); } } @@ -15386,7 +15475,20 @@ cp_parser_mem_initializer (cp_parser* parser) in_base_initializer = 0; - return member ? build_tree_list (member, expression_list) : error_mark_node; + if (!member) + return error_mark_node; + tree node = build_tree_list (member, expression_list); + + /* We can't attach the source location of this initializer directly to + the list node, so we instead attach it to a dummy EMPTY_CLASS_EXPR + within the TREE_TYPE of the list node. */ + location_t loc + = make_location (token->location, token->location, parser->lexer); + tree dummy = build0 (EMPTY_CLASS_EXPR, NULL_TREE); + SET_EXPR_LOCATION (dummy, loc); + TREE_TYPE (node) = dummy; + + return node; } /* Parse a mem-initializer-id. @@ -17615,7 +17717,6 @@ cp_parser_explicit_instantiation (cp_parser* parser) static void cp_parser_explicit_specialization (cp_parser* parser) { - bool need_lang_pop; cp_token *token = cp_lexer_peek_token (parser->lexer); /* Look for the `template' keyword. */ @@ -17626,52 +17727,54 @@ cp_parser_explicit_specialization (cp_parser* parser) cp_parser_require (parser, CPP_GREATER, RT_GREATER); /* We have processed another parameter list. */ ++parser->num_template_parameter_lists; + /* [temp] A template ... explicit specialization ... shall not have C linkage. */ - if (current_lang_name == lang_name_c) + bool need_lang_pop = current_lang_name == lang_name_c; + if (need_lang_pop) { error_at (token->location, "template specialization with C linkage"); maybe_show_extern_c_location (); + /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); need_lang_pop = true; } - else - need_lang_pop = false; - /* Let the front end know that we are beginning a specialization. */ - if (!begin_specialization ()) - { - end_specialization (); - return; - } - /* If the next keyword is `template', we need to figure out whether - or not we're looking a template-declaration. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + /* Let the front end know that we are beginning a specialization. */ + if (begin_specialization ()) { - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS - && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER) - cp_parser_template_declaration_after_export (parser, - /*member_p=*/false); + /* If the next keyword is `template', we need to figure out + whether or not we're looking a template-declaration. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS + && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER) + cp_parser_template_declaration_after_export (parser, + /*member_p=*/false); + else + cp_parser_explicit_specialization (parser); + } else - cp_parser_explicit_specialization (parser); + /* Parse the dependent declaration. */ + cp_parser_single_declaration (parser, + /*checks=*/NULL, + /*member_p=*/false, + /*explicit_specialization_p=*/true, + /*friend_p=*/NULL); } - else - /* Parse the dependent declaration. */ - cp_parser_single_declaration (parser, - /*checks=*/NULL, - /*member_p=*/false, - /*explicit_specialization_p=*/true, - /*friend_p=*/NULL); + /* We're done with the specialization. */ end_specialization (); + /* For the erroneous case of a template with C linkage, we pushed an implicit C++ linkage scope; exit that scope now. */ if (need_lang_pop) pop_lang_context (); + /* We're done with this parameter list. */ --parser->num_template_parameter_lists; } @@ -18801,7 +18904,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, if (!template_p) cp_parser_parse_tentatively (parser); /* The `template' keyword must follow a nested-name-specifier. */ - else if (!nested_name_specifier) + else if (!nested_name_specifier && !globalscope) { cp_parser_error (parser, "%<template%> must follow a nested-" "name-specifier"); @@ -19014,21 +19117,20 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, definition of a new type; a new type can only be declared in a declaration context. */ - tag_scope ts; - bool template_p; + TAG_how how; if (is_friend) /* Friends have special name lookup rules. */ - ts = ts_within_enclosing_non_class; + how = TAG_how::HIDDEN_FRIEND; else if (is_declaration && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) /* This is a `class-key identifier ;' */ - ts = ts_current; + how = TAG_how::CURRENT_ONLY; else - ts = ts_global; + how = TAG_how::GLOBAL; - template_p = + bool template_p = (template_parm_lists_apply && (cp_parser_next_token_starts_class_definition_p (parser) || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))); @@ -19041,7 +19143,8 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, token->location, /*declarator=*/NULL)) return error_mark_node; - type = xref_tag (tag_type, identifier, ts, template_p); + + type = xref_tag (tag_type, identifier, how, template_p); } } @@ -19412,7 +19515,12 @@ cp_parser_enum_specifier (cp_parser* parser) "ISO C++ forbids empty unnamed enum"); } else - cp_parser_enumerator_list (parser, type); + { + /* We've seen a '{' so we know we're in an enum-specifier. + Commit to any tentative parse to get syntax errors. */ + cp_parser_commit_to_tentative_parse (parser); + cp_parser_enumerator_list (parser, type); + } /* Consume the final '}'. */ braces.require_close (parser); @@ -20967,8 +21075,6 @@ cp_parser_init_declarator (cp_parser* parser, declarations. */ if (!member_p && decl && decl != error_mark_node && !range_for_decl_p) { - int cf = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit) - ? LOOKUP_CONSTINIT : 0); cp_finish_decl (decl, initializer, !is_non_constant_init, asm_specification, @@ -20977,7 +21083,7 @@ cp_parser_init_declarator (cp_parser* parser, `explicit' constructor is OK. Otherwise, an `explicit' constructor cannot be used. */ ((is_direct_init || !is_initialized) - ? LOOKUP_NORMAL : LOOKUP_IMPLICIT) | cf); + ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)); } else if ((cxx_dialect != cxx98) && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL) @@ -21682,8 +21788,14 @@ cp_parser_direct_declarator (cp_parser* parser, templates, assume S::p to name a type. Otherwise, don't. */ tree decl - = cp_parser_lookup_name_simple (parser, unqualified_name, - token->location); + = cp_parser_lookup_name (parser, unqualified_name, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/false, + /*ambiguous_decls=*/NULL, + token->location); + if (!is_overloaded_fn (decl) /* Allow template<typename T> @@ -23932,10 +24044,6 @@ cp_parser_class_specifier_1 (cp_parser* parser) = parser->in_unbraced_linkage_specification_p; parser->in_unbraced_linkage_specification_p = false; - // Associate constraints with the type. - if (flag_concepts) - type = associate_classtype_constraints (type); - /* Start the class. */ if (nested_name_specifier_p) { @@ -24662,10 +24770,10 @@ cp_parser_class_head (cp_parser* parser, /* If the class was unnamed, create a dummy name. */ if (!id) id = make_anon_name (); - tag_scope tag_scope = (parser->in_type_id_in_expr_p - ? ts_within_enclosing_non_class - : ts_current); - type = xref_tag (class_key, id, tag_scope, + TAG_how how = (parser->in_type_id_in_expr_p + ? TAG_how::INNERMOST_NON_CLASS + : TAG_how::CURRENT_ONLY); + type = xref_tag (class_key, id, how, parser->num_template_parameter_lists); } @@ -24703,6 +24811,10 @@ cp_parser_class_head (cp_parser* parser, fixup_attribute_variants (type); } + /* Associate constraints with the type. */ + if (flag_concepts) + type = associate_classtype_constraints (type); + /* We will have entered the scope containing the class; the names of base classes should be looked up in that context. For example: @@ -28169,21 +28281,17 @@ cp_parser_nested_requirement (cp_parser *parser) /* Support Functions */ -/* Return the appropriate prefer_type argument for lookup_name_real based on - tag_type and template_mem_access. */ +/* Return the appropriate prefer_type argument for lookup_name based on + tag_type. */ -static inline int -prefer_type_arg (tag_types tag_type, bool template_mem_access = false) +static inline LOOK_want +prefer_type_arg (tag_types tag_type) { - /* DR 141: When looking in the current enclosing context for a template-name - after -> or ., only consider class templates. */ - if (template_mem_access) - return 2; switch (tag_type) { - case none_type: return 0; // No preference. - case scope_type: return 1; // Type or namespace. - default: return 2; // Type only. + case none_type: return LOOK_want::NORMAL; // No preference. + case scope_type: return LOOK_want::TYPE_NAMESPACE; // Type or namespace. + default: return LOOK_want::TYPE; // Type only. } } @@ -28407,7 +28515,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, decl = lookup_member (object_type, name, /*protect=*/0, - prefer_type_arg (tag_type), + /*prefer_type=*/tag_type != none_type, tf_warning_or_error); else decl = NULL_TREE; @@ -28415,17 +28523,20 @@ cp_parser_lookup_name (cp_parser *parser, tree name, if (!decl) /* Look it up in the enclosing context. DR 141: When looking for a template-name after -> or ., only consider class templates. */ - decl = lookup_name_real (name, prefer_type_arg (tag_type, is_template), - /*nonclass=*/0, - /*block_p=*/true, is_namespace, 0); + decl = lookup_name (name, is_namespace ? LOOK_want::NAMESPACE + /* DR 141: When looking in the + current enclosing context for a + template-name after -> or ., only + consider class templates. */ + : is_template ? LOOK_want::TYPE + : prefer_type_arg (tag_type)); parser->object_scope = object_type; parser->qualifying_scope = NULL_TREE; } else { - decl = lookup_name_real (name, prefer_type_arg (tag_type), - /*nonclass=*/0, - /*block_p=*/true, is_namespace, 0); + decl = lookup_name (name, is_namespace ? LOOK_want::NAMESPACE + : prefer_type_arg (tag_type)); parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; } @@ -32935,44 +33046,42 @@ cp_parser_objc_method_prototype_list (cp_parser* parser) static void cp_parser_objc_method_definition_list (cp_parser* parser) { - cp_token *token = cp_lexer_peek_token (parser->lexer); - - while (token->keyword != RID_AT_END && token->type != CPP_EOF) + for (;;) { - tree meth; + cp_token *token = cp_lexer_peek_token (parser->lexer); - if (token->type == CPP_PLUS || token->type == CPP_MINUS) + if (token->keyword == RID_AT_END) { - cp_token *ptk; - tree sig, attribute; - bool is_class_method; - if (token->type == CPP_PLUS) - is_class_method = true; - else - is_class_method = false; + cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */ + break; + } + else if (token->type == CPP_EOF) + { + cp_parser_error (parser, "expected %<@end%>"); + break; + } + else if (token->type == CPP_PLUS || token->type == CPP_MINUS) + { + bool is_class_method = token->type == CPP_PLUS; + push_deferring_access_checks (dk_deferred); - sig = cp_parser_objc_method_signature (parser, &attribute); + tree attribute; + tree sig = cp_parser_objc_method_signature (parser, &attribute); if (sig == error_mark_node) + cp_parser_skip_to_end_of_block_or_statement (parser); + else { - cp_parser_skip_to_end_of_block_or_statement (parser); - token = cp_lexer_peek_token (parser->lexer); - continue; - } - objc_start_method_definition (is_class_method, sig, attribute, - NULL_TREE); + objc_start_method_definition (is_class_method, sig, + attribute, NULL_TREE); - /* For historical reasons, we accept an optional semicolon. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) - cp_lexer_consume_token (parser->lexer); + /* For historical reasons, we accept an optional semicolon. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); - ptk = cp_lexer_peek_token (parser->lexer); - if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS - || ptk->type == CPP_EOF || ptk->keyword == RID_AT_END)) - { perform_deferred_access_checks (tf_warning_or_error); stop_deferring_access_checks (); - meth = cp_parser_function_definition_after_declarator (parser, - false); + tree meth + = cp_parser_function_definition_after_declarator (parser, false); pop_deferring_access_checks (); objc_finish_method_definition (meth); } @@ -32992,15 +33101,8 @@ cp_parser_objc_method_definition_list (cp_parser* parser) else /* Allow for interspersed non-ObjC++ code. */ cp_parser_objc_interstitial_code (parser); - - token = cp_lexer_peek_token (parser->lexer); } - if (token->type != CPP_EOF) - cp_lexer_consume_token (parser->lexer); /* Eat '@end'. */ - else - cp_parser_error (parser, "expected %<@end%>"); - objc_finish_implementation (); } @@ -35365,12 +35467,21 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location) t = cp_parser_assignment_expression (parser); + if (t != error_mark_node) + { + t = fold_non_dependent_expr (t); + if (!value_dependent_expression_p (t) + && (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || !tree_fits_shwi_p (t) + || tree_int_cst_sgn (t) == -1)) + error_at (location, "expected constant integer expression with " + "valid sync-hint value"); + } if (t == error_mark_node || !parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); - check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint", location); c = build_omp_clause (location, OMP_CLAUSE_HINT); @@ -38192,13 +38303,10 @@ cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok, bool *if_p) if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); - - clauses = cp_parser_omp_all_clauses (parser, - OMP_CRITICAL_CLAUSE_MASK, - "#pragma omp critical", pragma_tok); } - else - cp_parser_require_pragma_eol (parser, pragma_tok); + + clauses = cp_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK, + "#pragma omp critical", pragma_tok); stmt = cp_parser_omp_structured_block (parser, if_p); return c_finish_omp_critical (input_location, stmt, name, clauses); @@ -39253,7 +39361,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, TREE_VEC_ELT (incrv, i) = incr; if (orig_init) { - orig_inits.safe_grow_cleared (i + 1); + orig_inits.safe_grow_cleared (i + 1, true); orig_inits[i] = orig_init; } if (orig_decl) @@ -41068,6 +41176,10 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) } if (!found_in_scope) + /* This seems to ignore the existence of cleanup scopes? + What is the meaning for local extern decls? The local + extern is in this scope, but it is referring to a decl that + is namespace scope. */ for (tree d = current_binding_level->names; d; d = TREE_CHAIN (d)) if (d == decl) { @@ -41097,6 +41209,16 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) { tree id; + if (DECL_LOCAL_DECL_P (decl)) + /* We need to mark the aliased decl, as that is the entity + that is being referred to. This won't work for + dependent variables, but it didn't work for them before + DECL_LOCAL_DECL_P was a thing either. But then + dependent local extern variable decls are as rare as + hen's teeth. */ + if (auto alias = DECL_LOCAL_DECL_ALIAS (decl)) + decl = alias; + if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK) id = get_identifier ("omp declare target link"); else @@ -41472,11 +41594,8 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, } /* Store away all pragma tokens. */ - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - parser->omp_declare_simd->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); @@ -42528,7 +42647,8 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, if (current_function_decl) { block_scope = true; - DECL_CONTEXT (fndecl) = global_namespace; + DECL_CONTEXT (fndecl) = current_function_decl; + DECL_LOCAL_DECL_P (fndecl) = true; if (!processing_template_decl) pushdecl (fndecl); } @@ -42536,11 +42656,8 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, { if (cp == NULL) { - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - goto fail; cp = cp_token_cache_new (first_token, cp_lexer_peek_nth_token (parser->lexer, 2)); @@ -42555,7 +42672,9 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, else { DECL_CONTEXT (fndecl) = current_namespace; - pushdecl (fndecl); + tree d = pushdecl (fndecl); + /* We should never meet a matched duplicate decl. */ + gcc_checking_assert (d == error_mark_node || d == fndecl); } if (!block_scope) start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); @@ -42566,16 +42685,9 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, cp_parser_push_lexer_for_tokens (parser, cp); parser->lexer->in_pragma = true; } - if (!cp_parser_omp_declare_reduction_exprs (fndecl, parser)) - { - if (!block_scope) - finish_function (/*inline_p=*/false); - else - DECL_CONTEXT (fndecl) = current_function_decl; - if (cp) - cp_parser_pop_lexer (parser); - goto fail; - } + + bool ok = cp_parser_omp_declare_reduction_exprs (fndecl, parser); + if (cp) cp_parser_pop_lexer (parser); if (!block_scope) @@ -42583,6 +42695,14 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, else { DECL_CONTEXT (fndecl) = current_function_decl; + if (DECL_TEMPLATE_INFO (fndecl)) + DECL_CONTEXT (DECL_TI_TEMPLATE (fndecl)) = current_function_decl; + } + if (!ok) + goto fail; + + if (block_scope) + { block = finish_omp_structured_block (block); if (TREE_CODE (block) == BIND_EXPR) DECL_SAVED_TREE (fndecl) = BIND_EXPR_BODY (block); @@ -42591,6 +42711,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, if (processing_template_decl) add_decl_expr (fndecl); } + cp_check_omp_declare_reduction (fndecl); if (cp == NULL && types.length () > 1) cp = cp_token_cache_new (first_token, @@ -43019,11 +43140,8 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, else /* No optional '( name )'. */ { /* Store away all pragma tokens. */ - while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) - && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF)) + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) cp_lexer_consume_token (parser->lexer); - if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) - parser->oacc_routine->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); struct cp_token_cache *cp = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); @@ -43587,31 +43705,28 @@ static GTY (()) cp_parser *the_parser; static void cp_parser_initial_pragma (cp_token *first_token) { - tree name = NULL; - - cp_lexer_get_preprocessor_token (NULL, first_token); if (cp_parser_pragma_kind (first_token) != PRAGMA_GCC_PCH_PREPROCESS) - { - c_common_no_more_pch (); - return; - } + return; + + cp_lexer_get_preprocessor_token (0, first_token); - cp_lexer_get_preprocessor_token (NULL, first_token); + tree name = NULL; if (first_token->type == CPP_STRING) { name = first_token->u.value; - cp_lexer_get_preprocessor_token (NULL, first_token); - if (first_token->type != CPP_PRAGMA_EOL) - error_at (first_token->location, - "junk at end of %<#pragma GCC pch_preprocess%>"); + cp_lexer_get_preprocessor_token (0, first_token); } - else - error_at (first_token->location, "expected string literal"); /* Skip to the end of the pragma. */ - while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF) - cp_lexer_get_preprocessor_token (NULL, first_token); + if (first_token->type != CPP_PRAGMA_EOL) + { + error_at (first_token->location, + "malformed %<#pragma GCC pch_preprocess%>"); + do + cp_lexer_get_preprocessor_token (0, first_token); + while (first_token->type != CPP_PRAGMA_EOL); + } /* Now actually load the PCH file. */ if (name) @@ -43620,7 +43735,7 @@ cp_parser_initial_pragma (cp_token *first_token) /* Read one more token to return to our caller. We have to do this after reading the PCH file in, since its pointers have to be live. */ - cp_lexer_get_preprocessor_token (NULL, first_token); + cp_lexer_get_preprocessor_token (0, first_token); } /* Parse a pragma GCC ivdep. */ @@ -44019,7 +44134,7 @@ pragma_lex (tree *value, location_t *loc) if (loc) *loc = tok->location; - if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF) + if (ret == CPP_PRAGMA_EOL) ret = CPP_EOF; else if (ret == CPP_STRING) *value = cp_parser_string_literal (the_parser, false, false); @@ -44045,12 +44160,15 @@ c_parse_file (void) if (already_called) fatal_error (input_location, - "inter-module optimizations not implemented for C++"); + "multi-source compilation not implemented for C++"); already_called = true; - the_parser = cp_parser_new (); - push_deferring_access_checks (flag_access_control - ? dk_no_deferred : dk_no_check); + /* cp_lexer_new_main is called before doing any GC allocation + because tokenization might load a PCH file. */ + cp_lexer *lexer = cp_lexer_new_main (); + + the_parser = cp_parser_new (lexer); + cp_parser_translation_unit (the_parser); class_decl_loc_t::diag_mismatched_tags (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 61f2273..555dc47 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -227,6 +227,7 @@ static tree canonicalize_expr_argument (tree, tsubst_flags_t); static tree make_argument_pack (tree); static void register_parameter_specializations (tree, tree); static tree enclosing_instantiation_of (tree tctx); +static void instantiate_body (tree pattern, tree args, tree d, bool nested); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -586,13 +587,23 @@ add_to_template_args (tree args, tree extra_args) (EXTRA_ARGS) levels are added. This function is used to combine the template arguments from a partial instantiation with the template arguments used to attain the full instantiation from the - partial instantiation. */ + partial instantiation. + + If ARGS is a TEMPLATE_DECL, use its parameters as args. */ tree add_outermost_template_args (tree args, tree extra_args) { tree new_args; + if (!args) + return extra_args; + if (TREE_CODE (args) == TEMPLATE_DECL) + { + tree ti = get_template_info (DECL_TEMPLATE_RESULT (args)); + args = TI_ARGS (ti); + } + /* If there are more levels of EXTRA_ARGS than there are ARGS, something very fishy is going on. */ gcc_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args)); @@ -1624,7 +1635,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, for the specialization, we want this to look as if there were no definition, and vice versa. */ DECL_INITIAL (fn) = NULL_TREE; - duplicate_decls (spec, fn, is_friend); + duplicate_decls (spec, fn, /*hiding=*/is_friend); /* The call to duplicate_decls will have applied [temp.expl.spec]: @@ -1651,7 +1662,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, } else if (DECL_TEMPLATE_SPECIALIZATION (fn)) { - tree dd = duplicate_decls (spec, fn, is_friend); + tree dd = duplicate_decls (spec, fn, /*hiding=*/is_friend); if (dd == error_mark_node) /* We've already complained in duplicate_decls. */ return error_mark_node; @@ -1666,7 +1677,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, } } else if (fn) - return duplicate_decls (spec, fn, is_friend); + return duplicate_decls (spec, fn, /*hiding=*/is_friend); /* A specialization must be declared in the same namespace as the template it is specializing. */ @@ -2977,6 +2988,7 @@ check_explicit_specialization (tree declarator, tree tmpl = NULL_TREE; tree targs = NULL_TREE; bool was_template_id = (TREE_CODE (declarator) == TEMPLATE_ID_EXPR); + bool found_hidden = false; /* Make sure that the declarator is a TEMPLATE_ID_EXPR. */ if (!was_template_id) @@ -2995,13 +3007,17 @@ check_explicit_specialization (tree declarator, /* Find the namespace binding, using the declaration context. */ fns = lookup_qualified_name (CP_DECL_CONTEXT (decl), dname, - false, true); + LOOK_want::NORMAL, true); if (fns == error_mark_node) - /* If lookup fails, look for a friend declaration so we can - give a better diagnostic. */ - fns = lookup_qualified_name (CP_DECL_CONTEXT (decl), dname, - /*type*/false, /*complain*/true, - /*hidden*/true); + { + /* If lookup fails, look for a friend declaration so we can + give a better diagnostic. */ + fns = (lookup_qualified_name + (CP_DECL_CONTEXT (decl), dname, + LOOK_want::NORMAL | LOOK_want::HIDDEN_FRIEND, + /*complain*/true)); + found_hidden = true; + } if (fns == error_mark_node || !is_overloaded_fn (fns)) { @@ -3110,8 +3126,7 @@ check_explicit_specialization (tree declarator, return error_mark_node; else { - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_HIDDEN_FRIEND_P (tmpl)) + if (found_hidden && TREE_CODE (decl) == FUNCTION_DECL) { auto_diagnostic_group d; if (pedwarn (DECL_SOURCE_LOCATION (decl), 0, @@ -3120,8 +3135,9 @@ check_explicit_specialization (tree declarator, inform (DECL_SOURCE_LOCATION (tmpl), "friend declaration here"); } - else if (!ctype && !is_friend - && CP_DECL_CONTEXT (decl) == current_namespace) + + if (!ctype && !is_friend + && CP_DECL_CONTEXT (decl) == current_namespace) check_unqualified_spec_or_inst (tmpl, DECL_SOURCE_LOCATION (decl)); tree gen_tmpl = most_general_template (tmpl); @@ -4420,7 +4436,7 @@ canonical_type_parameter (tree type) gcc_assert (TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM); if (vec_safe_length (canonical_template_parms) <= (unsigned) idx) - vec_safe_grow_cleared (canonical_template_parms, idx + 1); + vec_safe_grow_cleared (canonical_template_parms, idx + 1, true); for (tree list = (*canonical_template_parms)[idx]; list; list = TREE_CHAIN (list)) @@ -4453,6 +4469,7 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, type); TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl); TREE_READONLY (decl) = TREE_READONLY (orig_decl); + DECL_VIRTUAL_P (decl) = DECL_VIRTUAL_P (orig_decl); DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); @@ -4691,29 +4708,37 @@ end_template_decl (void) current_template_parms = TREE_CHAIN (current_template_parms); } -/* Takes a TREE_LIST representing a template parameter and convert it - into an argument suitable to be passed to the type substitution - functions. Note that If the TREE_LIST contains an error_mark - node, the returned argument is error_mark_node. */ +/* Takes a TEMPLATE_PARM_P or DECL_TEMPLATE_PARM_P node or a TREE_LIST + thereof, and converts it into an argument suitable to be passed to + the type substitution functions. Note that if the TREE_LIST contains + an error_mark node, the returned argument is error_mark_node. */ tree template_parm_to_arg (tree t) { + if (!t) + return NULL_TREE; - if (t == NULL_TREE - || TREE_CODE (t) != TREE_LIST) - return t; + if (TREE_CODE (t) == TREE_LIST) + t = TREE_VALUE (t); - if (error_operand_p (TREE_VALUE (t))) + if (error_operand_p (t)) return error_mark_node; - t = TREE_VALUE (t); - - if (TREE_CODE (t) == TYPE_DECL - || TREE_CODE (t) == TEMPLATE_DECL) + if (DECL_P (t) && DECL_TEMPLATE_PARM_P (t)) { - t = TREE_TYPE (t); + if (TREE_CODE (t) == TYPE_DECL + || TREE_CODE (t) == TEMPLATE_DECL) + t = TREE_TYPE (t); + else + t = DECL_INITIAL (t); + } + gcc_assert (TEMPLATE_PARM_P (t)); + + if (TREE_CODE (t) == TEMPLATE_TYPE_PARM + || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM) + { if (TEMPLATE_TYPE_PARAMETER_PACK (t)) { /* Turn this argument into a TYPE_ARGUMENT_PACK @@ -4730,8 +4755,6 @@ template_parm_to_arg (tree t) } else { - t = DECL_INITIAL (t); - if (TEMPLATE_PARM_PARAMETER_PACK (t)) { /* Turn this argument into a NONTYPE_ARGUMENT_PACK @@ -5405,7 +5428,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary, class template. */ if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL - || (TREE_CODE (decl) == FUNCTION_DECL && DECL_LOCAL_FUNCTION_P (decl))) + || (TREE_CODE (decl) == FUNCTION_DECL && DECL_LOCAL_DECL_P (decl))) /* You can't have a function template declaration in a local scope, nor you can you define a member of a class template in a local scope. */ @@ -5481,14 +5504,15 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary, /* Don't complain about an enclosing partial specialization. */ && parm_level == parms - && TREE_CODE (decl) == TYPE_DECL + && (TREE_CODE (decl) == TYPE_DECL || VAR_P (decl)) && i < ntparms - 1 && template_parameter_pack_p (TREE_VALUE (parm)) /* A fixed parameter pack will be partially instantiated into a fixed length list. */ && !fixed_parameter_pack_p (TREE_VALUE (parm))) { - /* A primary class template can only have one + /* A primary class template, primary variable template + (DR 2032), or alias template can only have one parameter pack, at the end of the template parameter list. */ @@ -5649,7 +5673,7 @@ template_parm_outer_level (tree t, void *data) If IS_FRIEND is true, DECL is a friend declaration. */ tree -push_template_decl_real (tree decl, bool is_friend) +push_template_decl (tree decl, bool is_friend) { tree tmpl; tree args; @@ -5674,8 +5698,10 @@ push_template_decl_real (tree decl, bool is_friend) && DECL_TEMPLATE_SPECIALIZATION (decl) && TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (decl)))); - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl)) - is_friend = true; + /* No surprising friend functions. */ + gcc_checking_assert (is_friend + || !(TREE_CODE (decl) == FUNCTION_DECL + && DECL_FRIEND_P (decl))); if (is_friend) /* For a friend, we want the context of the friend, not @@ -5986,7 +6012,6 @@ push_template_decl_real (tree decl, bool is_friend) gcc_checking_assert (DECL_TEMPLATE_RESULT (tmpl) == decl); - if (new_template_p) { /* Push template declarations for global functions and types. @@ -5997,16 +6022,13 @@ push_template_decl_real (tree decl, bool is_friend) if (!ctx && !(is_friend && template_class_depth (current_class_type) > 0)) { - tmpl = pushdecl_namespace_level (tmpl, is_friend); - if (tmpl == error_mark_node) - return error_mark_node; - /* Hide template friend classes that haven't been declared yet. */ if (is_friend && TREE_CODE (decl) == TYPE_DECL) - { - DECL_ANTICIPATED (tmpl) = 1; - DECL_FRIEND_P (tmpl) = 1; - } + DECL_FRIEND_P (tmpl) = 1; + + tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend); + if (tmpl == error_mark_node) + return error_mark_node; } } else @@ -6059,7 +6081,9 @@ push_template_decl_real (tree decl, bool is_friend) { if (is_primary) retrofit_lang_decl (decl); - if (DECL_LANG_SPECIFIC (decl)) + if (DECL_LANG_SPECIFIC (decl) + && !(VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl))) DECL_TEMPLATE_INFO (decl) = info; } @@ -6075,12 +6099,6 @@ push_template_decl_real (tree decl, bool is_friend) return DECL_TEMPLATE_RESULT (tmpl); } -tree -push_template_decl (tree decl) -{ - return push_template_decl_real (decl, false); -} - /* FN is an inheriting constructor that inherits from the constructor template INHERITED; turn FN into a constructor template with a matching template header. */ @@ -6908,7 +6926,9 @@ template_parm_object_p (const_tree t) } /* Subroutine of convert_nontype_argument, to check whether EXPR, as an - argument for TYPE, points to an unsuitable object. */ + argument for TYPE, points to an unsuitable object. + + Also adjust the type of the index in C++20 array subobject references. */ static bool invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) @@ -6936,6 +6956,19 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) { tree decl = TREE_OPERAND (expr, 0); + if (cxx_dialect >= cxx20) + while (TREE_CODE (decl) == COMPONENT_REF + || TREE_CODE (decl) == ARRAY_REF) + { + tree &op = TREE_OPERAND (decl, 1); + if (TREE_CODE (decl) == ARRAY_REF + && TREE_CODE (op) == INTEGER_CST) + /* Canonicalize array offsets to ptrdiff_t; how they were + written doesn't matter for subobject identity. */ + op = fold_convert (ptrdiff_type_node, op); + decl = TREE_OPERAND (decl, 0); + } + if (!VAR_P (decl)) { if (complain & tf_error) @@ -6977,9 +7010,10 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain) decl); return true; } - else if (!same_type_ignoring_top_level_qualifiers_p - (strip_array_types (TREE_TYPE (type)), - strip_array_types (TREE_TYPE (decl)))) + else if (cxx_dialect < cxx20 + && !(same_type_ignoring_top_level_qualifiers_p + (strip_array_types (TREE_TYPE (type)), + strip_array_types (TREE_TYPE (decl))))) { if (complain & tf_error) error ("the address of the %qT subobject of %qD is not a " @@ -7057,12 +7091,12 @@ get_template_parm_object (tree expr, tsubst_flags_t complain) tree type = cp_build_qualified_type (TREE_TYPE (expr), TYPE_QUAL_CONST); decl = create_temporary_var (type); + DECL_CONTEXT (decl) = NULL_TREE; TREE_STATIC (decl) = true; DECL_DECLARED_CONSTEXPR_P (decl) = true; TREE_READONLY (decl) = true; DECL_NAME (decl) = name; SET_DECL_ASSEMBLER_NAME (decl, name); - DECL_CONTEXT (decl) = global_namespace; comdat_linkage (decl); if (!zero_init_p (type)) @@ -8093,9 +8127,10 @@ canonicalize_expr_argument (tree arg, tsubst_flags_t complain) return canon; } -// A template declaration can be substituted for a constrained -// template template parameter only when the argument is more -// constrained than the parameter. +/* A template declaration can be substituted for a constrained + template template parameter only when the argument is no more + constrained than the parameter. */ + static bool is_compatible_template_arg (tree parm, tree arg) { @@ -9819,12 +9854,11 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, && !PRIMARY_TEMPLATE_P (gen_tmpl) && !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl)) && TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL) - { - found = xref_tag_from_type (TREE_TYPE (gen_tmpl), - DECL_NAME (gen_tmpl), - /*tag_scope=*/ts_global); - return found; - } + /* This occurs when the user has tried to define a tagged type + in a scope that forbids it. We emitted an error during the + parse. We didn't complete the bail out then, so here we + are. */ + return error_mark_node; context = DECL_CONTEXT (gen_tmpl); if (context && TYPE_P (context)) @@ -9907,7 +9941,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, /* A local class. Make sure the decl gets registered properly. */ if (context == current_function_decl) - if (pushtag (DECL_NAME (gen_tmpl), t, /*tag_scope=*/ts_current) + if (pushtag (DECL_NAME (gen_tmpl), t) == error_mark_node) return error_mark_node; @@ -10070,8 +10104,26 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, } } - // Build template info for the new specialization. - SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); + /* Build template info for the new specialization. */ + if (TYPE_ALIAS_P (t)) + { + /* This is constructed during instantiation of the alias + decl. But for member templates of template classes, that + is not correct as we need to refer to the partially + instantiated template, not the most general template. + The incorrect knowledge will not have escaped this + instantiation process, so we're good just updating the + template_info we made then. */ + tree ti = DECL_TEMPLATE_INFO (TYPE_NAME (t)); + gcc_checking_assert (template_args_equal (TI_ARGS (ti), arglist)); + if (TI_TEMPLATE (ti) != found) + { + gcc_checking_assert (DECL_TI_TEMPLATE (found) == TI_TEMPLATE (ti)); + TI_TEMPLATE (ti) = found; + } + } + else + SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); elt.spec = t; slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT); @@ -10189,6 +10241,42 @@ lookup_and_finish_template_variable (tree templ, tree targs, return convert_from_reference (templ); } +/* If the set of template parameters PARMS contains a template parameter + at the given LEVEL and INDEX, then return this parameter. Otherwise + return NULL_TREE. */ + +static tree +corresponding_template_parameter (tree parms, int level, int index) +{ + while (TMPL_PARMS_DEPTH (parms) > level) + parms = TREE_CHAIN (parms); + + if (TMPL_PARMS_DEPTH (parms) != level + || TREE_VEC_LENGTH (TREE_VALUE (parms)) <= index) + return NULL_TREE; + + tree t = TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), index)); + /* As in template_parm_to_arg. */ + if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == TEMPLATE_DECL) + t = TREE_TYPE (t); + else + t = DECL_INITIAL (t); + + gcc_assert (TEMPLATE_PARM_P (t)); + return t; +} + +/* Return the template parameter from PARMS that positionally corresponds + to the template parameter PARM, or else return NULL_TREE. */ + +static tree +corresponding_template_parameter (tree parms, tree parm) +{ + int level, index; + template_parm_level_and_index (parm, &level, &index); + return corresponding_template_parameter (parms, level, index); +} + struct pair_fn_data { @@ -10490,6 +10578,19 @@ keep_template_parm (tree t, void* data) if (level > ftpi->max_depth) return 0; + if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) + /* We want the underlying TEMPLATE_TEMPLATE_PARM, not the + BOUND_TEMPLATE_TEMPLATE_PARM itself. */ + t = TREE_TYPE (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t)); + + /* This template parameter might be an argument to a cached dependent + specalization that was formed earlier inside some other template, in + which case the parameter is not among the ones that are in-scope. + Look in CTX_PARMS to find the corresponding in-scope template + parameter, and use it instead. */ + if (tree in_scope = corresponding_template_parameter (ftpi->ctx_parms, t)) + t = in_scope; + /* Arguments like const T yield parameters like const T. This means that a template-id like X<T, const T> would yield two distinct parameters: T and const T. Adjust types to their unqualified versions. */ @@ -10736,7 +10837,7 @@ static GTY(()) struct tinst_level *last_error_tinst_level; /* We're starting to instantiate D; record the template instantiation context at LOC for diagnostics and to restore it later. */ -static bool +bool push_tinst_level_loc (tree tldcl, tree targs, location_t loc) { struct tinst_level *new_level; @@ -10790,7 +10891,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) /* We're starting substitution of TMPL<ARGS>; record the template substitution context for diagnostics and to restore it later. */ -static bool +bool push_tinst_level (tree tmpl, tree args) { return push_tinst_level_loc (tmpl, args, input_location); @@ -10979,7 +11080,7 @@ tsubst_friend_function (tree decl, tree args) into the namespace of the template. */ ns = decl_namespace_context (new_friend); push_nested_namespace (ns); - old_decl = pushdecl_namespace_level (new_friend, /*is_friend=*/true); + old_decl = pushdecl_namespace_level (new_friend, /*hiding=*/true); pop_nested_namespace (ns); if (old_decl == error_mark_node) @@ -11166,9 +11267,8 @@ tsubst_friend_class (tree friend_tmpl, tree args) push_nested_class (context); } - tmpl = lookup_name_real (DECL_NAME (friend_tmpl), /*prefer_type=*/false, - /*non_class=*/false, /*block_p=*/false, - /*namespaces_only=*/false, LOOKUP_HIDDEN); + tmpl = lookup_name (DECL_NAME (friend_tmpl), LOOK_where::CLASS_NAMESPACE, + LOOK_want::NORMAL | LOOK_want::HIDDEN_FRIEND); if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl)) { @@ -11209,11 +11309,6 @@ tsubst_friend_class (tree friend_tmpl, tree args) CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)) = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))); - /* It is hidden. */ - retrofit_lang_decl (DECL_TEMPLATE_RESULT (tmpl)); - DECL_ANTICIPATED (tmpl) - = DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (tmpl)) = true; - /* Substitute into and set the constraints on the new declaration. */ if (tree ci = get_constraints (friend_tmpl)) { @@ -11225,7 +11320,7 @@ tsubst_friend_class (tree friend_tmpl, tree args) } /* Inject this template into the enclosing namspace scope. */ - tmpl = pushdecl_namespace_level (tmpl, true); + tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/true); } } @@ -11795,7 +11890,7 @@ instantiate_class_template_1 (tree type) tsubst_enum. */ if (name) SET_IDENTIFIER_TYPE_VALUE (name, newtag); - pushtag (name, newtag, /*tag_scope=*/ts_current); + pushtag (name, newtag); } } else if (DECL_DECLARES_FUNCTION_P (t)) @@ -11971,29 +12066,11 @@ instantiate_class_template_1 (tree type) adjust_processing_template_decl = true; --processing_template_decl; } - else if (TREE_CODE (friend_type) != BOUND_TEMPLATE_TEMPLATE_PARM - && !CLASSTYPE_USE_TEMPLATE (friend_type) - && TYPE_HIDDEN_P (friend_type)) - { - /* friend class C; - - where C hasn't been declared yet. Let's lookup name - from namespace scope directly, bypassing any name that - come from dependent base class. */ - tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type)); - - /* The call to xref_tag_from_type does injection for friend - classes. */ - push_nested_namespace (ns); - friend_type = - xref_tag_from_type (friend_type, NULL_TREE, - /*tag_scope=*/ts_current); - pop_nested_namespace (ns); - } else if (uses_template_parms (friend_type)) /* friend class C<T>; */ friend_type = tsubst (friend_type, args, tf_warning_or_error, NULL_TREE); + /* Otherwise it's friend class C; @@ -13374,6 +13451,18 @@ tsubst_aggr_type (tree t, complain, in_decl); if (argvec == error_mark_node) r = error_mark_node; + else if (!entering_scope + && cxx_dialect >= cxx17 && dependent_scope_p (context)) + { + /* See maybe_dependent_member_ref. */ + tree name = TYPE_IDENTIFIER (t); + tree fullname = name; + if (instantiates_primary_template_p (t)) + fullname = build_nt (TEMPLATE_ID_EXPR, name, + INNERMOST_TEMPLATE_ARGS (argvec)); + return build_typename_type (context, name, fullname, + typename_type); + } else { r = lookup_template_class (t, argvec, in_decl, context, @@ -13645,14 +13734,20 @@ static tree tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, tree lambda_fntype) { - tree gen_tmpl, argvec; + tree gen_tmpl = NULL_TREE, argvec = NULL_TREE; hashval_t hash = 0; tree in_decl = t; /* Nobody should be tsubst'ing into non-template functions. */ - gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE); + gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE + || DECL_LOCAL_DECL_P (t)); - if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL) + if (DECL_LOCAL_DECL_P (t)) + { + if (tree spec = retrieve_local_specialization (t)) + return spec; + } + else if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL) { /* If T is not dependent, just return it. */ if (!uses_template_parms (DECL_TI_ARGS (t)) @@ -13902,6 +13997,11 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, && !uses_template_parms (argvec)) tsubst_default_arguments (r, complain); } + else if (DECL_LOCAL_DECL_P (r)) + { + if (!cp_unevaluated_operand) + register_local_specialization (r, t); + } else DECL_TEMPLATE_INFO (r) = NULL_TREE; @@ -14061,7 +14161,11 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, class_p = true; inner = TREE_TYPE (inner); } - inner = tsubst (inner, args, complain, in_decl); + if (class_p) + inner = tsubst_aggr_type (inner, args, complain, + in_decl, /*entering*/1); + else + inner = tsubst (inner, args, complain, in_decl); } --processing_template_decl; if (inner == error_mark_node) @@ -14447,11 +14551,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) { tree argvec = NULL_TREE; tree gen_tmpl = NULL_TREE; - tree spec; tree tmpl = NULL_TREE; - tree ctx; tree type = NULL_TREE; - bool local_p; if (TREE_TYPE (t) == error_mark_node) RETURN (error_mark_node); @@ -14473,19 +14574,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Check to see if we already have the specialization we need. */ - spec = NULL_TREE; - if (DECL_CLASS_SCOPE_P (t) || DECL_NAMESPACE_SCOPE_P (t)) + tree spec = NULL_TREE; + bool local_p = false; + tree ctx = DECL_CONTEXT (t); + if (!(VAR_P (t) && DECL_LOCAL_DECL_P (t)) + && (DECL_CLASS_SCOPE_P (t) || DECL_NAMESPACE_SCOPE_P (t))) { - /* T is a static data member or namespace-scope entity. - We have to substitute into namespace-scope variables - (not just variable templates) because of cases like: - - template <class T> void f() { extern T t; } - - where the entity referenced is not known until - instantiation time. */ local_p = false; - ctx = DECL_CONTEXT (t); if (DECL_CLASS_SCOPE_P (t)) { ctx = tsubst_aggr_type (ctx, args, @@ -14525,10 +14620,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) } else { + if (!(VAR_P (t) && DECL_LOCAL_DECL_P (t))) + /* Subsequent calls to pushdecl will fill this in. */ + ctx = NULL_TREE; /* A local variable. */ local_p = true; - /* Subsequent calls to pushdecl will fill this in. */ - ctx = NULL_TREE; /* Unless this is a reference to a static variable from an enclosing function, in which case we need to fill it in now. */ if (TREE_STATIC (t)) @@ -14690,10 +14786,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); - /* Remember whether we require constant initialization of - a non-constant template variable. */ - TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (r)) - = TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (t)); if (!error_operand_p (r) || (complain & tf_error)) register_specialization (r, gen_tmpl, argvec, false, hash); } @@ -16169,10 +16261,10 @@ tsubst_qualified_id (tree qualified_id, tree args, } else expr = lookup_qualified_name (scope, complete_dtor_identifier, - /*is_type_p=*/0, false); + LOOK_want::NORMAL, false); } else - expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0, false); + expr = lookup_qualified_name (scope, expr, LOOK_want::NORMAL, false); if (TREE_CODE (TREE_CODE (expr) == TEMPLATE_DECL ? DECL_TEMPLATE_RESULT (expr) : expr) == TYPE_DECL) { @@ -16296,6 +16388,31 @@ tsubst_init (tree init, tree decl, tree args, return init; } +/* If T is a reference to a dependent member of the current instantiation C and + we are trying to refer to that member in a partial instantiation of C, + return a SCOPE_REF; otherwise, return NULL_TREE. + + This can happen when forming a C++17 deduction guide, as in PR96199. */ + +static tree +maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain, + tree in_decl) +{ + if (cxx_dialect < cxx17) + return NULL_TREE; + + tree ctx = context_for_name_lookup (t); + if (!CLASS_TYPE_P (ctx)) + return NULL_TREE; + + ctx = tsubst (ctx, args, complain, in_decl); + if (dependent_scope_p (ctx)) + return build_qualified_name (NULL_TREE, ctx, DECL_NAME (t), + /*template_p=*/false); + + return NULL_TREE; +} + /* Like tsubst, but deals with expressions. This function just replaces template parms; to finish processing the resultant expression, use tsubst_copy_and_build or tsubst_expr. */ @@ -16354,6 +16471,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (args == NULL_TREE) return scalar_constant_value (t); + if (tree ref = maybe_dependent_member_ref (t, args, complain, in_decl)) + return ref; + /* Unfortunately, we cannot just call lookup_name here. Consider: @@ -16404,9 +16524,20 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) return t; case VAR_DECL: + if (tree ref = maybe_dependent_member_ref (t, args, complain, in_decl)) + return ref; + gcc_fallthrough(); case FUNCTION_DECL: if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)) r = tsubst (t, args, complain, in_decl); + else if (DECL_LOCAL_DECL_P (t)) + { + /* Local specialization will have been created when we + instantiated the DECL_EXPR_DECL. */ + r = retrieve_local_specialization (t); + if (!r) + r = error_mark_node; + } else if (local_variable_p (t) && uses_template_parms (DECL_CONTEXT (t))) { @@ -17818,7 +17949,7 @@ lookup_init_capture_pack (tree decl) for (int i = 0; i < len; ++i) { tree ename = vec ? make_ith_pack_parameter_name (cname, i) : cname; - tree elt = lookup_name_real (ename, 0, 0, true, 0, LOOKUP_NORMAL); + tree elt = lookup_name (ename); if (vec) TREE_VEC_ELT (vec, i) = elt; else @@ -17923,9 +18054,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, tree inst; if (!DECL_PACK_P (decl)) { - inst = lookup_name_real (DECL_NAME (decl), /*prefer_type*/0, - /*nonclass*/1, /*block_p=*/true, - /*ns_only*/0, LOOKUP_HIDDEN); + inst = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK, + LOOK_want::HIDDEN_LAMBDA); gcc_assert (inst != decl && is_capture_proxy (inst)); } else if (is_normal_capture_proxy (decl)) @@ -17953,13 +18083,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, else { init = DECL_INITIAL (decl); - /* The following tsubst call will clear the DECL_TEMPLATE_INFO - for local variables, so save if DECL was declared constinit. */ - const bool constinit_p - = (VAR_P (decl) - && DECL_LANG_SPECIFIC (decl) - && DECL_TEMPLATE_INFO (decl) - && TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (decl))); decl = tsubst (decl, args, complain, in_decl); if (decl != error_mark_node) { @@ -17987,14 +18110,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } else if (DECL_IMPLICIT_TYPEDEF_P (t)) /* We already did a pushtag. */; - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_OMP_DECLARE_REDUCTION_P (decl) - && DECL_FUNCTION_SCOPE_P (pattern_decl)) + else if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl)) { - DECL_CONTEXT (decl) = NULL_TREE; - pushdecl (decl); - DECL_CONTEXT (decl) = current_function_decl; - cp_check_omp_declare_reduction (decl); + if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + decl = pushdecl (decl); + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_OMP_DECLARE_REDUCTION_P (decl) + && cp_check_omp_declare_reduction (decl)) + instantiate_body (pattern_decl, args, decl, true); } else { @@ -18024,8 +18149,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, now. */ predeclare_vla (decl); - cp_finish_decl (decl, init, const_init, NULL_TREE, - constinit_p ? LOOKUP_CONSTINIT : 0); + cp_finish_decl (decl, init, const_init, NULL_TREE, 0); if (ndecl != error_mark_node) cp_finish_decomp (ndecl, first, cnt); @@ -18516,6 +18640,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, stmt = pop_stmt_list (stmt); } + if (TREE_CODE (t) == OMP_CRITICAL + && tmp != NULL_TREE + && integer_nonzerop (OMP_CLAUSE_HINT_EXPR (tmp))) + { + error_at (OMP_CLAUSE_LOCATION (tmp), + "%<#pragma omp critical%> with %<hint%> clause requires " + "a name, except when %<omp_sync_hint_none%> is used"); + RETURN (error_mark_node); + } t = copy_node (t); OMP_BODY (t) = stmt; OMP_CLAUSES (t) = tmp; @@ -18804,7 +18937,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (t == NULL_TREE || t == error_mark_node) return; - gcc_assert (TREE_CODE (t) == STATEMENT_LIST); + gcc_assert (TREE_CODE (t) == STATEMENT_LIST && current_function_decl); tree_stmt_iterator tsi; int i; @@ -18824,6 +18957,8 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl) args, complain, in_decl); tree omp_in = tsubst (DECL_EXPR_DECL (stmts[1]), args, complain, in_decl); + /* tsubsting a local var_decl leaves DECL_CONTEXT null, as we + expect to be pushing it. */ DECL_CONTEXT (omp_out) = current_function_decl; DECL_CONTEXT (omp_in) = current_function_decl; keep_next_level (true); @@ -19149,7 +19284,8 @@ out: } /* Like tsubst but deals with expressions and performs semantic - analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)". */ + analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)" or + "F<TARGS> (ARGS)". */ tree tsubst_copy_and_build (tree t, @@ -19231,7 +19367,10 @@ tsubst_copy_and_build (tree t, case TEMPLATE_ID_EXPR: { tree object; - tree templ = RECUR (TREE_OPERAND (t, 0)); + tree templ = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, + complain, in_decl, + function_p, + integral_constant_expression_p); tree targs = TREE_OPERAND (t, 1); if (targs) @@ -19278,13 +19417,21 @@ tsubst_copy_and_build (tree t, } else object = NULL_TREE; - templ = lookup_template_function (templ, targs); + + tree tid = lookup_template_function (templ, targs); if (object) - RETURN (build3 (COMPONENT_REF, TREE_TYPE (templ), - object, templ, NULL_TREE)); + RETURN (build3 (COMPONENT_REF, TREE_TYPE (tid), + object, tid, NULL_TREE)); + else if (identifier_p (templ)) + { + /* C++20 P0846: we can encounter an IDENTIFIER_NODE here when + name lookup found nothing when parsing the template name. */ + gcc_assert (cxx_dialect >= cxx20 || seen_error ()); + RETURN (tid); + } else - RETURN (baselink_for_fns (templ)); + RETURN (baselink_for_fns (tid)); } case INDIRECT_REF: @@ -19387,6 +19534,8 @@ tsubst_copy_and_build (tree t, break; case STATIC_CAST_EXPR: r = build_static_cast (input_location, type, op, complain); + if (IMPLICIT_RVALUE_P (t)) + set_implicit_rvalue_p (r); break; default: gcc_unreachable (); @@ -19818,7 +19967,7 @@ tsubst_copy_and_build (tree t, /* Stripped-down processing for a call in a thunk. Specifically, in the thunk template for a generic lambda. */ - if (CALL_FROM_THUNK_P (t)) + if (call_from_lambda_thunk_p (t)) { /* Now that we've expanded any packs, the number of call args might be different. */ @@ -19873,14 +20022,17 @@ tsubst_copy_and_build (tree t, /* We do not perform argument-dependent lookup if normal lookup finds a non-function, in accordance with the - expected resolution of DR 218. */ + resolution of DR 218. */ if (koenig_p && ((is_overloaded_fn (function) /* If lookup found a member function, the Koenig lookup is not appropriate, even if an unqualified-name was used to denote the function. */ && !DECL_FUNCTION_MEMBER_P (get_first_fn (function))) - || identifier_p (function)) + || identifier_p (function) + /* C++20 P0846: Lookup found nothing. */ + || (TREE_CODE (function) == TEMPLATE_ID_EXPR + && identifier_p (TREE_OPERAND (function, 0)))) /* Only do this when substitution turns a dependent call into a non-dependent call. */ && type_dependent_expression_p_push (t) @@ -19888,9 +20040,13 @@ tsubst_copy_and_build (tree t, function = perform_koenig_lookup (function, call_args, tf_none); if (function != NULL_TREE - && identifier_p (function) + && (identifier_p (function) + || (TREE_CODE (function) == TEMPLATE_ID_EXPR + && identifier_p (TREE_OPERAND (function, 0)))) && !any_type_dependent_arguments_p (call_args)) { + if (TREE_CODE (function) == TEMPLATE_ID_EXPR) + function = TREE_OPERAND (function, 0); if (koenig_p && (complain & tf_warning_or_error)) { /* For backwards compatibility and good diagnostics, try @@ -20194,8 +20350,7 @@ tsubst_copy_and_build (tree t, tree scope = TREE_OPERAND (member, 0); tree tmpl = TREE_OPERAND (TREE_OPERAND (member, 1), 0); tree args = TREE_OPERAND (TREE_OPERAND (member, 1), 1); - member = lookup_qualified_name (scope, tmpl, - /*is_type_p=*/false, + member = lookup_qualified_name (scope, tmpl, LOOK_want::NORMAL, /*complain=*/false); if (BASELINK_P (member)) { @@ -21211,13 +21366,24 @@ fn_type_unification (tree fn, goto fail; } + deduced: + + /* CWG2369: Check satisfaction before non-deducible conversions. */ + if (!constraints_satisfied_p (fn, targs)) + { + if (explain_p) + diagnose_constraints (DECL_SOURCE_LOCATION (fn), fn, targs); + goto fail; + } + /* DR 1391: All parameters have args, now check non-dependent parms for - convertibility. */ - if (check_non_deducible_conversions (parms, args, nargs, fn, strict, flags, - convs, explain_p)) + convertibility. We don't do this if all args were explicitly specified, + as the standard says that we substitute explicit args immediately. */ + if (incomplete + && check_non_deducible_conversions (parms, args, nargs, fn, strict, flags, + convs, explain_p)) goto fail; - deduced: /* All is well so far. Now, check: [temp.deduct] @@ -22093,7 +22259,18 @@ resolve_overloaded_unification (tree tparms, if (subargs != error_mark_node && !any_dependent_template_arguments_p (subargs)) { - elem = TREE_TYPE (instantiate_template (fn, subargs, tf_none)); + fn = instantiate_template (fn, subargs, tf_none); + if (!constraints_satisfied_p (fn)) + continue; + if (undeduced_auto_decl (fn)) + { + /* Instantiate the function to deduce its return type. */ + ++function_depth; + instantiate_decl (fn, /*defer*/false, /*class*/false); + --function_depth; + } + + elem = TREE_TYPE (fn); if (try_one_overload (tparms, targs, tempargs, parm, elem, strict, sub_strict, addr_p, explain_p) && (!goodfn || !same_type_p (goodfn, elem))) @@ -22231,7 +22408,8 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain) badfn = fn; badargs = subargs; } - else if (elem && (!goodfn || !decls_match (goodfn, elem))) + else if (elem && (!goodfn || !decls_match (goodfn, elem)) + && constraints_satisfied_p (elem)) { goodfn = elem; ++good; @@ -24902,23 +25080,22 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) [temp.explicit] - The explicit instantiation of a class template specialization - implies the instantiation of all of its members not - previously explicitly specialized in the translation unit - containing the explicit instantiation. - - Of course, we can't instantiate member template classes, since we - don't have any arguments for them. Note that the standard is - unclear on whether the instantiation of the members are - *explicit* instantiations or not. However, the most natural - interpretation is that it should be an explicit - instantiation. */ + An explicit instantiation that names a class template + specialization is also an explicit instantiation of the same + kind (declaration or definition) of each of its members (not + including members inherited from base classes and members + that are templates) that has not been previously explicitly + specialized in the translation unit containing the explicit + instantiation, provided that the associated constraints, if + any, of that member are satisfied by the template arguments + of the explicit instantiation. */ for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld)) if ((VAR_P (fld) || (TREE_CODE (fld) == FUNCTION_DECL && !static_p && user_provided_p (fld))) - && DECL_TEMPLATE_INSTANTIATION (fld)) + && DECL_TEMPLATE_INSTANTIATION (fld) + && constraints_satisfied_p (fld)) { mark_decl_instantiated (fld, extern_p); if (! extern_p) @@ -25235,15 +25412,20 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) push_deferring_access_checks (dk_no_deferred); input_location = DECL_SOURCE_LOCATION (fn); - /* If needed, set current_class_ptr for the benefit of - tsubst_copy/PARM_DECL. */ - tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn)); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl)) + if (!DECL_LOCAL_DECL_P (fn)) { - tree this_parm = DECL_ARGUMENTS (tdecl); - current_class_ptr = NULL_TREE; - current_class_ref = cp_build_fold_indirect_ref (this_parm); - current_class_ptr = this_parm; + /* If needed, set current_class_ptr for the benefit of + tsubst_copy/PARM_DECL. The exception pattern will + refer to the parm of the template, not the + instantiation. */ + tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn)); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl)) + { + tree this_parm = DECL_ARGUMENTS (tdecl); + current_class_ptr = NULL_TREE; + current_class_ref = cp_build_fold_indirect_ref (this_parm); + current_class_ptr = this_parm; + } } /* If this function is represented by a TEMPLATE_DECL, then @@ -25325,6 +25507,164 @@ register_parameter_specializations (tree pattern, tree inst) gcc_assert (!spec_parm); } +/* Instantiate the body of D using PATTERN with ARGS. We have + already determined PATTERN is the correct template to use. + NESTED_P is true if this is a nested function, in which case + PATTERN will be a FUNCTION_DECL not a TEMPLATE_DECL. */ + +static void +instantiate_body (tree pattern, tree args, tree d, bool nested_p) +{ + tree td = NULL_TREE; + tree code_pattern = pattern; + + if (!nested_p) + { + td = pattern; + code_pattern = DECL_TEMPLATE_RESULT (td); + } + else + /* Only OMP reductions are nested. */ + gcc_checking_assert (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)); + + vec<tree> omp_privatization_save; + if (current_function_decl) + save_omp_privatization_clauses (omp_privatization_save); + + bool push_to_top + = !(current_function_decl + && !LAMBDA_FUNCTION_P (d) + && decl_function_context (d) == current_function_decl); + + if (push_to_top) + push_to_top_level (); + else + { + gcc_assert (!processing_template_decl); + push_function_context (); + cp_unevaluated_operand = 0; + c_inhibit_evaluation_warnings = 0; + } + + if (VAR_P (d)) + { + /* The variable might be a lambda's extra scope, and that + lambda's visibility depends on D's. */ + maybe_commonize_var (d); + determine_visibility (d); + } + + /* Mark D as instantiated so that recursive calls to + instantiate_decl do not try to instantiate it again. */ + DECL_TEMPLATE_INSTANTIATED (d) = 1; + + if (td) + /* Regenerate the declaration in case the template has been modified + by a subsequent redeclaration. */ + regenerate_decl_from_template (d, td, args); + + /* We already set the file and line above. Reset them now in case + they changed as a result of calling regenerate_decl_from_template. */ + input_location = DECL_SOURCE_LOCATION (d); + + if (VAR_P (d)) + { + tree init; + bool const_init = false; + + /* Clear out DECL_RTL; whatever was there before may not be right + since we've reset the type of the declaration. */ + SET_DECL_RTL (d, NULL); + DECL_IN_AGGR_P (d) = 0; + + /* The initializer is placed in DECL_INITIAL by + regenerate_decl_from_template so we don't need to + push/pop_access_scope again here. Pull it out so that + cp_finish_decl can process it. */ + init = DECL_INITIAL (d); + DECL_INITIAL (d) = NULL_TREE; + DECL_INITIALIZED_P (d) = 0; + + /* Clear DECL_EXTERNAL so that cp_finish_decl will process the + initializer. That function will defer actual emission until + we have a chance to determine linkage. */ + DECL_EXTERNAL (d) = 0; + + /* Enter the scope of D so that access-checking works correctly. */ + bool enter_context = DECL_CLASS_SCOPE_P (d); + if (enter_context) + push_nested_class (DECL_CONTEXT (d)); + + const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern); + cp_finish_decl (d, init, const_init, NULL_TREE, 0); + + if (enter_context) + pop_nested_class (); + } + else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern)) + synthesize_method (d); + else if (TREE_CODE (d) == FUNCTION_DECL) + { + /* Set up the list of local specializations. */ + local_specialization_stack lss (push_to_top ? lss_blank : lss_copy); + tree block = NULL_TREE; + + /* Set up context. */ + if (nested_p) + block = push_stmt_list (); + else + start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); + + perform_instantiation_time_access_checks (code_pattern, args); + + /* Create substitution entries for the parameters. */ + register_parameter_specializations (code_pattern, d); + + /* Substitute into the body of the function. */ + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) + tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args, + tf_warning_or_error, d); + else + { + tsubst_expr (DECL_SAVED_TREE (code_pattern), args, + tf_warning_or_error, DECL_TI_TEMPLATE (d), + /*integral_constant_expression_p=*/false); + + /* Set the current input_location to the end of the function + so that finish_function knows where we are. */ + input_location + = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus; + + /* Remember if we saw an infinite loop in the template. */ + current_function_infinite_loop + = DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop; + } + + /* Finish the function. */ + if (nested_p) + DECL_SAVED_TREE (d) = pop_stmt_list (block); + else + { + d = finish_function (/*inline_p=*/false); + expand_or_defer_fn (d); + } + + if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) + cp_check_omp_declare_reduction (d); + } + + /* We're not deferring instantiation any more. */ + TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0; + + if (push_to_top) + pop_from_top_level (); + else + pop_function_context (); + + if (current_function_decl) + restore_omp_privatization_clauses (omp_privatization_save); +} + /* Produce the definition of D, a _DECL generated from a template. If DEFER_OK is true, then we don't have to actually do the instantiation now; we just have to do it sometime. Normally it is @@ -25356,6 +25696,8 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) /* A concept is never instantiated. */ gcc_assert (!DECL_DECLARED_CONCEPT_P (d)); + gcc_checking_assert (!DECL_FUNCTION_SCOPE_P (d)); + /* Variables are never deferred; if instantiation is required, they are instantiated right away. That allows for better code in the case that an expression refers to the value of the variable -- @@ -25562,164 +25904,19 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) /* If we're in unevaluated context, we just wanted to get the constant value; this isn't an odr use, so don't queue a full instantiation. */ - if (cp_unevaluated_operand != 0) - goto out; - /* ??? Historically, we have instantiated inline functions, even - when marked as "extern template". */ - if (!(external_p && VAR_P (d))) + if (!cp_unevaluated_operand + /* ??? Historically, we have instantiated inline functions, even + when marked as "extern template". */ + && !(external_p && VAR_P (d))) add_pending_template (d); - goto out; } - - bool push_to_top, nested; - tree fn_context; - fn_context = decl_function_context (d); - if (LAMBDA_FUNCTION_P (d)) - /* tsubst_lambda_expr resolved any references to enclosing functions. */ - fn_context = NULL_TREE; - nested = current_function_decl != NULL_TREE; - push_to_top = !(nested && fn_context == current_function_decl); - - vec<tree> omp_privatization_save; - if (nested) - save_omp_privatization_clauses (omp_privatization_save); - - if (push_to_top) - push_to_top_level (); else { - gcc_assert (!processing_template_decl); - push_function_context (); - cp_unevaluated_operand = 0; - c_inhibit_evaluation_warnings = 0; - } - - if (VAR_P (d)) - { - /* The variable might be a lambda's extra scope, and that - lambda's visibility depends on D's. */ - maybe_commonize_var (d); - determine_visibility (d); - } - - /* Mark D as instantiated so that recursive calls to - instantiate_decl do not try to instantiate it again. */ - DECL_TEMPLATE_INSTANTIATED (d) = 1; - - /* Regenerate the declaration in case the template has been modified - by a subsequent redeclaration. */ - regenerate_decl_from_template (d, td, args); - - /* We already set the file and line above. Reset them now in case - they changed as a result of calling regenerate_decl_from_template. */ - input_location = DECL_SOURCE_LOCATION (d); - - if (VAR_P (d)) - { - tree init; - bool const_init = false; - - /* Clear out DECL_RTL; whatever was there before may not be right - since we've reset the type of the declaration. */ - SET_DECL_RTL (d, NULL); - DECL_IN_AGGR_P (d) = 0; - - /* The initializer is placed in DECL_INITIAL by - regenerate_decl_from_template so we don't need to - push/pop_access_scope again here. Pull it out so that - cp_finish_decl can process it. */ - init = DECL_INITIAL (d); - DECL_INITIAL (d) = NULL_TREE; - DECL_INITIALIZED_P (d) = 0; - - /* Clear DECL_EXTERNAL so that cp_finish_decl will process the - initializer. That function will defer actual emission until - we have a chance to determine linkage. */ - DECL_EXTERNAL (d) = 0; - - /* Enter the scope of D so that access-checking works correctly. */ - bool enter_context = DECL_CLASS_SCOPE_P (d); - if (enter_context) - push_nested_class (DECL_CONTEXT (d)); - - const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern); - int flags = (TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (d)) - ? LOOKUP_CONSTINIT : 0); - cp_finish_decl (d, init, const_init, NULL_TREE, flags); - - if (enter_context) - pop_nested_class (); - if (variable_template_p (gen_tmpl)) note_variable_template_instantiation (d); - } - else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern)) - synthesize_method (d); - else if (TREE_CODE (d) == FUNCTION_DECL) - { - /* Set up the list of local specializations. */ - local_specialization_stack lss (push_to_top ? lss_blank : lss_copy); - tree block = NULL_TREE; - - /* Set up context. */ - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) - && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) - block = push_stmt_list (); - else - start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); - - perform_instantiation_time_access_checks (DECL_TEMPLATE_RESULT (td), - args); - - /* Create substitution entries for the parameters. */ - register_parameter_specializations (code_pattern, d); - - /* Substitute into the body of the function. */ - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) - tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args, - tf_warning_or_error, tmpl); - else - { - tsubst_expr (DECL_SAVED_TREE (code_pattern), args, - tf_warning_or_error, tmpl, - /*integral_constant_expression_p=*/false); - - /* Set the current input_location to the end of the function - so that finish_function knows where we are. */ - input_location - = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus; - - /* Remember if we saw an infinite loop in the template. */ - current_function_infinite_loop - = DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop; - } - - /* Finish the function. */ - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) - && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) - DECL_SAVED_TREE (d) = pop_stmt_list (block); - else - { - d = finish_function (/*inline_p=*/false); - expand_or_defer_fn (d); - } - - if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) - cp_check_omp_declare_reduction (d); + instantiate_body (td, args, d, false); } - /* We're not deferring instantiation any more. */ - TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0; - - if (push_to_top) - pop_from_top_level (); - else - pop_function_context (); - - if (nested) - restore_omp_privatization_clauses (omp_privatization_save); - -out: pop_deferring_access_checks (); timevar_pop (TV_TEMPLATE_INST); pop_tinst_level (); @@ -25982,6 +26179,9 @@ tsubst_initializer_list (tree t, tree argvec) if (decl) { init = build_tree_list (decl, init); + /* Carry over the dummy TREE_TYPE node containing the source + location. */ + TREE_TYPE (init) = TREE_TYPE (t); TREE_CHAIN (init) = inits; inits = init; } @@ -26714,8 +26914,7 @@ type_dependent_expression_p (tree expression) return true; /* Some expression forms are never type-dependent. */ - if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR - || TREE_CODE (expression) == SIZEOF_EXPR + if (TREE_CODE (expression) == SIZEOF_EXPR || TREE_CODE (expression) == ALIGNOF_EXPR || TREE_CODE (expression) == AT_ENCODE_EXPR || TREE_CODE (expression) == NOEXCEPT_EXPR @@ -26752,6 +26951,10 @@ type_dependent_expression_p (tree expression) return dependent_type_p (TREE_VALUE (TREE_PURPOSE (type))) || value_dependent_expression_p (TREE_OPERAND (TREE_VALUE (type), 1)); + /* Array type whose dimension has to be deduced. */ + else if (TREE_CODE (type) == ARRAY_TYPE + && TREE_OPERAND (expression, 2) == NULL_TREE) + return true; else return dependent_type_p (type); } @@ -26849,7 +27052,7 @@ type_dependent_expression_p (tree expression) && DECL_FRIEND_P (expression) && (!DECL_FRIEND_CONTEXT (expression) || dependent_type_p (DECL_FRIEND_CONTEXT (expression)))) - && !DECL_LOCAL_FUNCTION_P (expression)) + && !DECL_LOCAL_DECL_P (expression)) { gcc_assert (!dependent_type_p (TREE_TYPE (expression)) || undeduced_auto_decl (expression)); @@ -27730,7 +27933,9 @@ make_constrained_placeholder_type (tree type, tree con, tree args) tree expr = tmpl; if (TREE_CODE (con) == FUNCTION_DECL) expr = ovl_make (tmpl); + ++processing_template_decl; expr = build_concept_check (expr, type, args, tf_warning_or_error); + --processing_template_decl; PLACEHOLDER_TYPE_CONSTRAINTS (type) = expr; @@ -28288,6 +28493,16 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com fargs = tsubst (fargs, tsubst_args, complain, ctor); current_template_parms = save_parms; } + else + { + /* Substitute in the same arguments to rewrite class members into + references to members of an unknown specialization. */ + cp_evaluated ev; + fparms = tsubst_arg_types (fparms, targs, NULL_TREE, complain, ctor); + fargs = tsubst (fargs, targs, complain, ctor); + if (ci) + ci = tsubst_constraint_info (ci, targs, complain, ctor); + } --processing_template_decl; if (!ok) @@ -28358,8 +28573,13 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE) if (TREE_CODE (ftype) == ARRAY_TYPE && (BRACE_ENCLOSED_INITIALIZER_P (val) || TREE_CODE (val) == STRING_CST)) - ftype = (cp_build_reference_type - (ftype, BRACE_ENCLOSED_INITIALIZER_P (val))); + { + if (TREE_CODE (val) == STRING_CST) + ftype = cp_build_qualified_type + (ftype, cp_type_quals (ftype) | TYPE_QUAL_CONST); + ftype = (cp_build_reference_type + (ftype, BRACE_ENCLOSED_INITIALIZER_P (val))); + } list = tree_cons (arg, ftype, list); } @@ -28590,7 +28810,10 @@ alias_ctad_tweaks (tree tmpl, tree uguides) } if (ci) - set_constraints (fprime, ci); + { + remove_constraints (fprime); + set_constraints (fprime, ci); + } } else { @@ -28661,26 +28884,29 @@ static GTY((deletable)) hash_map<tree, tree_pair_p> *dguide_cache; /* Return the non-aggregate deduction guides for deducible template TMPL. The aggregate candidate is added separately because it depends on the - initializer. */ + initializer. Set ANY_DGUIDES_P if we find a non-implicit deduction + guide. */ static tree -deduction_guides_for (tree tmpl, tsubst_flags_t complain) +deduction_guides_for (tree tmpl, bool &any_dguides_p, tsubst_flags_t complain) { tree guides = NULL_TREE; if (DECL_ALIAS_TEMPLATE_P (tmpl)) { tree under = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); tree tinfo = get_template_info (under); - guides = deduction_guides_for (TI_TEMPLATE (tinfo), complain); + guides = deduction_guides_for (TI_TEMPLATE (tinfo), any_dguides_p, + complain); } else { guides = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dguide_name (tmpl), - /*type*/false, /*complain*/false, - /*hidden*/false); + LOOK_want::NORMAL, /*complain*/false); if (guides == error_mark_node) guides = NULL_TREE; + else + any_dguides_p = true; } /* Cache the deduction guides for a template. We also remember the result of @@ -28772,6 +28998,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree type = TREE_TYPE (tmpl); bool try_list_ctor = false; + bool list_init_p = false; releasing_vec rv_args = NULL; vec<tree,va_gc> *&args = *&rv_args; @@ -28779,6 +29006,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, args = make_tree_vector (); else if (BRACE_ENCLOSED_INITIALIZER_P (init)) { + list_init_p = true; try_list_ctor = TYPE_HAS_LIST_CTOR (type); if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1) { @@ -28806,13 +29034,15 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (args == NULL) return error_mark_node; - tree cands = deduction_guides_for (tmpl, complain); + bool any_dguides_p = false; + tree cands = deduction_guides_for (tmpl, any_dguides_p, complain); if (cands == error_mark_node) return error_mark_node; - /* Prune explicit deduction guides in copy-initialization context. */ + /* Prune explicit deduction guides in copy-initialization context (but + not copy-list-initialization). */ bool elided = false; - if (flags & LOOKUP_ONLYCONVERTING) + if (!list_init_p && (flags & LOOKUP_ONLYCONVERTING)) { for (lkp_iterator iter (cands); !elided && iter; ++iter) if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter))) @@ -28881,18 +29111,57 @@ do_class_deduction (tree ptype, tree tmpl, tree init, --cp_unevaluated_operand; } - if (call == error_mark_node - && (complain & tf_warning_or_error)) + if (call == error_mark_node) { - error ("class template argument deduction failed:"); + if (complain & tf_warning_or_error) + { + error ("class template argument deduction failed:"); - ++cp_unevaluated_operand; - call = build_new_function_call (cands, &args, complain | tf_decltype); - --cp_unevaluated_operand; + ++cp_unevaluated_operand; + call = build_new_function_call (cands, &args, + complain | tf_decltype); + --cp_unevaluated_operand; - if (elided) - inform (input_location, "explicit deduction guides not considered " - "for copy-initialization"); + if (elided) + inform (input_location, "explicit deduction guides not considered " + "for copy-initialization"); + } + return error_mark_node; + } + /* [over.match.list]/1: In copy-list-initialization, if an explicit + constructor is chosen, the initialization is ill-formed. */ + else if (flags & LOOKUP_ONLYCONVERTING) + { + tree fndecl = cp_get_callee_fndecl_nofold (call); + if (fndecl && DECL_NONCONVERTING_P (fndecl)) + { + if (complain & tf_warning_or_error) + { + // TODO: Pass down location from cp_finish_decl. + error ("class template argument deduction for %qT failed: " + "explicit deduction guide selected in " + "copy-list-initialization", type); + inform (DECL_SOURCE_LOCATION (fndecl), + "explicit deduction guide declared here"); + + } + return error_mark_node; + } + } + + /* If CTAD succeeded but the type doesn't have any explicit deduction + guides, this deduction might not be what the user intended. */ + if (call != error_mark_node && !any_dguides_p) + { + tree fndecl = cp_get_callee_fndecl_nofold (call); + if (fndecl != NULL_TREE + && (!DECL_IN_SYSTEM_HEADER (fndecl) + || global_dc->dc_warn_system_headers) + && warning (OPT_Wctad_maybe_unsupported, + "%qT may not intend to support class template argument " + "deduction", type)) + inform (input_location, "add a deduction guide to suppress this " + "warning"); } return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype)); @@ -28994,6 +29263,12 @@ do_auto_deduction (tree type, tree init, tree auto_node, error ("%qT as type rather than plain %<decltype(auto)%>", type); return error_mark_node; } + else if (TYPE_QUALS (type) != TYPE_UNQUALIFIED) + { + if (complain & tf_error) + error ("%<decltype(auto)%> cannot be cv-qualified"); + return error_mark_node; + } } else { @@ -29285,7 +29560,7 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) if (tree constr = TEMPLATE_PARM_CONSTRAINTS (node)) { tree id = unpack_concept_check (constr); - TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = template_parm_to_arg (t); + TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = t; tree fold = finish_left_unary_fold_expr (constr, TRUTH_ANDIF_EXPR); TEMPLATE_PARM_CONSTRAINTS (node) = fold; diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index ab18eec..a28b722 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -41,6 +41,7 @@ cxx_print_decl (FILE *file, tree node, int indent) if (!CODE_CONTAINS_STRUCT (TREE_CODE (node), TS_DECL_COMMON) || !DECL_LANG_SPECIFIC (node)) return; + if (TREE_CODE (node) == FUNCTION_DECL) { int flags = TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE @@ -56,17 +57,35 @@ cxx_print_decl (FILE *file, tree node, int indent) decl_as_string (node, TFF_TEMPLATE_HEADER)); } - indent_to (file, indent + 3); + bool need_indent = true; + if (DECL_EXTERNAL (node) && DECL_NOT_REALLY_EXTERN (node)) - fprintf (file, " not-really-extern"); + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " not-really-extern"); + need_indent = false; + } + if (TREE_CODE (node) == FUNCTION_DECL && DECL_PENDING_INLINE_INFO (node)) - fprintf (file, " pending-inline-info %p", - (void *) DECL_PENDING_INLINE_INFO (node)); + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " pending-inline-info %p", + (void *) DECL_PENDING_INLINE_INFO (node)); + need_indent = false; + } + if (VAR_OR_FUNCTION_DECL_P (node) && DECL_TEMPLATE_INFO (node)) - fprintf (file, " template-info %p", - (void *) DECL_TEMPLATE_INFO (node)); + { + if (need_indent) + indent_to (file, indent + 3); + fprintf (file, " template-info %p", + (void *) DECL_TEMPLATE_INFO (node)); + need_indent = false; + } } void @@ -105,6 +124,16 @@ cxx_print_type (FILE *file, tree node, int indent) indent + 4); return; + case TYPEOF_TYPE: + print_node (file, "expr", TYPEOF_TYPE_EXPR (node), indent + 4); + return; + + case BASES: + if (BASES_DIRECT (node)) + fputs (" direct", file); + print_node (file, "type", BASES_TYPE (node), indent + 4); + return; + case TYPE_PACK_EXPANSION: print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + 4); return; @@ -218,8 +247,8 @@ cxx_print_xnode (FILE *file, tree node, int indent) print_node (file, "optype", BASELINK_OPTYPE (node), indent + 4); break; case OVERLOAD: - print_node (file, "function", OVL_FUNCTION (node), indent+4); - print_node (file, "next", OVL_CHAIN (node), indent+4); + print_node (file, "function", OVL_FUNCTION (node), indent + 4); + print_node (file, "next", OVL_CHAIN (node), indent + 4); break; case TEMPLATE_PARM_INDEX: print_node (file, "decl", TEMPLATE_PARM_DECL (node), indent+4); @@ -292,3 +321,23 @@ debug_tree (cp_expr node) { debug_tree (node.get_value()); } + +DEBUG_FUNCTION void +debug_overload (tree node) +{ + FILE *file = stdout; + + for (lkp_iterator iter (node); iter; ++iter) + { + tree decl = *iter; + auto xloc = expand_location (DECL_SOURCE_LOCATION (decl)); + auto fullname = decl_as_string (decl, 0); + bool using_p = iter.using_p (); + bool hidden_p = iter.hidden_p (); + + fprintf (file, "%p:%c%c %s:%d:%d \"%s\"\n", (void *)decl, + hidden_p ? 'H' : '-', + using_p ? 'U' : '-', + xloc.file, xloc.line, xloc.column, fullname); + } +} diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index f20941c..7c4bff7 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -62,7 +62,7 @@ along with GCC; see the file COPYING3. If not see /* Auxiliary data we hold for each type_info derived object we need. */ struct GTY (()) tinfo_s { - tree type; /* The RECORD_TYPE for this type_info object */ + tree type; /* The (const-qualified) RECORD_TYPE for this type_info object */ tree vtable; /* The VAR_DECL of the vtable. Only filled at end of translation. */ @@ -169,8 +169,7 @@ init_rtti_processing (void) tree type_info_type; push_nested_namespace (std_node); - type_info_type = xref_tag (class_type, get_identifier ("type_info"), - /*tag_scope=*/ts_current, false); + type_info_type = xref_tag (class_type, get_identifier ("type_info")); pop_nested_namespace (std_node); const_type_info_type_node = cp_build_qualified_type (type_info_type, TYPE_QUAL_CONST); @@ -458,6 +457,7 @@ get_tinfo_decl (tree type) DECL_IGNORED_P (d) = 1; TREE_READONLY (d) = 1; TREE_STATIC (d) = 1; + /* Mark the variable as undefined -- but remember that we can define it later if we need to do so. */ DECL_EXTERNAL (d) = 1; @@ -760,9 +760,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr, push_abi_namespace (); tinfo_ptr = xref_tag (class_type, - get_identifier ("__class_type_info"), - /*tag_scope=*/ts_current, false); - + get_identifier ("__class_type_info")); tinfo_ptr = build_pointer_type (cp_build_qualified_type (tinfo_ptr, TYPE_QUAL_CONST)); @@ -947,10 +945,8 @@ tinfo_base_init (tinfo_s *ti, tree target) vtable_ptr = ti->vtable; if (!vtable_ptr) { - tree real_type; push_abi_namespace (); - real_type = xref_tag (class_type, ti->name, - /*tag_scope=*/ts_current, false); + tree real_type = xref_tag (class_type, ti->name); pop_abi_namespace (); if (!COMPLETE_TYPE_P (real_type)) @@ -1176,7 +1172,7 @@ get_pseudo_ti_init (tree type, unsigned tk_index) gcc_assert (tk_index - TK_VMI_CLASS_TYPES + 1 == nbases); - vec_safe_grow (init_vec, nbases); + vec_safe_grow (init_vec, nbases, true); /* Generate the base information initializer. */ for (unsigned ix = nbases; ix--;) { @@ -1563,7 +1559,7 @@ emit_support_tinfos (void) /* Look for a defined class. */ tree bltn_type = lookup_qualified_name - (abi_node, "__fundamental_type_info", true, false); + (abi_node, "__fundamental_type_info", LOOK_want::TYPE, false); if (TREE_CODE (bltn_type) != TYPE_DECL) return; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4a3ef3d..1e42cd7 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2518,7 +2518,7 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, { tree ifn = get_first_fn (fn); if (TREE_CODE (ifn) == FUNCTION_DECL - && DECL_LOCAL_FUNCTION_P (ifn)) + && DECL_LOCAL_DECL_P (ifn)) orig_fn = DECL_NAME (ifn); } @@ -2707,12 +2707,16 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, { if (!vec_safe_is_empty (*args)) error ("arguments to destructor are not allowed"); - /* Mark the pseudo-destructor call as having side-effects so - that we do not issue warnings about its use. */ - result = build1 (NOP_EXPR, - void_type_node, - TREE_OPERAND (fn, 0)); - TREE_SIDE_EFFECTS (result) = 1; + /* C++20/DR: If the postfix-expression names a pseudo-destructor (in + which case the postfix-expression is a possibly-parenthesized class + member access), the function call destroys the object of scalar type + denoted by the object expression of the class member access. */ + tree ob = TREE_OPERAND (fn, 0); + if (obvalue_p (ob)) + result = build_trivial_dtor_call (ob, true); + else + /* No location to clobber. */ + result = convert_to_void (ob, ICV_STATEMENT, complain); } else if (CLASS_TYPE_P (TREE_TYPE (fn))) /* If the "function" is really an object of class type, it might @@ -2845,7 +2849,10 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor, } } - return build3_loc (loc, PSEUDO_DTOR_EXPR, void_type_node, object, + tree type = (type_dependent_expression_p (object) + ? NULL_TREE : void_type_node); + + return build3_loc (loc, PSEUDO_DTOR_EXPR, type, object, scope, destructor); } @@ -3023,6 +3030,7 @@ finish_compound_literal (tree type, tree compound_literal, && initializer_constant_valid_p (compound_literal, type)) { tree decl = create_temporary_var (type); + DECL_CONTEXT (decl) = NULL_TREE; DECL_INITIAL (decl) = compound_literal; TREE_STATIC (decl) = 1; if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type)) @@ -3209,13 +3217,13 @@ begin_class_definition (tree t) if (t == error_mark_node || ! MAYBE_CLASS_TYPE_P (t)) { t = make_class_type (RECORD_TYPE); - pushtag (make_anon_name (), t, /*tag_scope=*/ts_current); + pushtag (make_anon_name (), t); } if (TYPE_BEING_DEFINED (t)) { t = make_class_type (TREE_CODE (t)); - pushtag (TYPE_IDENTIFIER (t), t, /*tag_scope=*/ts_current); + pushtag (TYPE_IDENTIFIER (t), t); } maybe_process_partial_specialization (t); pushclass (t); @@ -5076,8 +5084,13 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, { if (length == NULL_TREE) { - error_at (OMP_CLAUSE_LOCATION (c), - "for pointer type length expression must be specified"); + if (TREE_CODE (ret) == PARM_DECL && DECL_ARRAY_PARAMETER_P (ret)) + error_at (OMP_CLAUSE_LOCATION (c), + "for array function parameter length expression " + "must be specified"); + else + error_at (OMP_CLAUSE_LOCATION (c), + "for pointer type length expression must be specified"); return error_mark_node; } if (length != NULL_TREE @@ -5515,7 +5528,7 @@ omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp, omp_reduction_id (ERROR_MARK, TREE_OPERAND (id, 1), type), - false, false); + LOOK_want::NORMAL, false); tree fns = id; id = NULL_TREE; if (fns && is_overloaded_fn (fns)) @@ -5667,7 +5680,7 @@ cp_check_omp_declare_reduction_r (tree *tp, int *, void *data) /* Diagnose violation of OpenMP #pragma omp declare reduction restrictions. */ -void +bool cp_check_omp_declare_reduction (tree udr) { tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (udr))); @@ -5677,7 +5690,7 @@ cp_check_omp_declare_reduction (tree udr) location_t loc = DECL_SOURCE_LOCATION (udr); if (type == error_mark_node) - return; + return false; if (ARITHMETIC_TYPE_P (type)) { static enum tree_code predef_codes[] @@ -5711,7 +5724,7 @@ cp_check_omp_declare_reduction (tree udr) { error_at (loc, "predeclared arithmetic type %qT in " "%<#pragma omp declare reduction%>", type); - return; + return false; } } else if (FUNC_OR_METHOD_TYPE_P (type) @@ -5719,24 +5732,24 @@ cp_check_omp_declare_reduction (tree udr) { error_at (loc, "function or array type %qT in " "%<#pragma omp declare reduction%>", type); - return; + return false; } else if (TYPE_REF_P (type)) { error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>", type); - return; + return false; } else if (TYPE_QUALS_NO_ADDR_SPACE (type)) { error_at (loc, "%<const%>, %<volatile%> or %<__restrict%>-qualified " "type %qT in %<#pragma omp declare reduction%>", type); - return; + return false; } tree body = DECL_SAVED_TREE (udr); if (body == NULL_TREE || TREE_CODE (body) != STATEMENT_LIST) - return; + return true; tree_stmt_iterator tsi; struct cp_check_omp_declare_reduction_data data; @@ -5752,7 +5765,7 @@ cp_check_omp_declare_reduction (tree udr) gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR && TREE_CODE (data.stmts[1]) == DECL_EXPR); if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0]))) - return; + return true; data.combiner_p = true; if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r, &data, NULL)) @@ -5771,6 +5784,7 @@ cp_check_omp_declare_reduction (tree udr) if (i == 7) gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR); } + return true; } /* Helper function of finish_omp_clauses. Clone STMT as if we were making @@ -8758,7 +8772,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, { tree ivc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); OMP_CLAUSE_DECL (ivc) = iter; - cxx_omp_finish_clause (ivc, NULL); + cxx_omp_finish_clause (ivc, NULL, false); OMP_CLAUSE_CHAIN (ivc) = clauses; clauses = ivc; } @@ -8790,7 +8804,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, OMP_CLAUSE_CODE (loop_iv_seen) = OMP_CLAUSE_FIRSTPRIVATE; } if (OMP_CLAUSE_CODE (loop_iv_seen) == OMP_CLAUSE_FIRSTPRIVATE) - cxx_omp_finish_clause (loop_iv_seen, NULL); + cxx_omp_finish_clause (loop_iv_seen, NULL, false); } orig_pre_body = *pre_body; @@ -10315,8 +10329,8 @@ static tree capture_decltype (tree decl) { tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); - tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0, /*nonclass*/1, - /*block_p=*/true, /*ns*/0, LOOKUP_HIDDEN); + tree cap = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK, + LOOK_want::HIDDEN_LAMBDA); tree type; if (cap && is_capture_proxy (cap)) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 1fcba55..9bc37ac 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -73,7 +73,12 @@ lvalue_kind (const_tree ref) && TREE_CODE (ref) != COMPONENT_REF /* Functions are always lvalues. */ && TREE_CODE (TREE_TYPE (TREE_TYPE (ref))) != FUNCTION_TYPE) - return clk_rvalueref; + { + op1_lvalue_kind = clk_rvalueref; + if (implicit_rvalue_p (ref)) + op1_lvalue_kind |= clk_implicit_rval; + return op1_lvalue_kind; + } /* lvalue references and named rvalue references are lvalues. */ return clk_ordinary; @@ -2232,13 +2237,13 @@ ovl_make (tree fn, tree next) return result; } -/* Add FN to the (potentially NULL) overload set OVL. USING_P is - true, if FN is via a using declaration. We also pay attention to - DECL_HIDDEN. We keep the hidden decls first, but remaining ones - are unordered. */ +/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN + is > 0, if FN is via a using declaration. USING_OR_HIDDEN is < 0, + if FN is hidden. (A decl cannot be both using and hidden.) We + keep the hidden decls first, but remaining ones are unordered. */ tree -ovl_insert (tree fn, tree maybe_ovl, bool using_p) +ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden) { tree result = maybe_ovl; tree insert_after = NULL_TREE; @@ -2252,13 +2257,13 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) insert_after = maybe_ovl; } - bool hidden_p = DECL_HIDDEN_P (fn); - if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL) + if (maybe_ovl || using_or_hidden || TREE_CODE (fn) == TEMPLATE_DECL) { maybe_ovl = ovl_make (fn, maybe_ovl); - if (hidden_p) + + if (using_or_hidden < 0) OVL_HIDDEN_P (maybe_ovl) = true; - if (using_p) + if (using_or_hidden > 0) OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true; } else @@ -2280,23 +2285,13 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p) tree ovl_skip_hidden (tree ovl) { - for (; - ovl && TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl); - ovl = OVL_CHAIN (ovl)) - gcc_checking_assert (DECL_HIDDEN_P (OVL_FUNCTION (ovl))); - - if (ovl && TREE_CODE (ovl) != OVERLOAD && DECL_HIDDEN_P (ovl)) - { - /* Any hidden functions should have been wrapped in an - overload, but injected friend classes will not. */ - gcc_checking_assert (!DECL_DECLARES_FUNCTION_P (ovl)); - ovl = NULL_TREE; - } + while (ovl && TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl)) + ovl = OVL_CHAIN (ovl); return ovl; } -/* NODE is an OVL_HIDDEN_P node which is now revealed. */ +/* NODE is an OVL_HIDDEN_P node that is now revealed. */ tree ovl_iterator::reveal_node (tree overload, tree node) @@ -2643,6 +2638,9 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, /* Need to build a new variant. */ v = build_variant_type_copy (type); + if (!TYPE_DEPENDENT_P (v)) + /* We no longer know that it's not type-dependent. */ + TYPE_DEPENDENT_P_VALID (v) = false; TYPE_RAISES_EXCEPTIONS (v) = raises; TYPE_HAS_LATE_RETURN_TYPE (v) = late; switch (rqual) @@ -3805,6 +3803,8 @@ cp_tree_equal (tree t1, tree t2) if (SIZEOF_EXPR_TYPE_P (t2)) o2 = TREE_TYPE (o2); } + else if (ALIGNOF_EXPR_STD_P (t1) != ALIGNOF_EXPR_STD_P (t2)) + return false; if (TREE_CODE (o1) != TREE_CODE (o2)) return false; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 7e84f11..95b36a9 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1384,6 +1384,7 @@ structural_comptypes (tree t1, tree t2, int strict) case METHOD_TYPE: case FUNCTION_TYPE: + /* Exception specs and memfn_rquals were checked above. */ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) return false; if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))) @@ -1451,19 +1452,25 @@ structural_comptypes (tree t1, tree t2, int strict) case DECLTYPE_TYPE: if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) - != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2) - || (DECLTYPE_FOR_LAMBDA_CAPTURE (t1) - != DECLTYPE_FOR_LAMBDA_CAPTURE (t2)) - || (DECLTYPE_FOR_LAMBDA_PROXY (t1) - != DECLTYPE_FOR_LAMBDA_PROXY (t2)) - || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), - DECLTYPE_TYPE_EXPR (t2))) + != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)) + return false; + if (DECLTYPE_FOR_LAMBDA_CAPTURE (t1) != DECLTYPE_FOR_LAMBDA_CAPTURE (t2)) + return false; + if (DECLTYPE_FOR_LAMBDA_PROXY (t1) != DECLTYPE_FOR_LAMBDA_PROXY (t2)) + return false; + if (!cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), DECLTYPE_TYPE_EXPR (t2))) return false; break; case UNDERLYING_TYPE: - return same_type_p (UNDERLYING_TYPE_TYPE (t1), - UNDERLYING_TYPE_TYPE (t2)); + if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2))) + return false; + break; + + case TYPEOF_TYPE: + if (!cp_tree_equal (TYPEOF_TYPE_EXPR (t1), TYPEOF_TYPE_EXPR (t2))) + return false; + break; default: return false; @@ -7473,6 +7480,20 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p, t. */ result = perform_direct_initialization_if_possible (type, expr, c_cast_p, complain); + /* P1975 allows static_cast<Aggr>(42), as well as static_cast<T[5]>(42), + which initialize the first element of the aggregate. We need to handle + the array case specifically. */ + if (result == NULL_TREE + && cxx_dialect >= cxx20 + && TREE_CODE (type) == ARRAY_TYPE) + { + /* Create { EXPR } and perform direct-initialization from it. */ + tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr); + CONSTRUCTOR_IS_DIRECT_INIT (e) = true; + CONSTRUCTOR_IS_PAREN_INIT (e) = true; + result = perform_direct_initialization_if_possible (type, e, c_cast_p, + complain); + } if (result) { if (processing_template_decl) @@ -9712,19 +9733,62 @@ can_do_nrvo_p (tree retval, tree functype) && !TYPE_VOLATILE (TREE_TYPE (retval))); } -/* Returns true if we should treat RETVAL, an expression being returned, - as if it were designated by an rvalue. See [class.copy.elision]. - PARM_P is true if a function parameter is OK in this context. */ +/* If we should treat RETVAL, an expression being returned, as if it were + designated by an rvalue, returns it adjusted accordingly; otherwise, returns + NULL_TREE. See [class.copy.elision]. RETURN_P is true if this is a return + context (rather than throw). */ -bool -treat_lvalue_as_rvalue_p (tree retval, bool parm_ok) +tree +treat_lvalue_as_rvalue_p (tree expr, bool return_p) { + if (cxx_dialect == cxx98) + return NULL_TREE; + + tree retval = expr; STRIP_ANY_LOCATION_WRAPPER (retval); - return ((cxx_dialect != cxx98) - && ((VAR_P (retval) && !DECL_HAS_VALUE_EXPR_P (retval)) - || (parm_ok && TREE_CODE (retval) == PARM_DECL)) - && DECL_CONTEXT (retval) == current_function_decl - && !TREE_STATIC (retval)); + if (REFERENCE_REF_P (retval)) + retval = TREE_OPERAND (retval, 0); + + /* An implicitly movable entity is a variable of automatic storage duration + that is either a non-volatile object or (C++20) an rvalue reference to a + non-volatile object type. */ + if (!(((VAR_P (retval) && !DECL_HAS_VALUE_EXPR_P (retval)) + || TREE_CODE (retval) == PARM_DECL) + && !TREE_STATIC (retval) + && !CP_TYPE_VOLATILE_P (non_reference (TREE_TYPE (retval))) + && (TREE_CODE (TREE_TYPE (retval)) != REFERENCE_TYPE + || (cxx_dialect >= cxx20 + && TYPE_REF_IS_RVALUE (TREE_TYPE (retval)))))) + return NULL_TREE; + + /* If the expression in a return or co_return statement is a (possibly + parenthesized) id-expression that names an implicitly movable entity + declared in the body or parameter-declaration-clause of the innermost + enclosing function or lambda-expression, */ + if (DECL_CONTEXT (retval) != current_function_decl) + return NULL_TREE; + if (return_p) + return set_implicit_rvalue_p (move (expr)); + + /* if the operand of a throw-expression is a (possibly parenthesized) + id-expression that names an implicitly movable entity whose scope does not + extend beyond the compound-statement of the innermost try-block or + function-try-block (if any) whose compound-statement or ctor-initializer + encloses the throw-expression, */ + + /* C++20 added move on throw of parms. */ + if (TREE_CODE (retval) == PARM_DECL && cxx_dialect < cxx20) + return NULL_TREE; + + for (cp_binding_level *b = current_binding_level; + ; b = b->level_chain) + { + for (tree decl = b->names; decl; decl = TREE_CHAIN (decl)) + if (decl == retval) + return set_implicit_rvalue_p (move (expr)); + if (b->kind == sk_function_parms || b->kind == sk_try) + return NULL_TREE; + } } /* Warn about wrong usage of std::move in a return statement. RETVAL @@ -9760,6 +9824,7 @@ maybe_warn_pessimizing_move (tree retval, tree functype) if (is_std_move_p (fn)) { tree arg = CALL_EXPR_ARG (fn, 0); + tree moved; if (TREE_CODE (arg) != NOP_EXPR) return; arg = TREE_OPERAND (arg, 0); @@ -9779,12 +9844,12 @@ maybe_warn_pessimizing_move (tree retval, tree functype) /* Warn if the move is redundant. It is redundant when we would do maybe-rvalue overload resolution even without std::move. */ else if (warn_redundant_move - && treat_lvalue_as_rvalue_p (arg, /*parm_ok*/true)) + && (moved = treat_lvalue_as_rvalue_p (arg, /*return*/true))) { /* Make sure that the overload resolution would actually succeed if we removed the std::move call. */ tree t = convert_for_initialization (NULL_TREE, functype, - move (arg), + moved, (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING | LOOKUP_PREFER_RVALUE), @@ -10082,24 +10147,31 @@ check_return_expr (tree retval, bool *no_warning) Note that these conditions are similar to, but not as strict as, the conditions for the named return value optimization. */ bool converted = false; - if (treat_lvalue_as_rvalue_p (retval, /*parm_ok*/true) - /* This is only interesting for class type. */ - && CLASS_TYPE_P (functype)) - { - tree moved = move (retval); - moved = convert_for_initialization - (NULL_TREE, functype, moved, flags|LOOKUP_PREFER_RVALUE, - ICR_RETURN, NULL_TREE, 0, tf_none); - if (moved != error_mark_node) + tree moved; + /* This is only interesting for class type. */ + if (CLASS_TYPE_P (functype) + && (moved = treat_lvalue_as_rvalue_p (retval, /*return*/true))) + { + if (cxx_dialect < cxx20) { - retval = moved; - converted = true; + moved = convert_for_initialization + (NULL_TREE, functype, moved, flags|LOOKUP_PREFER_RVALUE, + ICR_RETURN, NULL_TREE, 0, tf_none); + if (moved != error_mark_node) + { + retval = moved; + converted = true; + } } + else + /* In C++20 we just treat the return value as an rvalue that + can bind to lvalue refs. */ + retval = moved; } /* The call in a (lambda) thunk needs no conversions. */ if (TREE_CODE (retval) == CALL_EXPR - && CALL_FROM_THUNK_P (retval)) + && call_from_lambda_thunk_p (retval)) converted = true; /* First convert the value to the function's return type, then diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index dac135a..e259a42 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -711,7 +711,17 @@ split_nonconstant_init_1 (tree dest, tree init, bool nested) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); - code = build2 (INIT_EXPR, inner_type, sub, value); + if (unsafe_return_slot_p (sub)) + { + /* We may need to add a copy constructor call if + the field has [[no_unique_address]]. */ + releasing_vec args = make_tree_vector_single (value); + code = build_special_member_call + (sub, complete_ctor_identifier, &args, inner_type, + LOOKUP_NORMAL, tf_warning_or_error); + } + else + code = build2 (INIT_EXPR, inner_type, sub, value); code = build_stmt (input_location, EXPR_STMT, code); code = maybe_cleanup_point_expr_void (code); add_stmt (code); @@ -910,7 +920,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) /* [dcl.constinit]/2 "If a variable declared with the constinit specifier has dynamic initialization, the program is ill-formed." */ - if (flags & LOOKUP_CONSTINIT) + if (DECL_DECLARED_CONSTINIT_P (decl)) { error_at (location_of (decl), "%<constinit%> variable %qD does not have a constant " |